From 7ea4fbecb6567d91e4734c892fb7d42cbaa5cfd5 Mon Sep 17 00:00:00 2001 From: "yongle.wu" Date: Wed, 17 May 2023 08:20:37 +0000 Subject: [PATCH 1/6] Signed-off-by: yongle.wu add CWD for pytorch model link #I6VR33 add CWD for pytorch model --- cv/distiller/CWD/README.md | 73 + cv/distiller/CWD/mmcv/.circleci/config.yml | 32 + .../CWD/mmcv/.circleci/docker/Dockerfile | 15 + cv/distiller/CWD/mmcv/.circleci/test.yml | 270 +++ .../mmcv/.dev_scripts/check_installation.py | 44 + cv/distiller/CWD/mmcv/.dockerignore | 6 + cv/distiller/CWD/mmcv/.owners.yml | 14 + .../CWD/mmcv/.pre-commit-config-zh-cn.yaml | 72 + cv/distiller/CWD/mmcv/.pre-commit-config.yaml | 72 + cv/distiller/CWD/mmcv/.readthedocs.yml | 9 + cv/distiller/CWD/mmcv/CITATION.cff | 8 + cv/distiller/CWD/mmcv/CONTRIBUTING.md | 258 +++ cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md | 274 +++ cv/distiller/CWD/mmcv/Jenkinsfile | 56 + cv/distiller/CWD/mmcv/LICENSE | 203 ++ cv/distiller/CWD/mmcv/LICENSES.md | 8 + cv/distiller/CWD/mmcv/MANIFEST.in | 6 + cv/distiller/CWD/mmcv/README.md | 161 ++ cv/distiller/CWD/mmcv/README_zh-CN.md | 164 ++ cv/distiller/CWD/mmcv/TERMINOLOGY.md | 30 + cv/distiller/CWD/mmcv/build_mmcv.sh | 26 + cv/distiller/CWD/mmcv/clean_mmcv.sh | 14 + cv/distiller/CWD/mmcv/compile.log | 229 ++ cv/distiller/CWD/mmcv/docker/README.md | 70 + cv/distiller/CWD/mmcv/docker/dev/Dockerfile | 31 + .../CWD/mmcv/docker/release/Dockerfile | 23 + cv/distiller/CWD/mmcv/docs/en/Makefile | 19 + .../CWD/mmcv/docs/en/_static/community/1.png | Bin 0 -> 84328 bytes .../CWD/mmcv/docs/en/_static/community/2.png | Bin 0 -> 66595 bytes .../CWD/mmcv/docs/en/_static/community/3.png | Bin 0 -> 182941 bytes .../mmcv/docs/en/_static/css/readthedocs.css | 10 + .../mmcv/docs/en/_static/flow_img2toimg1.png | Bin 0 -> 94702 bytes .../mmcv/docs/en/_static/flow_raw_images.png | Bin 0 -> 1515531 bytes .../docs/en/_static/flow_visualization.png | Bin 0 -> 23832 bytes .../CWD/mmcv/docs/en/_static/flow_warp.png | Bin 0 -> 760348 bytes .../mmcv/docs/en/_static/flow_warp_diff.png | Bin 0 -> 1379939 bytes .../mmcv/docs/en/_static/image/mmcv-logo.png | Bin 0 -> 27173 bytes .../docs/en/_static/parallel_progress.gif | Bin 0 -> 27666 bytes .../docs/en/_static/parallel_progress.png | Bin 0 -> 9729 bytes .../CWD/mmcv/docs/en/_static/progress.gif | Bin 0 -> 100747 bytes .../CWD/mmcv/docs/en/_static/progress.png | Bin 0 -> 20918 bytes .../CWD/mmcv/docs/en/_static/version.json | 575 +++++ .../mmcv/docs/en/_templates/classtemplate.rst | 14 + .../CWD/mmcv/docs/en/api/arraymisc.rst | 19 + cv/distiller/CWD/mmcv/docs/en/api/cnn.rst | 70 + cv/distiller/CWD/mmcv/docs/en/api/image.rst | 100 + cv/distiller/CWD/mmcv/docs/en/api/ops.rst | 135 ++ .../CWD/mmcv/docs/en/api/transforms.rst | 57 + cv/distiller/CWD/mmcv/docs/en/api/utils.rst | 23 + cv/distiller/CWD/mmcv/docs/en/api/video.rst | 56 + .../CWD/mmcv/docs/en/api/visualization.rst | 50 + .../mmcv/docs/en/community/contributing.md | 267 +++ cv/distiller/CWD/mmcv/docs/en/community/pr.md | 3 + .../CWD/mmcv/docs/en/compatibility.md | 176 ++ cv/distiller/CWD/mmcv/docs/en/conf.py | 215 ++ .../docs/en/deployment/mmcv_ops_definition.md | 686 ++++++ cv/distiller/CWD/mmcv/docs/en/docutils.conf | 2 + cv/distiller/CWD/mmcv/docs/en/faq.md | 93 + .../CWD/mmcv/docs/en/get_started/build.md | 292 +++ .../mmcv/docs/en/get_started/installation.md | 348 +++ .../mmcv/docs/en/get_started/introduction.md | 36 + .../docs/en/get_started/previous_versions.md | 47 + cv/distiller/CWD/mmcv/docs/en/index.rst | 69 + cv/distiller/CWD/mmcv/docs/en/make.bat | 35 + cv/distiller/CWD/mmcv/docs/en/mmcv-logo.png | Bin 0 -> 27173 bytes .../CWD/mmcv/docs/en/switch_language.md | 3 + .../CWD/mmcv/docs/en/understand_mmcv/cnn.md | 120 ++ .../docs/en/understand_mmcv/data_process.md | 286 +++ .../docs/en/understand_mmcv/data_transform.md | 341 +++ .../CWD/mmcv/docs/en/understand_mmcv/ops.md | 63 + .../docs/en/understand_mmcv/visualization.md | 24 + cv/distiller/CWD/mmcv/docs/zh_cn/Makefile | 19 + .../docs/zh_cn/_static/css/readthedocs.css | 10 + .../docs/zh_cn/_static/image/mmcv-logo.png | Bin 0 -> 27173 bytes .../CWD/mmcv/docs/zh_cn/_static/version.json | 575 +++++ .../docs/zh_cn/_templates/classtemplate.rst | 14 + .../CWD/mmcv/docs/zh_cn/api/arraymisc.rst | 19 + cv/distiller/CWD/mmcv/docs/zh_cn/api/cnn.rst | 70 + .../CWD/mmcv/docs/zh_cn/api/image.rst | 100 + cv/distiller/CWD/mmcv/docs/zh_cn/api/ops.rst | 135 ++ .../CWD/mmcv/docs/zh_cn/api/transforms.rst | 57 + .../CWD/mmcv/docs/zh_cn/api/utils.rst | 23 + .../CWD/mmcv/docs/zh_cn/api/video.rst | 56 + .../CWD/mmcv/docs/zh_cn/api/visualization.rst | 50 + .../mmcv/docs/zh_cn/community/code_style.md | 609 ++++++ .../mmcv/docs/zh_cn/community/contributing.md | 278 +++ .../CWD/mmcv/docs/zh_cn/community/pr.md | 3 + .../CWD/mmcv/docs/zh_cn/compatibility.md | 176 ++ cv/distiller/CWD/mmcv/docs/zh_cn/conf.py | 217 ++ .../CWD/mmcv/docs/zh_cn/docutils.conf | 2 + cv/distiller/CWD/mmcv/docs/zh_cn/faq.md | 91 + .../mmcv/docs/zh_cn/get_started/article.md | 63 + .../CWD/mmcv/docs/zh_cn/get_started/build.md | 300 +++ .../docs/zh_cn/get_started/installation.md | 369 ++++ .../docs/zh_cn/get_started/introduction.md | 36 + .../zh_cn/get_started/previous_versions.md | 47 + cv/distiller/CWD/mmcv/docs/zh_cn/index.rst | 66 + cv/distiller/CWD/mmcv/docs/zh_cn/make.bat | 35 + .../CWD/mmcv/docs/zh_cn/mmcv-logo.png | 1 + .../CWD/mmcv/docs/zh_cn/switch_language.md | 3 + .../mmcv/docs/zh_cn/understand_mmcv/cnn.md | 114 + .../zh_cn/understand_mmcv/data_process.md | 275 +++ .../zh_cn/understand_mmcv/data_transform.md | 341 +++ .../mmcv/docs/zh_cn/understand_mmcv/ops.md | 63 + .../zh_cn/understand_mmcv/visualization.md | 24 + cv/distiller/CWD/mmcv/install_mmcv.sh | 36 + cv/distiller/CWD/mmcv/mmcv/__init__.py | 13 + .../CWD/mmcv/mmcv/arraymisc/__init__.py | 4 + .../CWD/mmcv/mmcv/arraymisc/quantization.py | 65 + cv/distiller/CWD/mmcv/mmcv/cnn/__init__.py | 27 + cv/distiller/CWD/mmcv/mmcv/cnn/alexnet.py | 63 + .../CWD/mmcv/mmcv/cnn/bricks/__init__.py | 32 + .../CWD/mmcv/mmcv/cnn/bricks/activation.py | 114 + .../CWD/mmcv/mmcv/cnn/bricks/context_block.py | 126 ++ cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv.py | 49 + .../cnn/bricks/conv2d_adaptive_padding.py | 63 + .../CWD/mmcv/mmcv/cnn/bricks/conv_module.py | 212 ++ .../CWD/mmcv/mmcv/cnn/bricks/conv_ws.py | 153 ++ .../bricks/depthwise_separable_conv_module.py | 99 + cv/distiller/CWD/mmcv/mmcv/cnn/bricks/drop.py | 67 + .../mmcv/cnn/bricks/generalized_attention.py | 411 ++++ .../CWD/mmcv/mmcv/cnn/bricks/hsigmoid.py | 50 + .../CWD/mmcv/mmcv/cnn/bricks/hswish.py | 39 + .../CWD/mmcv/mmcv/cnn/bricks/non_local.py | 308 +++ cv/distiller/CWD/mmcv/mmcv/cnn/bricks/norm.py | 153 ++ .../CWD/mmcv/mmcv/cnn/bricks/padding.py | 41 + .../CWD/mmcv/mmcv/cnn/bricks/plugin.py | 98 + .../CWD/mmcv/mmcv/cnn/bricks/scale.py | 57 + .../CWD/mmcv/mmcv/cnn/bricks/swish.py | 24 + .../CWD/mmcv/mmcv/cnn/bricks/transformer.py | 951 +++++++++ .../CWD/mmcv/mmcv/cnn/bricks/upsample.py | 90 + .../CWD/mmcv/mmcv/cnn/bricks/wrappers.py | 177 ++ cv/distiller/CWD/mmcv/mmcv/cnn/resnet.py | 321 +++ .../CWD/mmcv/mmcv/cnn/utils/__init__.py | 5 + .../CWD/mmcv/mmcv/cnn/utils/flops_counter.py | 604 ++++++ .../CWD/mmcv/mmcv/cnn/utils/fuse_conv_bn.py | 59 + cv/distiller/CWD/mmcv/mmcv/cnn/vgg.py | 176 ++ cv/distiller/CWD/mmcv/mmcv/image/__init__.py | 29 + .../CWD/mmcv/mmcv/image/colorspace.py | 309 +++ cv/distiller/CWD/mmcv/mmcv/image/geometric.py | 786 +++++++ cv/distiller/CWD/mmcv/mmcv/image/io.py | 364 ++++ cv/distiller/CWD/mmcv/mmcv/image/misc.py | 58 + .../CWD/mmcv/mmcv/image/photometric.py | 561 +++++ cv/distiller/CWD/mmcv/mmcv/ops/__init__.py | 104 + .../mmcv/mmcv/ops/active_rotated_filter.py | 64 + .../CWD/mmcv/mmcv/ops/assign_score_withk.py | 131 ++ cv/distiller/CWD/mmcv/mmcv/ops/ball_query.py | 87 + cv/distiller/CWD/mmcv/mmcv/ops/bbox.py | 130 ++ .../CWD/mmcv/mmcv/ops/bezier_align.py | 137 ++ .../CWD/mmcv/mmcv/ops/border_align.py | 114 + .../CWD/mmcv/mmcv/ops/box_iou_quadri.py | 49 + .../CWD/mmcv/mmcv/ops/box_iou_rotated.py | 148 ++ cv/distiller/CWD/mmcv/mmcv/ops/carafe.py | 300 +++ .../CWD/mmcv/mmcv/ops/cc_attention.py | 85 + .../CWD/mmcv/mmcv/ops/chamfer_distance.py | 93 + .../CWD/mmcv/mmcv/ops/contour_expand.py | 52 + cv/distiller/CWD/mmcv/mmcv/ops/convex_iou.py | 52 + cv/distiller/CWD/mmcv/mmcv/ops/corner_pool.py | 83 + cv/distiller/CWD/mmcv/mmcv/ops/correlation.py | 200 ++ cv/distiller/CWD/mmcv/mmcv/ops/csrc/README.md | 162 ++ .../ops/csrc/common/box_iou_rotated_utils.hpp | 426 ++++ .../active_rotated_filter_cuda_kernel.cuh | 59 + .../cuda/assign_score_withk_cuda_kernel.cuh | 116 + .../common/cuda/ball_query_cuda_kernel.cuh | 58 + .../common/cuda/bbox_overlaps_cuda_kernel.cuh | 147 ++ .../common/cuda/bezier_align_cuda_kernel.cuh | 230 ++ .../common/cuda/border_align_cuda_kernel.cuh | 200 ++ .../csrc/common/cuda/box_iou_quadri_cuda.cuh | 91 + .../csrc/common/cuda/box_iou_rotated_cuda.cuh | 81 + .../csrc/common/cuda/carafe_cuda_kernel.cuh | 333 +++ .../common/cuda/carafe_naive_cuda_kernel.cuh | 111 + .../cuda/chamfer_distance_cuda_kernel.cuh | 101 + .../csrc/common/cuda/common_cuda_helper.hpp | 120 ++ .../common/cuda/convex_iou_cuda_kernel.cuh | 831 ++++++++ .../ops/csrc/common/cuda/correlation_cuda.cuh | 231 ++ .../common/cuda/deform_conv_cuda_kernel.cuh | 367 ++++ .../cuda/deform_roi_pool_cuda_kernel.cuh | 186 ++ .../cuda/diff_iou_rotated_cuda_kernel.cuh | 137 ++ .../furthest_point_sample_cuda_kernel.cuh | 152 ++ .../common/cuda/gather_points_cuda_kernel.cuh | 58 + .../common/cuda/group_points_cuda_kernel.cuh | 65 + .../csrc/common/cuda/iou3d_cuda_kernel.cuh | 367 ++++ .../ops/csrc/common/cuda/knn_cuda_kernel.cuh | 92 + .../common/cuda/masked_conv2d_cuda_kernel.cuh | 62 + .../common/cuda/min_area_polygons_cuda.cuh | 300 +++ .../modulated_deform_conv_cuda_kernel.cuh | 399 ++++ .../cuda/ms_deform_attn_cuda_kernel.cuh | 801 +++++++ .../ops/csrc/common/cuda/nms_cuda_kernel.cuh | 117 + .../ops/csrc/common/cuda/nms_quadri_cuda.cuh | 141 ++ .../ops/csrc/common/cuda/nms_rotated_cuda.cuh | 133 ++ .../common/cuda/parrots_cudawarpfunction.cuh | 109 + .../cuda/points_in_boxes_cuda_kernel.cuh | 95 + .../cuda/points_in_polygons_cuda_kernel.cuh | 79 + .../common/cuda/prroi_pool_cuda_kernel.cuh | 381 ++++ .../csrc/common/cuda/psamask_cuda_kernel.cuh | 141 ++ .../cuda/riroi_align_rotated_cuda_kernel.cuh | 242 +++ .../common/cuda/roi_align_cuda_kernel.cuh | 212 ++ .../cuda/roi_align_rotated_cuda_kernel.cuh | 202 ++ .../csrc/common/cuda/roi_pool_cuda_kernel.cuh | 93 + .../cuda/roiaware_pool3d_cuda_kernel.cuh | 260 +++ .../cuda/roipoint_pool3d_cuda_kernel.cuh | 134 ++ .../rotated_feature_align_cuda_kernel.cuh | 129 ++ .../cuda/scatter_points_cuda_kernel.cuh | 188 ++ .../cuda/sigmoid_focal_loss_cuda_kernel.cuh | 71 + .../cuda/softmax_focal_loss_cuda_kernel.cuh | 72 + .../cuda/stack_ball_query_cuda_kernel.cuh | 68 + .../cuda/stack_group_points_cuda_kernel.cuh | 97 + .../csrc/common/cuda/sync_bn_cuda_kernel.cuh | 331 +++ .../cuda/three_interpolate_cuda_kernel.cuh | 61 + .../common/cuda/tin_shift_cuda_kernel.cuh | 61 + .../common/cuda/voxelization_cuda_kernel.cuh | 216 ++ .../common/mlu/bbox_overlaps_mlu_kernel.mlu | 322 +++ .../ops/csrc/common/mlu/carafe_mlu_kernel.mlu | 552 +++++ .../mmcv/ops/csrc/common/mlu/carafe_utils.hpp | 95 + .../ops/csrc/common/mlu/common_mlu_helper.hpp | 398 ++++ .../common/mlu/deform_roi_pool_mlu_kernel.mlu | 712 +++++++ .../mlu/focal_loss_sigmoid_mlu_kernel.mlu | 888 ++++++++ .../ops/csrc/common/mlu/iou3d_mlu_kernel.mlu | 431 ++++ .../mmcv/ops/csrc/common/mlu/iou3d_utils.hpp | 695 ++++++ .../common/mlu/masked_conv2d_mlu_kernel.mlu | 181 ++ .../common/mlu/ms_deform_attn_mlu_kernel.mlu | 853 ++++++++ .../ops/csrc/common/mlu/nms_mlu_kernel.mlu | 483 +++++ .../mmcv/ops/csrc/common/mlu/nms_utils.hpp | 553 +++++ .../csrc/common/mlu/psamask_mlu_kernel.mlu | 615 ++++++ .../ops/csrc/common/mlu/psamask_utils.hpp | 55 + .../csrc/common/mlu/roi_align_mlu_kernel.mlu | 493 +++++ .../mlu/roi_align_rotated_mlu_kernel.mlu | 490 +++++ .../common/mlu/roi_align_rotated_utils.hpp | 24 + .../csrc/common/mlu/roi_pool_mlu_kernel.mlu | 747 +++++++ .../common/mlu/roiaware_pool3d_mlu_kernel.mlu | 747 +++++++ ...oint_pool3d_large_boxes_num_mlu_kernel.mlu | 536 +++++ .../common/mlu/roipoint_pool3d_mlu_kernel.mlu | 544 +++++ .../csrc/common/mlu/three_nn_mlu_kernel.mlu | 466 ++++ .../csrc/common/mlu/tin_shift_mlu_kernel.mlu | 307 +++ .../ops/csrc/common/parrots_cpp_helper.hpp | 40 + .../ops/csrc/common/parrots_cuda_helper.hpp | 111 + .../ops/csrc/common/pytorch_cpp_helper.hpp | 27 + .../ops/csrc/common/pytorch_cuda_helper.hpp | 20 + .../csrc/common/pytorch_device_registry.hpp | 141 ++ .../ops/csrc/common/pytorch_mlu_helper.hpp | 61 + .../csrc/pytorch/active_rotated_filter.cpp | 28 + .../ops/csrc/pytorch/assign_score_withk.cpp | 42 + .../mmcv/mmcv/ops/csrc/pytorch/ball_query.cpp | 38 + .../mmcv/ops/csrc/pytorch/bbox_overlaps.cpp | 14 + .../mmcv/ops/csrc/pytorch/bezier_align.cpp | 38 + .../mmcv/ops/csrc/pytorch/border_align.cpp | 30 + .../mmcv/ops/csrc/pytorch/box_iou_quadri.cpp | 17 + .../mmcv/ops/csrc/pytorch/box_iou_rotated.cpp | 19 + .../CWD/mmcv/mmcv/ops/csrc/pytorch/carafe.cpp | 38 + .../mmcv/ops/csrc/pytorch/carafe_naive.cpp | 32 + .../ops/csrc/pytorch/chamfer_distance.cpp | 35 + .../mmcv/ops/csrc/pytorch/contour_expand.cpp | 111 + .../mmcv/mmcv/ops/csrc/pytorch/convex_iou.cpp | 23 + .../mmcv/ops/csrc/pytorch/correlation.cpp | 47 + .../pytorch/cpu/active_rotated_filter.cpp | 120 ++ .../ops/csrc/pytorch/cpu/bezier_align.cpp | 447 ++++ .../ops/csrc/pytorch/cpu/box_iou_quadri.cpp | 36 + .../ops/csrc/pytorch/cpu/box_iou_rotated.cpp | 38 + .../mmcv/ops/csrc/pytorch/cpu/deform_conv.cpp | 408 ++++ .../pytorch/cpu/modulated_deform_conv.cpp | 436 ++++ .../mmcv/mmcv/ops/csrc/pytorch/cpu/nms.cpp | 230 ++ .../mmcv/ops/csrc/pytorch/cpu/nms_quadri.cpp | 64 + .../mmcv/ops/csrc/pytorch/cpu/nms_rotated.cpp | 66 + .../mmcv/ops/csrc/pytorch/cpu/pixel_group.cpp | 126 ++ .../ops/csrc/pytorch/cpu/points_in_boxes.cpp | 53 + .../mmcv/ops/csrc/pytorch/cpu/psamask.cpp | 199 ++ .../mmcv/ops/csrc/pytorch/cpu/roi_align.cpp | 466 ++++ .../csrc/pytorch/cpu/roi_align_rotated.cpp | 455 ++++ .../pytorch/cpu/rotated_feature_align.cpp | 262 +++ .../ops/csrc/pytorch/cpu/voxelization.cpp | 186 ++ .../cuda/active_rotated_filter_cuda.cu | 58 + .../pytorch/cuda/assign_score_withk_cuda.cu | 66 + .../ops/csrc/pytorch/cuda/ball_query_cuda.cu | 38 + .../csrc/pytorch/cuda/bbox_overlaps_cuda.cu | 40 + .../csrc/pytorch/cuda/bezier_align_cuda.cu | 53 + .../csrc/pytorch/cuda/border_align_cuda.cu | 68 + .../csrc/pytorch/cuda/box_iou_quadri_cuda.cu | 23 + .../csrc/pytorch/cuda/box_iou_rotated_cuda.cu | 25 + .../mmcv/ops/csrc/pytorch/cuda/carafe_cuda.cu | 180 ++ .../csrc/pytorch/cuda/carafe_naive_cuda.cu | 52 + .../pytorch/cuda/chamfer_distance_cuda.cu | 63 + .../mmcv/ops/csrc/pytorch/cuda/convex_iou.cu | 41 + .../ops/csrc/pytorch/cuda/correlation_cuda.cu | 94 + .../mmcv/ops/csrc/pytorch/cuda/cudabind.cpp | 1895 +++++++++++++++++ .../ops/csrc/pytorch/cuda/deform_conv_cuda.cu | 105 + .../csrc/pytorch/cuda/deform_roi_pool_cuda.cu | 55 + .../pytorch/cuda/diff_iou_rotated_cuda.cu | 35 + .../ops/csrc/pytorch/cuda/focal_loss_cuda.cu | 111 + .../cuda/furthest_point_sample_cuda.cu | 143 ++ .../pytorch/cuda/fused_bias_leakyrelu_cuda.cu | 109 + .../csrc/pytorch/cuda/gather_points_cuda.cu | 58 + .../csrc/pytorch/cuda/group_points_cuda.cu | 61 + .../mmcv/ops/csrc/pytorch/cuda/iou3d_cuda.cu | 104 + .../mmcv/ops/csrc/pytorch/cuda/knn_cuda.cu | 34 + .../csrc/pytorch/cuda/masked_conv2d_cuda.cu | 54 + .../csrc/pytorch/cuda/min_area_polygons.cu | 21 + .../cuda/modulated_deform_conv_cuda.cu | 96 + .../csrc/pytorch/cuda/ms_deform_attn_cuda.cu | 351 +++ .../mmcv/ops/csrc/pytorch/cuda/nms_cuda.cu | 36 + .../ops/csrc/pytorch/cuda/nms_quadri_cuda.cu | 60 + .../ops/csrc/pytorch/cuda/nms_rotated_cuda.cu | 62 + .../csrc/pytorch/cuda/points_in_boxes_cuda.cu | 62 + .../pytorch/cuda/points_in_polygons_cuda.cu | 28 + .../ops/csrc/pytorch/cuda/prroi_pool_cuda.cu | 65 + .../ops/csrc/pytorch/cuda/psamask_cuda.cu | 60 + .../pytorch/cuda/riroi_align_rotated_cuda.cu | 53 + .../ops/csrc/pytorch/cuda/roi_align_cuda.cu | 58 + .../pytorch/cuda/roi_align_rotated_cuda.cu | 45 + .../ops/csrc/pytorch/cuda/roi_pool_cuda.cu | 50 + .../csrc/pytorch/cuda/roiaware_pool3d_cuda.cu | 118 + .../csrc/pytorch/cuda/roipoint_pool3d_cuda.cu | 60 + .../cuda/rotated_feature_align_cuda.cu | 53 + .../csrc/pytorch/cuda/scatter_points_cuda.cu | 132 ++ .../pytorch/cuda/stack_ball_query_cuda.cu | 45 + .../pytorch/cuda/stack_group_points_cuda.cu | 62 + .../ops/csrc/pytorch/cuda/sync_bn_cuda.cu | 110 + .../pytorch/cuda/three_interpolate_cuda.cu | 66 + .../ops/csrc/pytorch/cuda/tin_shift_cuda.cu | 55 + .../ops/csrc/pytorch/cuda/upfirdn2d_kernel.cu | 370 ++++ .../csrc/pytorch/cuda/voxelization_cuda.cu | 286 +++ .../mmcv/ops/csrc/pytorch/deform_conv.cpp | 517 +++++ .../mmcv/ops/csrc/pytorch/deform_roi_pool.cpp | 42 + .../ops/csrc/pytorch/diff_iou_rotated.cpp | 14 + .../mmcv/mmcv/ops/csrc/pytorch/focal_loss.cpp | 53 + .../csrc/pytorch/furthest_point_sample.cpp | 34 + .../ops/csrc/pytorch/fused_bias_leakyrelu.cpp | 119 ++ .../ops/csrc/pytorch/fused_spconv_ops.cpp | 34 + .../mmcv/ops/csrc/pytorch/gather_points.cpp | 30 + .../mmcv/ops/csrc/pytorch/group_points.cpp | 76 + .../CWD/mmcv/mmcv/ops/csrc/pytorch/info.cpp | 65 + .../CWD/mmcv/mmcv/ops/csrc/pytorch/iou3d.cpp | 66 + .../CWD/mmcv/mmcv/ops/csrc/pytorch/knn.cpp | 17 + .../mmcv/ops/csrc/pytorch/masked_conv2d.cpp | 33 + .../ops/csrc/pytorch/min_area_polygons.cpp | 11 + .../csrc/pytorch/mlu/bbox_overlaps_mlu.cpp | 100 + .../mmcv/ops/csrc/pytorch/mlu/carafe_mlu.cpp | 429 ++++ .../csrc/pytorch/mlu/deform_roi_pool_mlu.cpp | 343 +++ .../pytorch/mlu/focal_loss_sigmoid_mlu.cpp | 332 +++ .../mmcv/ops/csrc/pytorch/mlu/iou3d_mlu.cpp | 144 ++ .../csrc/pytorch/mlu/masked_conv2d_mlu.cpp | 226 ++ .../csrc/pytorch/mlu/ms_deform_attn_mlu.cpp | 420 ++++ .../mmcv/ops/csrc/pytorch/mlu/nms_mlu.cpp | 156 ++ .../mmcv/ops/csrc/pytorch/mlu/psamask_mlu.cpp | 308 +++ .../ops/csrc/pytorch/mlu/roi_align_mlu.cpp | 206 ++ .../pytorch/mlu/roi_align_rotated_mlu.cpp | 232 ++ .../ops/csrc/pytorch/mlu/roi_pool_mlu.cpp | 275 +++ .../csrc/pytorch/mlu/roiaware_pool3d_mlu.cpp | 399 ++++ .../csrc/pytorch/mlu/roipoint_pool3d_mlu.cpp | 166 ++ .../ops/csrc/pytorch/mlu/three_nn_mlu.cpp | 100 + .../ops/csrc/pytorch/mlu/tin_shift_mlu.cpp | 203 ++ .../csrc/pytorch/modulated_deform_conv.cpp | 237 +++ .../mmcv/ops/csrc/pytorch/ms_deform_attn.cpp | 60 + .../CWD/mmcv/mmcv/ops/csrc/pytorch/nms.cpp | 33 + .../mmcv/mmcv/ops/csrc/pytorch/nms_quadri.cpp | 30 + .../mmcv/ops/csrc/pytorch/nms_rotated.cpp | 32 + .../mmcv/ops/csrc/pytorch/pixel_group.cpp | 26 + .../mmcv/ops/csrc/pytorch/points_in_boxes.cpp | 44 + .../ops/csrc/pytorch/points_in_polygons.cpp | 15 + .../mmcv/mmcv/ops/csrc/pytorch/prroi_pool.cpp | 47 + .../mmcv/mmcv/ops/csrc/pytorch/psamask.cpp | 41 + .../CWD/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp | 922 ++++++++ .../ops/csrc/pytorch/riroi_align_rotated.cpp | 42 + .../mmcv/mmcv/ops/csrc/pytorch/roi_align.cpp | 41 + .../ops/csrc/pytorch/roi_align_rotated.cpp | 41 + .../mmcv/mmcv/ops/csrc/pytorch/roi_pool.cpp | 31 + .../mmcv/ops/csrc/pytorch/roiaware_pool3d.cpp | 72 + .../mmcv/ops/csrc/pytorch/roipoint_pool3d.cpp | 39 + .../csrc/pytorch/rotated_feature_align.cpp | 39 + .../mmcv/ops/csrc/pytorch/scatter_points.cpp | 53 + .../mmcv/mmcv/ops/csrc/pytorch/sync_bn.cpp | 69 + .../ops/csrc/pytorch/three_interpolate.cpp | 33 + .../mmcv/mmcv/ops/csrc/pytorch/tin_shift.cpp | 20 + .../mmcv/mmcv/ops/csrc/pytorch/upfirdn2d.cpp | 118 + .../mmcv/ops/csrc/pytorch/voxelization.cpp | 74 + cv/distiller/CWD/mmcv/mmcv/ops/deform_conv.py | 437 ++++ .../CWD/mmcv/mmcv/ops/deform_roi_pool.py | 211 ++ .../CWD/mmcv/mmcv/ops/deprecated_wrappers.py | 46 + .../CWD/mmcv/mmcv/ops/diff_iou_rotated.py | 301 +++ cv/distiller/CWD/mmcv/mmcv/ops/focal_loss.py | 208 ++ .../mmcv/mmcv/ops/furthest_point_sample.py | 84 + .../CWD/mmcv/mmcv/ops/fused_bias_leakyrelu.py | 282 +++ .../CWD/mmcv/mmcv/ops/gather_points.py | 59 + .../CWD/mmcv/mmcv/ops/group_points.py | 299 +++ cv/distiller/CWD/mmcv/mmcv/ops/info.py | 21 + cv/distiller/CWD/mmcv/mmcv/ops/iou3d.py | 226 ++ cv/distiller/CWD/mmcv/mmcv/ops/knn.py | 80 + cv/distiller/CWD/mmcv/mmcv/ops/masked_conv.py | 138 ++ cv/distiller/CWD/mmcv/mmcv/ops/merge_cells.py | 166 ++ .../CWD/mmcv/mmcv/ops/min_area_polygons.py | 20 + .../mmcv/mmcv/ops/modulated_deform_conv.py | 355 +++ .../mmcv/mmcv/ops/multi_scale_deform_attn.py | 369 ++++ cv/distiller/CWD/mmcv/mmcv/ops/nms.py | 471 ++++ cv/distiller/CWD/mmcv/mmcv/ops/pixel_group.py | 86 + .../CWD/mmcv/mmcv/ops/point_sample.py | 332 +++ .../CWD/mmcv/mmcv/ops/points_in_boxes.py | 137 ++ .../CWD/mmcv/mmcv/ops/points_in_polygons.py | 38 + .../CWD/mmcv/mmcv/ops/points_sampler.py | 178 ++ cv/distiller/CWD/mmcv/mmcv/ops/prroi_pool.py | 152 ++ cv/distiller/CWD/mmcv/mmcv/ops/psa_mask.py | 98 + .../CWD/mmcv/mmcv/ops/riroi_align_rotated.py | 140 ++ cv/distiller/CWD/mmcv/mmcv/ops/roi_align.py | 221 ++ .../CWD/mmcv/mmcv/ops/roi_align_rotated.py | 187 ++ cv/distiller/CWD/mmcv/mmcv/ops/roi_pool.py | 96 + .../CWD/mmcv/mmcv/ops/roiaware_pool3d.py | 132 ++ .../CWD/mmcv/mmcv/ops/roipoint_pool3d.py | 87 + .../mmcv/mmcv/ops/rotated_feature_align.py | 95 + cv/distiller/CWD/mmcv/mmcv/ops/saconv.py | 149 ++ .../CWD/mmcv/mmcv/ops/scatter_points.py | 148 ++ cv/distiller/CWD/mmcv/mmcv/ops/sync_bn.py | 283 +++ .../CWD/mmcv/mmcv/ops/three_interpolate.py | 69 + cv/distiller/CWD/mmcv/mmcv/ops/three_nn.py | 51 + cv/distiller/CWD/mmcv/mmcv/ops/tin_shift.py | 75 + cv/distiller/CWD/mmcv/mmcv/ops/upfirdn2d.py | 341 +++ cv/distiller/CWD/mmcv/mmcv/ops/voxelize.py | 183 ++ .../CWD/mmcv/mmcv/transforms/__init__.py | 30 + cv/distiller/CWD/mmcv/mmcv/transforms/base.py | 30 + .../CWD/mmcv/mmcv/transforms/builder.py | 2 + .../CWD/mmcv/mmcv/transforms/formatting.py | 127 ++ .../CWD/mmcv/mmcv/transforms/loading.py | 360 ++++ .../CWD/mmcv/mmcv/transforms/processing.py | 1562 ++++++++++++++ .../CWD/mmcv/mmcv/transforms/utils.py | 249 +++ .../CWD/mmcv/mmcv/transforms/wrappers.py | 648 ++++++ cv/distiller/CWD/mmcv/mmcv/utils/__init__.py | 10 + .../CWD/mmcv/mmcv/utils/device_type.py | 8 + cv/distiller/CWD/mmcv/mmcv/utils/env.py | 80 + .../CWD/mmcv/mmcv/utils/ext_loader.py | 72 + .../CWD/mmcv/mmcv/utils/parrots_jit.py | 41 + cv/distiller/CWD/mmcv/mmcv/version.py | 35 + cv/distiller/CWD/mmcv/mmcv/video/__init__.py | 11 + cv/distiller/CWD/mmcv/mmcv/video/io.py | 316 +++ cv/distiller/CWD/mmcv/mmcv/video/optflow.py | 272 +++ .../CWD/mmcv/mmcv/video/processing.py | 161 ++ .../CWD/mmcv/mmcv/visualization/__init__.py | 9 + .../CWD/mmcv/mmcv/visualization/color.py | 51 + .../CWD/mmcv/mmcv/visualization/image.py | 161 ++ .../CWD/mmcv/mmcv/visualization/optflow.py | 116 + cv/distiller/CWD/mmcv/requirements.txt | 4 + cv/distiller/CWD/mmcv/requirements/build.txt | 1 + cv/distiller/CWD/mmcv/requirements/docs.txt | 9 + .../CWD/mmcv/requirements/optional.txt | 2 + .../CWD/mmcv/requirements/runtime.txt | 8 + cv/distiller/CWD/mmcv/requirements/test.txt | 9 + cv/distiller/CWD/mmcv/setup.cfg | 26 + cv/distiller/CWD/mmcv/setup.py | 346 +++ .../CWD/mmcv/tests/data/batched_nms_data.pkl | Bin 0 -> 37884 bytes cv/distiller/CWD/mmcv/tests/data/color.jpg | Bin 0 -> 39779 bytes .../CWD/mmcv/tests/data/color_exif.jpg | Bin 0 -> 16139 bytes .../CWD/mmcv/tests/data/config/a.b.py | 5 + cv/distiller/CWD/mmcv/tests/data/config/a.py | 5 + .../CWD/mmcv/tests/data/config/b.json | 8 + .../CWD/mmcv/tests/data/config/base.py | 5 + .../CWD/mmcv/tests/data/config/c.yaml | 4 + .../CWD/mmcv/tests/data/config/code.py | 5 + cv/distiller/CWD/mmcv/tests/data/config/d.py | 6 + .../CWD/mmcv/tests/data/config/delete.py | 4 + .../CWD/mmcv/tests/data/config/deprecated.py | 6 + .../tests/data/config/deprecated_as_base.py | 2 + cv/distiller/CWD/mmcv/tests/data/config/e.py | 3 + .../CWD/mmcv/tests/data/config/expected.py | 2 + cv/distiller/CWD/mmcv/tests/data/config/f.py | 3 + cv/distiller/CWD/mmcv/tests/data/config/g.py | 2 + cv/distiller/CWD/mmcv/tests/data/config/h.py | 4 + .../CWD/mmcv/tests/data/config/i_base.py | 8 + .../CWD/mmcv/tests/data/config/i_child.py | 4 + cv/distiller/CWD/mmcv/tests/data/config/l.py | 10 + cv/distiller/CWD/mmcv/tests/data/config/l1.py | 2 + .../CWD/mmcv/tests/data/config/l2.yaml | 1 + .../CWD/mmcv/tests/data/config/l3.json | 3 + cv/distiller/CWD/mmcv/tests/data/config/l4.py | 4 + cv/distiller/CWD/mmcv/tests/data/config/m.py | 4 + cv/distiller/CWD/mmcv/tests/data/config/n.py | 23 + .../CWD/mmcv/tests/data/config/o.json | 3 + .../CWD/mmcv/tests/data/config/p.yaml | 1 + cv/distiller/CWD/mmcv/tests/data/config/q.py | 2 + cv/distiller/CWD/mmcv/tests/data/config/r.py | 4 + cv/distiller/CWD/mmcv/tests/data/config/s.py | 2 + .../CWD/mmcv/tests/data/config/t.json | 13 + cv/distiller/CWD/mmcv/tests/data/config/t.py | 7 + .../CWD/mmcv/tests/data/config/t.yaml | 6 + .../CWD/mmcv/tests/data/config/u.json | 26 + cv/distiller/CWD/mmcv/tests/data/config/u.py | 14 + .../CWD/mmcv/tests/data/config/u.yaml | 15 + cv/distiller/CWD/mmcv/tests/data/config/v.py | 12 + .../CWD/mmcv/tests/data/demo.lmdb/data.mdb | Bin 0 -> 70242 bytes .../CWD/mmcv/tests/data/demo.lmdb/lock.mdb | Bin 0 -> 8192 bytes cv/distiller/CWD/mmcv/tests/data/filelist.txt | 5 + .../for_3d_ops/features_for_fps_distance.npy | Bin 0 -> 32896 bytes .../mmcv/tests/data/for_3d_ops/fps_idx.npy | Bin 0 -> 256 bytes .../mmcv/tests/data/for_3d_ops/test_voxel.npy | Bin 0 -> 1663049 bytes .../tests/data/for_carafe/carafe_feat.bin | Bin 0 -> 4608 bytes .../data/for_carafe/carafe_feat_grad.bin | 33 + .../tests/data/for_carafe/carafe_mask.bin | Bin 0 -> 28800 bytes .../data/for_carafe/carafe_mask_grad.bin | Bin 0 -> 28800 bytes .../tests/data/for_carafe/carafe_output.bin | Bin 0 -> 18432 bytes .../for_ccattention/ccattention_input.bin | Bin 0 -> 259200 bytes .../for_ccattention/ccattention_output.bin | Bin 0 -> 259200 bytes .../masked_conv2d_for_bias.npy | Bin 0 -> 140 bytes .../masked_conv2d_for_input.npy | Bin 0 -> 3200 bytes .../masked_conv2d_for_mask.npy | Bin 0 -> 1152 bytes .../masked_conv2d_for_output.npy | Bin 0 -> 3200 bytes .../masked_conv2d_for_weight.npy | Bin 0 -> 452 bytes .../tests/data/for_psa_mask/psa_input.bin | Bin 0 -> 16384 bytes .../data/for_psa_mask/psa_output_collect.bin | Bin 0 -> 65536 bytes .../for_psa_mask/psa_output_distribute.bin | Bin 0 -> 65536 bytes .../CWD/mmcv/tests/data/for_scan/.file | 0 .../CWD/mmcv/tests/data/for_scan/1.json | 0 .../CWD/mmcv/tests/data/for_scan/1.txt | 0 .../CWD/mmcv/tests/data/for_scan/2.json | 0 .../CWD/mmcv/tests/data/for_scan/2.txt | 0 .../CWD/mmcv/tests/data/for_scan/3.TXT | 0 .../CWD/mmcv/tests/data/for_scan/a.bin | 0 .../CWD/mmcv/tests/data/for_scan/sub/1.json | 0 .../CWD/mmcv/tests/data/for_scan/sub/1.txt | 0 .../CWD/mmcv/tests/data/gray_alpha.png | Bin 0 -> 79322 bytes .../CWD/mmcv/tests/data/grayscale.jpg | Bin 0 -> 34638 bytes .../CWD/mmcv/tests/data/grayscale_dim3.jpg | Bin 0 -> 34661 bytes cv/distiller/CWD/mmcv/tests/data/mapping.txt | 3 + cv/distiller/CWD/mmcv/tests/data/optflow.flo | Bin 0 -> 38412 bytes .../CWD/mmcv/tests/data/optflow_concat0.jpg | Bin 0 -> 2951 bytes .../CWD/mmcv/tests/data/optflow_concat1.jpg | Bin 0 -> 2953 bytes cv/distiller/CWD/mmcv/tests/data/palette.gif | Bin 0 -> 127585 bytes .../CWD/mmcv/tests/data/patches/0.npy | Bin 0 -> 30080 bytes .../CWD/mmcv/tests/data/patches/1.npy | Bin 0 -> 45833 bytes .../CWD/mmcv/tests/data/patches/2.npy | Bin 0 -> 45080 bytes .../CWD/mmcv/tests/data/patches/3.npy | Bin 0 -> 120080 bytes .../CWD/mmcv/tests/data/patches/4.npy | Bin 0 -> 135080 bytes .../CWD/mmcv/tests/data/patches/pad0_0.npy | Bin 0 -> 43280 bytes .../CWD/mmcv/tests/data/patches/pad0_1.npy | Bin 0 -> 65783 bytes .../CWD/mmcv/tests/data/patches/pad0_2.npy | Bin 0 -> 64880 bytes .../CWD/mmcv/tests/data/patches/pad0_3.npy | Bin 0 -> 172520 bytes .../CWD/mmcv/tests/data/patches/pad0_4.npy | Bin 0 -> 193940 bytes .../CWD/mmcv/tests/data/patches/pad_0.npy | Bin 0 -> 43280 bytes .../CWD/mmcv/tests/data/patches/pad_1.npy | Bin 0 -> 65783 bytes .../CWD/mmcv/tests/data/patches/pad_2.npy | Bin 0 -> 64880 bytes .../CWD/mmcv/tests/data/patches/pad_3.npy | Bin 0 -> 172520 bytes .../CWD/mmcv/tests/data/patches/pad_4.npy | Bin 0 -> 193940 bytes .../CWD/mmcv/tests/data/patches/scale_0.npy | Bin 0 -> 43280 bytes .../CWD/mmcv/tests/data/patches/scale_1.npy | Bin 0 -> 55358 bytes .../CWD/mmcv/tests/data/patches/scale_2.npy | Bin 0 -> 54530 bytes .../CWD/mmcv/tests/data/patches/scale_3.npy | Bin 0 -> 144080 bytes .../CWD/mmcv/tests/data/patches/scale_4.npy | Bin 0 -> 162080 bytes .../CWD/mmcv/tests/data/scripts/hello.py | 25 + .../CWD/mmcv/tests/data/sparse_flow.png | Bin 0 -> 138 bytes cv/distiller/CWD/mmcv/tests/data/test.mp4 | Bin 0 -> 300601 bytes .../CWD/mmcv/tests/data/uint16-5channel.tif | Bin 0 -> 212483 bytes cv/distiller/CWD/mmcv/tests/test_arraymisc.py | 70 + .../mmcv/tests/test_cnn/test_build_layers.py | 430 ++++ .../mmcv/tests/test_cnn/test_context_block.py | 59 + .../test_cnn/test_conv2d_adaptive_padding.py | 28 + .../mmcv/tests/test_cnn/test_conv_module.py | 253 +++ .../test_depthwise_seperable_conv_module.py | 91 + .../mmcv/tests/test_cnn/test_flops_counter.py | 152 ++ .../mmcv/tests/test_cnn/test_fuse_conv_bn.py | 16 + .../test_cnn/test_generalized_attention.py | 76 + .../CWD/mmcv/tests/test_cnn/test_hsigmoid.py | 37 + .../CWD/mmcv/tests/test_cnn/test_hswish.py | 21 + .../CWD/mmcv/tests/test_cnn/test_non_local.py | 220 ++ .../CWD/mmcv/tests/test_cnn/test_scale.py | 78 + .../CWD/mmcv/tests/test_cnn/test_silu.py | 28 + .../CWD/mmcv/tests/test_cnn/test_swish.py | 16 + .../mmcv/tests/test_cnn/test_transformer.py | 687 ++++++ .../CWD/mmcv/tests/test_cnn/test_wrappers.py | 376 ++++ .../mmcv/tests/test_image/test_colorspace.py | 355 +++ .../mmcv/tests/test_image/test_geometric.py | 617 ++++++ .../mmcv/tests/test_image/test_image_misc.py | 73 + .../CWD/mmcv/tests/test_image/test_io.py | 437 ++++ .../mmcv/tests/test_image/test_photometric.py | 426 ++++ .../CWD/mmcv/tests/test_ops/output.pkl | Bin 0 -> 2168 bytes .../test_ops/test_active_rotated_filter.py | 258 +++ .../tests/test_ops/test_assign_score_withk.py | 188 ++ .../mmcv/tests/test_ops/test_ball_query.py | 102 + .../CWD/mmcv/tests/test_ops/test_bbox.py | 66 + .../mmcv/tests/test_ops/test_bezier_align.py | 54 + .../test_ops/test_bilinear_grid_sample.py | 41 + .../mmcv/tests/test_ops/test_border_align.py | 91 + .../tests/test_ops/test_box_iou_quadri.py | 77 + .../tests/test_ops/test_box_iou_rotated.py | 163 ++ .../CWD/mmcv/tests/test_ops/test_carafe.py | 85 + .../mmcv/tests/test_ops/test_cc_attention.py | 56 + .../tests/test_ops/test_chamfer_distance.py | 57 + .../tests/test_ops/test_contour_expand.py | 49 + .../mmcv/tests/test_ops/test_convex_iou.py | 56 + .../mmcv/tests/test_ops/test_corner_pool.py | 59 + .../mmcv/tests/test_ops/test_correlation.py | 46 + .../mmcv/tests/test_ops/test_deform_conv.py | 200 ++ .../tests/test_ops/test_deform_roi_pool.py | 152 ++ .../tests/test_ops/test_diff_iou_rotated.py | 49 + .../mmcv/tests/test_ops/test_focal_loss.py | 170 ++ .../test_ops/test_furthest_point_sample.py | 52 + .../test_ops/test_fused_bias_leakyrelu.py | 74 + .../mmcv/tests/test_ops/test_gather_points.py | 51 + .../mmcv/tests/test_ops/test_group_points.py | 164 ++ .../CWD/mmcv/tests/test_ops/test_info.py | 14 + .../CWD/mmcv/tests/test_ops/test_iou3d.py | 145 ++ .../CWD/mmcv/tests/test_ops/test_knn.py | 55 + .../mmcv/tests/test_ops/test_masked_conv2d.py | 41 + .../mmcv/tests/test_ops/test_merge_cells.py | 95 + .../tests/test_ops/test_min_area_polygons.py | 30 + .../test_ops/test_modulated_deform_conv.py | 127 ++ .../tests/test_ops/test_ms_deformable_attn.py | 244 +++ .../CWD/mmcv/tests/test_ops/test_nms.py | 205 ++ .../mmcv/tests/test_ops/test_nms_quadri.py | 119 ++ .../mmcv/tests/test_ops/test_nms_rotated.py | 116 + .../CWD/mmcv/tests/test_ops/test_onnx.py | 286 +++ .../mmcv/tests/test_ops/test_pixel_group.py | 78 + .../tests/test_ops/test_points_in_polygons.py | 23 + .../mmcv/tests/test_ops/test_prroi_pool.py | 98 + .../CWD/mmcv/tests/test_ops/test_psa_mask.py | 126 ++ .../test_ops/test_riroi_align_rotated.py | 84 + .../CWD/mmcv/tests/test_ops/test_roi_align.py | 120 ++ .../tests/test_ops/test_roi_align_rotated.py | 151 ++ .../CWD/mmcv/tests/test_ops/test_roi_pool.py | 105 + .../tests/test_ops/test_roiaware_pool3d.py | 159 ++ .../tests/test_ops/test_roipoint_pool3d.py | 50 + .../test_ops/test_rotated_feature_align.py | 131 ++ .../CWD/mmcv/tests/test_ops/test_saconv.py | 47 + .../tests/test_ops/test_scatter_points.py | 132 ++ .../CWD/mmcv/tests/test_ops/test_spconv.py | 133 ++ .../CWD/mmcv/tests/test_ops/test_syncbn.py | 295 +++ .../tests/test_ops/test_three_interpolate.py | 78 + .../CWD/mmcv/tests/test_ops/test_three_nn.py | 65 + .../CWD/mmcv/tests/test_ops/test_tin_shift.py | 226 ++ .../CWD/mmcv/tests/test_ops/test_upfirdn2d.py | 58 + .../mmcv/tests/test_ops/test_voxelization.py | 139 ++ .../test_transforms_formatting.py | 101 + .../test_transforms_loading.py | 151 ++ .../test_transforms_processing.py | 1014 +++++++++ .../test_transforms_wrapper.py | 585 +++++ .../CWD/mmcv/tests/test_utils/test_env.py | 34 + .../mmcv/tests/test_utils/test_parrots_jit.py | 278 +++ .../CWD/mmcv/tests/test_video/test_optflow.py | 291 +++ .../mmcv/tests/test_video/test_processing.py | 58 + .../CWD/mmcv/tests/test_video/test_reader.py | 210 ++ .../CWD/mmcv/tests/test_visualization.py | 19 + cv/distiller/CWD/mmrazor | 1 + 635 files changed, 83675 insertions(+) create mode 100644 cv/distiller/CWD/README.md create mode 100644 cv/distiller/CWD/mmcv/.circleci/config.yml create mode 100644 cv/distiller/CWD/mmcv/.circleci/docker/Dockerfile create mode 100644 cv/distiller/CWD/mmcv/.circleci/test.yml create mode 100644 cv/distiller/CWD/mmcv/.dev_scripts/check_installation.py create mode 100644 cv/distiller/CWD/mmcv/.dockerignore create mode 100644 cv/distiller/CWD/mmcv/.owners.yml create mode 100644 cv/distiller/CWD/mmcv/.pre-commit-config-zh-cn.yaml create mode 100644 cv/distiller/CWD/mmcv/.pre-commit-config.yaml create mode 100644 cv/distiller/CWD/mmcv/.readthedocs.yml create mode 100644 cv/distiller/CWD/mmcv/CITATION.cff create mode 100644 cv/distiller/CWD/mmcv/CONTRIBUTING.md create mode 100644 cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md create mode 100644 cv/distiller/CWD/mmcv/Jenkinsfile create mode 100644 cv/distiller/CWD/mmcv/LICENSE create mode 100644 cv/distiller/CWD/mmcv/LICENSES.md create mode 100644 cv/distiller/CWD/mmcv/MANIFEST.in create mode 100644 cv/distiller/CWD/mmcv/README.md create mode 100644 cv/distiller/CWD/mmcv/README_zh-CN.md create mode 100644 cv/distiller/CWD/mmcv/TERMINOLOGY.md create mode 100644 cv/distiller/CWD/mmcv/build_mmcv.sh create mode 100644 cv/distiller/CWD/mmcv/clean_mmcv.sh create mode 100644 cv/distiller/CWD/mmcv/compile.log create mode 100644 cv/distiller/CWD/mmcv/docker/README.md create mode 100644 cv/distiller/CWD/mmcv/docker/dev/Dockerfile create mode 100644 cv/distiller/CWD/mmcv/docker/release/Dockerfile create mode 100644 cv/distiller/CWD/mmcv/docs/en/Makefile create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/community/1.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/community/2.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/community/3.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/css/readthedocs.css create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/flow_img2toimg1.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/flow_raw_images.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/flow_visualization.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/flow_warp.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/flow_warp_diff.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/image/mmcv-logo.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/parallel_progress.gif create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/parallel_progress.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/progress.gif create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/progress.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/_static/version.json create mode 100644 cv/distiller/CWD/mmcv/docs/en/_templates/classtemplate.rst create mode 100644 cv/distiller/CWD/mmcv/docs/en/api/arraymisc.rst create mode 100644 cv/distiller/CWD/mmcv/docs/en/api/cnn.rst create mode 100644 cv/distiller/CWD/mmcv/docs/en/api/image.rst create mode 100644 cv/distiller/CWD/mmcv/docs/en/api/ops.rst create mode 100644 cv/distiller/CWD/mmcv/docs/en/api/transforms.rst create mode 100644 cv/distiller/CWD/mmcv/docs/en/api/utils.rst create mode 100644 cv/distiller/CWD/mmcv/docs/en/api/video.rst create mode 100644 cv/distiller/CWD/mmcv/docs/en/api/visualization.rst create mode 100644 cv/distiller/CWD/mmcv/docs/en/community/contributing.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/community/pr.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/compatibility.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/conf.py create mode 100644 cv/distiller/CWD/mmcv/docs/en/deployment/mmcv_ops_definition.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/docutils.conf create mode 100644 cv/distiller/CWD/mmcv/docs/en/faq.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/get_started/build.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/get_started/installation.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/get_started/introduction.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/get_started/previous_versions.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/index.rst create mode 100644 cv/distiller/CWD/mmcv/docs/en/make.bat create mode 100644 cv/distiller/CWD/mmcv/docs/en/mmcv-logo.png create mode 100644 cv/distiller/CWD/mmcv/docs/en/switch_language.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/understand_mmcv/cnn.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_process.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_transform.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/understand_mmcv/ops.md create mode 100644 cv/distiller/CWD/mmcv/docs/en/understand_mmcv/visualization.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/Makefile create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/_static/css/readthedocs.css create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/_static/image/mmcv-logo.png create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/_static/version.json create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/_templates/classtemplate.rst create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/api/arraymisc.rst create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/api/cnn.rst create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/api/image.rst create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/api/ops.rst create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/api/transforms.rst create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/api/utils.rst create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/api/video.rst create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/api/visualization.rst create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/community/code_style.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/community/contributing.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/community/pr.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/compatibility.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/conf.py create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/docutils.conf create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/faq.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/get_started/article.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/get_started/build.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/get_started/installation.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/get_started/introduction.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/get_started/previous_versions.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/index.rst create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/make.bat create mode 120000 cv/distiller/CWD/mmcv/docs/zh_cn/mmcv-logo.png create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/switch_language.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/cnn.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/data_process.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/data_transform.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/ops.md create mode 100644 cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/visualization.md create mode 100644 cv/distiller/CWD/mmcv/install_mmcv.sh create mode 100644 cv/distiller/CWD/mmcv/mmcv/__init__.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/arraymisc/__init__.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/arraymisc/quantization.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/__init__.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/alexnet.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/__init__.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/activation.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/context_block.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv2d_adaptive_padding.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv_module.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv_ws.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/depthwise_separable_conv_module.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/drop.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/generalized_attention.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/hsigmoid.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/hswish.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/non_local.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/norm.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/padding.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/plugin.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/scale.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/swish.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/transformer.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/upsample.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/bricks/wrappers.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/resnet.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/utils/__init__.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/utils/flops_counter.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/utils/fuse_conv_bn.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/cnn/vgg.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/image/__init__.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/image/colorspace.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/image/geometric.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/image/io.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/image/misc.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/image/photometric.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/__init__.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/active_rotated_filter.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/assign_score_withk.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/ball_query.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/bbox.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/bezier_align.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/border_align.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/box_iou_quadri.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/box_iou_rotated.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/carafe.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/cc_attention.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/chamfer_distance.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/contour_expand.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/convex_iou.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/corner_pool.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/correlation.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/README.md create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/active_rotated_filter_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/assign_score_withk_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/ball_query_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/bbox_overlaps_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/bezier_align_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/border_align_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/box_iou_quadri_cuda.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/box_iou_rotated_cuda.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/carafe_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/carafe_naive_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/chamfer_distance_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/common_cuda_helper.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/convex_iou_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/correlation_cuda.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/deform_conv_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/deform_roi_pool_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/diff_iou_rotated_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/furthest_point_sample_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/gather_points_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/group_points_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/iou3d_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/knn_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/masked_conv2d_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/min_area_polygons_cuda.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/modulated_deform_conv_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/ms_deform_attn_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/nms_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/nms_quadri_cuda.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/nms_rotated_cuda.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/parrots_cudawarpfunction.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/points_in_boxes_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/points_in_polygons_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/prroi_pool_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/psamask_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/riroi_align_rotated_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roi_align_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roi_align_rotated_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roi_pool_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roiaware_pool3d_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roipoint_pool3d_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/rotated_feature_align_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/scatter_points_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/sigmoid_focal_loss_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/softmax_focal_loss_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/stack_ball_query_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/stack_group_points_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/sync_bn_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/three_interpolate_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/tin_shift_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/voxelization_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/bbox_overlaps_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/carafe_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/carafe_utils.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/common_mlu_helper.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/deform_roi_pool_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/focal_loss_sigmoid_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/iou3d_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/iou3d_utils.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/masked_conv2d_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/ms_deform_attn_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/nms_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/nms_utils.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/psamask_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/psamask_utils.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_align_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_utils.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_pool_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roiaware_pool3d_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_large_boxes_num_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/three_nn_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/tin_shift_mlu_kernel.mlu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cpp_helper.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cuda_helper.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_cpp_helper.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_cuda_helper.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_device_registry.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_mlu_helper.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/active_rotated_filter.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/assign_score_withk.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/ball_query.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/bbox_overlaps.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/bezier_align.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/border_align.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/box_iou_quadri.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/box_iou_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/carafe.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/carafe_naive.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/chamfer_distance.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/contour_expand.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/convex_iou.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/correlation.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/active_rotated_filter.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/bezier_align.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_quadri.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/deform_conv.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/modulated_deform_conv.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/nms.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_quadri.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/pixel_group.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/points_in_boxes.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/psamask.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/rotated_feature_align.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/voxelization.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/active_rotated_filter_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/assign_score_withk_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/ball_query_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/bbox_overlaps_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/bezier_align_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/border_align_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_quadri_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_rotated_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_naive_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/chamfer_distance_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/convex_iou.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/correlation_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_conv_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_roi_pool_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/diff_iou_rotated_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/focal_loss_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/fused_bias_leakyrelu_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/gather_points_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/group_points_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/iou3d_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/knn_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/masked_conv2d_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/min_area_polygons.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/modulated_deform_conv_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/ms_deform_attn_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_quadri_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_rotated_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_boxes_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_polygons_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/prroi_pool_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/psamask_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/riroi_align_rotated_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_rotated_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_pool_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roiaware_pool3d_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roipoint_pool3d_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/rotated_feature_align_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/scatter_points_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_ball_query_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_group_points_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/sync_bn_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/three_interpolate_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/tin_shift_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/upfirdn2d_kernel.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/voxelization_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/deform_conv.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/deform_roi_pool.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/diff_iou_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/focal_loss.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/furthest_point_sample.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/fused_bias_leakyrelu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/fused_spconv_ops.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/gather_points.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/group_points.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/info.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/iou3d.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/knn.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/masked_conv2d.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/min_area_polygons.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/bbox_overlaps_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/carafe_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/deform_roi_pool_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/focal_loss_sigmoid_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/iou3d_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/masked_conv2d_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/ms_deform_attn_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/nms_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/psamask_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_rotated_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_pool_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roiaware_pool3d_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roipoint_pool3d_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/three_nn_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/tin_shift_mlu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/modulated_deform_conv.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/ms_deform_attn.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/nms.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/nms_quadri.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/nms_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pixel_group.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/points_in_boxes.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/points_in_polygons.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/prroi_pool.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/psamask.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/riroi_align_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roi_align.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roi_align_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roi_pool.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roiaware_pool3d.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roipoint_pool3d.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/rotated_feature_align.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/scatter_points.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/sync_bn.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/three_interpolate.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/tin_shift.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/upfirdn2d.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/voxelization.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/deform_conv.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/deform_roi_pool.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/deprecated_wrappers.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/diff_iou_rotated.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/focal_loss.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/furthest_point_sample.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/fused_bias_leakyrelu.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/gather_points.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/group_points.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/info.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/iou3d.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/knn.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/masked_conv.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/merge_cells.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/min_area_polygons.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/modulated_deform_conv.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/multi_scale_deform_attn.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/nms.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/pixel_group.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/point_sample.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/points_in_boxes.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/points_in_polygons.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/points_sampler.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/prroi_pool.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/psa_mask.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/riroi_align_rotated.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/roi_align.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/roi_align_rotated.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/roi_pool.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/roiaware_pool3d.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/roipoint_pool3d.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/rotated_feature_align.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/saconv.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/scatter_points.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/sync_bn.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/three_interpolate.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/three_nn.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/tin_shift.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/upfirdn2d.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/voxelize.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/transforms/__init__.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/transforms/base.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/transforms/builder.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/transforms/formatting.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/transforms/loading.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/transforms/processing.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/transforms/utils.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/transforms/wrappers.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/utils/__init__.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/utils/device_type.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/utils/env.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/utils/ext_loader.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/utils/parrots_jit.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/version.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/video/__init__.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/video/io.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/video/optflow.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/video/processing.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/visualization/__init__.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/visualization/color.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/visualization/image.py create mode 100644 cv/distiller/CWD/mmcv/mmcv/visualization/optflow.py create mode 100644 cv/distiller/CWD/mmcv/requirements.txt create mode 100644 cv/distiller/CWD/mmcv/requirements/build.txt create mode 100644 cv/distiller/CWD/mmcv/requirements/docs.txt create mode 100644 cv/distiller/CWD/mmcv/requirements/optional.txt create mode 100644 cv/distiller/CWD/mmcv/requirements/runtime.txt create mode 100644 cv/distiller/CWD/mmcv/requirements/test.txt create mode 100644 cv/distiller/CWD/mmcv/setup.cfg create mode 100644 cv/distiller/CWD/mmcv/setup.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/batched_nms_data.pkl create mode 100644 cv/distiller/CWD/mmcv/tests/data/color.jpg create mode 100644 cv/distiller/CWD/mmcv/tests/data/color_exif.jpg create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/a.b.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/a.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/b.json create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/base.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/c.yaml create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/code.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/d.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/delete.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/deprecated.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/deprecated_as_base.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/e.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/expected.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/f.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/g.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/h.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/i_base.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/i_child.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/l.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/l1.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/l2.yaml create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/l3.json create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/l4.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/m.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/n.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/o.json create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/p.yaml create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/q.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/r.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/s.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/t.json create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/t.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/t.yaml create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/u.json create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/u.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/u.yaml create mode 100644 cv/distiller/CWD/mmcv/tests/data/config/v.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/demo.lmdb/data.mdb create mode 100644 cv/distiller/CWD/mmcv/tests/data/demo.lmdb/lock.mdb create mode 100644 cv/distiller/CWD/mmcv/tests/data/filelist.txt create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_3d_ops/features_for_fps_distance.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_3d_ops/fps_idx.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_3d_ops/test_voxel.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_feat.bin create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_feat_grad.bin create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_mask.bin create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_mask_grad.bin create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_output.bin create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_ccattention/ccattention_input.bin create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_ccattention/ccattention_output.bin create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_bias.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_input.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_mask.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_output.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_weight.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_psa_mask/psa_input.bin create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_psa_mask/psa_output_collect.bin create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_psa_mask/psa_output_distribute.bin create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_scan/.file create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_scan/1.json create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_scan/1.txt create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_scan/2.json create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_scan/2.txt create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_scan/3.TXT create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_scan/a.bin create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_scan/sub/1.json create mode 100644 cv/distiller/CWD/mmcv/tests/data/for_scan/sub/1.txt create mode 100644 cv/distiller/CWD/mmcv/tests/data/gray_alpha.png create mode 100644 cv/distiller/CWD/mmcv/tests/data/grayscale.jpg create mode 100644 cv/distiller/CWD/mmcv/tests/data/grayscale_dim3.jpg create mode 100644 cv/distiller/CWD/mmcv/tests/data/mapping.txt create mode 100644 cv/distiller/CWD/mmcv/tests/data/optflow.flo create mode 100644 cv/distiller/CWD/mmcv/tests/data/optflow_concat0.jpg create mode 100644 cv/distiller/CWD/mmcv/tests/data/optflow_concat1.jpg create mode 100644 cv/distiller/CWD/mmcv/tests/data/palette.gif create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/0.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/1.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/2.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/3.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/4.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/pad0_0.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/pad0_1.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/pad0_2.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/pad0_3.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/pad0_4.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/pad_0.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/pad_1.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/pad_2.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/pad_3.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/pad_4.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/scale_0.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/scale_1.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/scale_2.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/scale_3.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/patches/scale_4.npy create mode 100644 cv/distiller/CWD/mmcv/tests/data/scripts/hello.py create mode 100644 cv/distiller/CWD/mmcv/tests/data/sparse_flow.png create mode 100644 cv/distiller/CWD/mmcv/tests/data/test.mp4 create mode 100644 cv/distiller/CWD/mmcv/tests/data/uint16-5channel.tif create mode 100644 cv/distiller/CWD/mmcv/tests/test_arraymisc.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_build_layers.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_context_block.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_conv2d_adaptive_padding.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_conv_module.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_depthwise_seperable_conv_module.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_flops_counter.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_fuse_conv_bn.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_generalized_attention.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_hsigmoid.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_hswish.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_non_local.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_scale.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_silu.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_swish.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_transformer.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_cnn/test_wrappers.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_image/test_colorspace.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_image/test_geometric.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_image/test_image_misc.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_image/test_io.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_image/test_photometric.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/output.pkl create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_active_rotated_filter.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_assign_score_withk.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_ball_query.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_bbox.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_bezier_align.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_bilinear_grid_sample.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_border_align.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_quadri.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_rotated.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_carafe.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_cc_attention.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_chamfer_distance.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_contour_expand.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_convex_iou.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_corner_pool.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_correlation.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_deform_conv.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_deform_roi_pool.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_diff_iou_rotated.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_focal_loss.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_furthest_point_sample.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_fused_bias_leakyrelu.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_gather_points.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_group_points.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_info.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_iou3d.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_knn.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_masked_conv2d.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_merge_cells.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_min_area_polygons.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_modulated_deform_conv.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_ms_deformable_attn.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_nms.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_nms_quadri.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_nms_rotated.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_onnx.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_pixel_group.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_points_in_polygons.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_prroi_pool.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_psa_mask.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_riroi_align_rotated.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align_rotated.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_roi_pool.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_roiaware_pool3d.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_roipoint_pool3d.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_rotated_feature_align.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_saconv.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_scatter_points.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_spconv.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_syncbn.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_three_interpolate.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_three_nn.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_tin_shift.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_upfirdn2d.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_ops/test_voxelization.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_formatting.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_loading.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_processing.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_wrapper.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_utils/test_env.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_utils/test_parrots_jit.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_video/test_optflow.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_video/test_processing.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_video/test_reader.py create mode 100644 cv/distiller/CWD/mmcv/tests/test_visualization.py create mode 160000 cv/distiller/CWD/mmrazor diff --git a/cv/distiller/CWD/README.md b/cv/distiller/CWD/README.md new file mode 100644 index 000000000..3302aa384 --- /dev/null +++ b/cv/distiller/CWD/README.md @@ -0,0 +1,73 @@ + +# CWD + +> [Channel-wise Knowledge Distillation for Dense Prediction](https://arxiv.org/abs/2011.13256) + + + +## Abstract + +Knowledge distillation (KD) has been proven to be a simple and effective tool for training compact models. Almost all KD variants for dense prediction tasks align the student and teacher networks' feature maps in the spatial domain, typically by minimizing point-wise and/or pair-wise discrepancy. Observing that in semantic segmentation, some layers' feature activations of each channel tend to encode saliency of scene categories (analogue to class activation mapping), we propose to align features channel-wise between the student and teacher networks. To this end, we first transform the feature map of each channel into a probability map using softmax normalization, and then minimize the Kullback-Leibler (KL) divergence of the corresponding channels of the two networks. By doing so, our method focuses on mimicking the soft distributions of channels between networks. In particular, the KL divergence enables learning to pay more attention to the most salient regions of the channel-wise maps, presumably corresponding to the most useful signals for semantic segmentation. Experiments demonstrate that our channel-wise distillation outperforms almost all existing spatial distillation methods for semantic segmentation considerably, and requires less computational cost during training. We consistently achieve superior performance on three benchmarks with various network structures. + +## Environment + +``` +cd mmcv +bash clean_mmcv.sh +bash build_mmcv.sh +bash install_mmcv.sh +cd ../mmrazor +pip3 install -r requirements.txt +pip3 install mmcls==v1.0.0rc6 +pip3 install mmsegmentation==v1.0.0rc6 +pip3 install mmengine==0.7.3 +python3 setup.py develop +``` + +## Cityscapes +Cityscapes 官方网站å¯ä»¥ä¸‹è½½ [Cityscapes]() æ•°æ®é›†ï¼ŒæŒ‰ç…§å®˜ç½‘è¦æ±‚注册并登陆åŽï¼Œæ•°æ®å¯ä»¥åœ¨[这里]()找到。 + +``` +mkdir data +cd data +# dowmload data +``` + +按照惯例,**labelTrainIds.png 用于 cityscapes 训练。 我们æä¾›äº†ä¸€ä¸ªåŸºäºŽ cityscapesscripts çš„è„šæœ¬ç”¨äºŽç”Ÿæˆ **labelTrainIds.png。 +```shell + ├── data + │ ├── cityscapes + │ │ ├── leftImg8bit + │ │ │ ├── train + │ │ │ ├── val + │ │ ├── gtFine + │ │ │ ├── train + │ │ │ ├── val + ``` +## --nproc 表示 8 个转æ¢è¿›ç¨‹ï¼Œä¹Ÿå¯ä»¥çœç•¥ã€‚ +``` +cd .. +python3 tools/dataset_converters/cityscapes.py data/cityscapes --nproc 8 +``` +## Training + +### On single GPU + +```bash +python3 tools/train.py configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py +``` + +### Multiple GPUs on one machine + +```bash +bash tools/dist_train.sh configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py 8 +``` + + + + +## Segmentation + +| Location | Dataset | Teacher | Student | mIoU | mIoU(T) | mIou(S) | Config | Download | +| :------: | :--------: | :------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------: | :---: | :-----: | :-----: | :----------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| logits | cityscapes | [pspnet_r101](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes.py) | [pspnet_r18](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/pspnet/pspnet_r18-d8_512x1024_80k_cityscapes.py) | 75.54 | 79.76 | 74.87 | [config](<>) | [teacher](https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes/pspnet_r101-d8_512x1024_80k_cityscapes_20200606_112211-e1e1100f.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/cwd/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k_mIoU-75.54_20211222-3e643f6f.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/distill/cwd/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k_20211212_205711.log.json) | \ No newline at end of file diff --git a/cv/distiller/CWD/mmcv/.circleci/config.yml b/cv/distiller/CWD/mmcv/.circleci/config.yml new file mode 100644 index 000000000..e13eabe9c --- /dev/null +++ b/cv/distiller/CWD/mmcv/.circleci/config.yml @@ -0,0 +1,32 @@ +version: 2.1 + +# this allows you to use CircleCI's dynamic configuration feature +setup: true + +# the path-filtering orb is required to continue a pipeline based on +# the path of an updated fileset +orbs: + path-filtering: circleci/path-filtering@0.1.2 + +workflows: + # the always-run workflow is always triggered, regardless of the pipeline parameters. + always-run: + jobs: + # the path-filtering/filter job determines which pipeline + # parameters to update. + - path-filtering/filter: + name: check-updated-files + # 3-column, whitespace-delimited mapping. One mapping per + # line: + # + mapping: | + mmcv/.* lint_only false + requirements/.* lint_only false + tests/.* lint_only false + .circleci/.* lint_only false + base-revision: 2.x + # this is the path of the configuration we should trigger once + # path filtering and pipeline parameter value updates are + # complete. In this case, we are using the parent dynamic + # configuration itself. + config-path: .circleci/test.yml diff --git a/cv/distiller/CWD/mmcv/.circleci/docker/Dockerfile b/cv/distiller/CWD/mmcv/.circleci/docker/Dockerfile new file mode 100644 index 000000000..db5ab86e3 --- /dev/null +++ b/cv/distiller/CWD/mmcv/.circleci/docker/Dockerfile @@ -0,0 +1,15 @@ +ARG PYTORCH="1.8.1" +ARG CUDA="10.2" +ARG CUDNN="7" + +FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-devel + +# Set MKL_THREADING_LAYER=GNU to fix issue: +# https://github.com/pytorch/pytorch/issues/37377 +ENV MKL_THREADING_LAYER GNU + +# To fix GPG key error when running apt-get update +RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub +RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/7fa2af80.pub + +RUN apt-get update && apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx ffmpeg libturbojpeg git diff --git a/cv/distiller/CWD/mmcv/.circleci/test.yml b/cv/distiller/CWD/mmcv/.circleci/test.yml new file mode 100644 index 000000000..9150be69e --- /dev/null +++ b/cv/distiller/CWD/mmcv/.circleci/test.yml @@ -0,0 +1,270 @@ +version: 2.1 + +# the default pipeline parameters, which will be updated according to +# the results of the path-filtering orb +parameters: + lint_only: + type: boolean + default: true + +jobs: + lint: + docker: + - image: cimg/python:3.7.4 + steps: + - checkout + - run: + name: Install pre-commit hook + command: | + pip install pre-commit + pre-commit install + - run: + name: Linting + command: pre-commit run --all-files + build_without_torch: + parameters: + # The python version must match available image tags in + # https://circleci.com/developer/images/image/cimg/python + python: + type: string + default: "3.7.4" + docker: + - image: cimg/python:<< parameters.python >> + resource_class: large + steps: + - checkout + - run: + name: Install Libraries + command: | + sudo apt-get update + sudo apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx libjpeg-dev zlib1g-dev libtinfo-dev libncurses5 ffmpeg libturbojpeg + - run: + name: Upgrade pip + command: | + pip install pip --upgrade + pip --version + - run: + name: Install MMEngine from main branch + command: pip install git+https://github.com/open-mmlab/mmengine.git@main + - run: + name: Build MMCV from source + command: pip install -e . -v + environment: + MMCV_WITH_OPS: 0 + - run: + name: Install unit tests dependencies + command: pip install -r requirements/test.txt + - run: + name: Run unit tests + command: pytest tests/test_image tests/test_transforms tests/test_video tests/test_arraymisc.py tests/test_visualization.py tests/test_utils/test_env.py --ignore=tests/test_image/test_io.py + build_without_ops: + parameters: + # The python version must match available image tags in + # https://circleci.com/developer/images/image/cimg/python + python: + type: string + default: "3.7.4" + torch: + type: string + torchvision: + type: string + docker: + - image: cimg/python:<< parameters.python >> + resource_class: large + steps: + - checkout + - run: + name: Install Libraries + command: | + sudo apt-get update + sudo apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx libjpeg-dev zlib1g-dev libtinfo-dev libncurses5 ffmpeg libturbojpeg + - run: + name: Configure Python & pip + command: | + pip install --upgrade pip + pip install wheel + - run: + name: Install PyTorch + command: pip install torch==<< parameters.torch >>+cpu torchvision==<< parameters.torchvision >>+cpu -f https://download.pytorch.org/whl/torch_stable.html + - run: + name: Install MMEngine from main branch + command: pip install git+https://github.com/open-mmlab/mmengine.git@main + - run: + name: Create sdist and untar + command: | + sed -i "s/os.getenv('MMCV_WITH_OPS', '1')/os.getenv('MMCV_WITH_OPS', '0')/g" setup.py + python setup.py sdist + tar zxvf dist/mmcv* -C /tmp + rm -r mmcv + - run: + name: Build and install from sdist + command: | + pushd /tmp/mmcv* + pip install -e . -v + popd + - run: + name: Install unit tests dependencies + command: pip install -r requirements/test.txt + - run: + name: Run unit tests + command: pytest tests --ignore=tests/test_ops + build_cpu: + parameters: + # The python version must match available image tags in + # https://circleci.com/developer/images/image/cimg/python + python: + type: string + torch: + type: string + torchvision: + type: string + docker: + - image: cimg/python:<< parameters.python >> + resource_class: large + steps: + - checkout + - run: + name: Install Libraries + command: | + sudo apt-get update + sudo apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx libjpeg-dev zlib1g-dev libtinfo-dev libncurses5 ffmpeg libturbojpeg + - run: + name: Configure Python & pip + command: | + pip install --upgrade pip + pip install wheel + - run: + name: Install PyTorch + command: pip install torch==<< parameters.torch >>+cpu torchvision==<< parameters.torchvision >>+cpu -f https://download.pytorch.org/whl/torch_stable.html + - run: + name: Install MMEngine from main branch + command: pip install git+https://github.com/open-mmlab/mmengine.git@main + - run: + name: Install ninja to speed the compilation + command: pip install ninja + - run: + name: Create sdist and untar + command: | + python setup.py sdist + tar zxvf dist/mmcv* -C /tmp + rm -r mmcv + - run: + name: Build and install from sdist + command: | + pushd /tmp/mmcv* + pip install -e . -v + popd + - run: + name: Install unit tests dependencies + command: pip install -r requirements/test.txt + - run: + name: Run unittests + command: | + coverage run --branch --source mmcv -m pytest tests/ + coverage xml + coverage report -m + build_cuda: + parameters: + torch: + type: string + cuda: + type: enum + enum: ["10.1", "10.2", "11.1"] + cudnn: + type: integer + default: 7 + machine: + image: ubuntu-2004-cuda-11.4:202110-01 + docker_layer_caching: true + resource_class: gpu.nvidia.small + steps: + - checkout + - run: + name: Build Docker image + command: | + docker build .circleci/docker -t mmcv:gpu --build-arg PYTORCH=<< parameters.torch >> --build-arg CUDA=<< parameters.cuda >> --build-arg CUDNN=<< parameters.cudnn >> + docker run --gpus all -t -d -v /home/circleci/project:/mmcv -w /mmcv --name mmcv mmcv:gpu + - run: + name: Install MMEngine from main branch + command: docker exec mmcv pip install git+https://github.com/open-mmlab/mmengine.git@main + - run: + name: Build MMCV from source + command: docker exec mmcv pip install -e . -v + - run: + name: Install unit tests dependencies + command: docker exec mmcv pip install -r requirements/test.txt + - run: + name: Run unittests + command: docker exec mmcv python -m pytest tests/ +workflows: + pr_stage_lint: + when: << pipeline.parameters.lint_only >> + jobs: + - lint: + name: lint + filters: + branches: + ignore: + - 2.x + pr_stage_test: + when: + not: + << pipeline.parameters.lint_only >> + jobs: + - lint: + name: lint + filters: + branches: + ignore: + - 2.x + - build_without_torch: + name: build_without_torch + requires: + - lint + - build_without_ops: + name: build_without_ops + torch: 1.6.0 + torchvision: 0.7.0 + requires: + - build_without_torch + - build_cpu: + name: minimum_version_cpu + torch: 1.6.0 + torchvision: 0.7.0 + python: 3.7.4 + requires: + - build_without_ops + - build_cpu: + name: maximum_version_cpu + torch: 1.13.0 + torchvision: 0.14.0 + python: 3.9.0 + requires: + - minimum_version_cpu + - hold: + type: approval + requires: + - maximum_version_cpu + - build_cuda: + name: mainstream_version_gpu + torch: 1.8.1 + # Use double quotation mark to explicitly specify its type + # as string instead of number + cuda: "10.2" + requires: + - hold + merge_stage_test: + when: + not: + << pipeline.parameters.lint_only >> + jobs: + - build_cuda: + name: minimum_version_gpu + torch: 1.6.0 + # Use double quotation mark to explicitly specify its type + # as string instead of number + cuda: "10.1" + filters: + branches: + only: + - 2.x diff --git a/cv/distiller/CWD/mmcv/.dev_scripts/check_installation.py b/cv/distiller/CWD/mmcv/.dev_scripts/check_installation.py new file mode 100644 index 000000000..739c1e110 --- /dev/null +++ b/cv/distiller/CWD/mmcv/.dev_scripts/check_installation.py @@ -0,0 +1,44 @@ +import numpy as np +import torch + +from mmcv.ops import box_iou_rotated +from mmcv.utils import collect_env + + +def check_installation(): + """Check whether mmcv has been installed successfully.""" + np_boxes1 = np.asarray( + [[1.0, 1.0, 3.0, 4.0, 0.5], [2.0, 2.0, 3.0, 4.0, 0.6], + [7.0, 7.0, 8.0, 8.0, 0.4]], + dtype=np.float32) + np_boxes2 = np.asarray( + [[0.0, 2.0, 2.0, 5.0, 0.3], [2.0, 1.0, 3.0, 3.0, 0.5], + [5.0, 5.0, 6.0, 7.0, 0.4]], + dtype=np.float32) + boxes1 = torch.from_numpy(np_boxes1) + boxes2 = torch.from_numpy(np_boxes2) + + # test mmcv with CPU ops + box_iou_rotated(boxes1, boxes2) + print('CPU ops were compiled successfully.') + + # test mmcv with both CPU and CUDA ops + if torch.cuda.is_available(): + boxes1 = boxes1.cuda() + boxes2 = boxes2.cuda() + box_iou_rotated(boxes1, boxes2) + print('CUDA ops were compiled successfully.') + else: + print('No CUDA runtime is found, skipping the checking of CUDA ops.') + + +if __name__ == '__main__': + print('Start checking the installation of mmcv ...') + check_installation() + print('mmcv has been installed successfully.\n') + + env_info_dict = collect_env() + env_info = '\n'.join([(f'{k}: {v}') for k, v in env_info_dict.items()]) + dash_line = '-' * 60 + '\n' + print('Environment information:') + print(dash_line + env_info + '\n' + dash_line) diff --git a/cv/distiller/CWD/mmcv/.dockerignore b/cv/distiller/CWD/mmcv/.dockerignore new file mode 100644 index 000000000..8c22f226d --- /dev/null +++ b/cv/distiller/CWD/mmcv/.dockerignore @@ -0,0 +1,6 @@ +.git +.gitignore +*.egg-info +.eggs/ +.mypy-cache +pip-wheel-metadata diff --git a/cv/distiller/CWD/mmcv/.owners.yml b/cv/distiller/CWD/mmcv/.owners.yml new file mode 100644 index 000000000..8f7057cb3 --- /dev/null +++ b/cv/distiller/CWD/mmcv/.owners.yml @@ -0,0 +1,14 @@ +assign: + strategy: + # random + daily-shift-based + scedule: + '*/1 * * * *' + assignees: + - zhouzaida + - ice-tong + - HAOCHENYE + - zhouzaida + - ice-tong + - HAOCHENYE + - zhouzaida diff --git a/cv/distiller/CWD/mmcv/.pre-commit-config-zh-cn.yaml b/cv/distiller/CWD/mmcv/.pre-commit-config-zh-cn.yaml new file mode 100644 index 000000000..73f0388fe --- /dev/null +++ b/cv/distiller/CWD/mmcv/.pre-commit-config-zh-cn.yaml @@ -0,0 +1,72 @@ +exclude: ^tests/data/ +repos: + - repo: https://gitee.com/openmmlab/mirrors-flake8 + rev: 5.0.4 + hooks: + - id: flake8 + - repo: https://gitee.com/openmmlab/mirrors-isort + rev: 5.10.1 + hooks: + - id: isort + - repo: https://gitee.com/openmmlab/mirrors-yapf + rev: v0.32.0 + hooks: + - id: yapf + - repo: https://gitee.com/openmmlab/mirrors-pre-commit-hooks + rev: v4.3.0 + hooks: + - id: trailing-whitespace + - id: check-yaml + - id: end-of-file-fixer + - id: requirements-txt-fixer + - id: double-quote-string-fixer + - id: check-merge-conflict + - id: fix-encoding-pragma + args: ["--remove"] + - id: mixed-line-ending + args: ["--fix=lf"] + - repo: https://gitee.com/openmmlab/mirrors-codespell + rev: v2.2.1 + hooks: + - id: codespell + - repo: https://gitee.com/openmmlab/mirrors-mdformat + rev: 0.7.9 + hooks: + - id: mdformat + args: ["--number"] + additional_dependencies: + - mdformat-openmmlab + - mdformat_frontmatter + - linkify-it-py + - repo: https://gitee.com/openmmlab/mirrors-docformatter + rev: v1.3.1 + hooks: + - id: docformatter + args: ["--in-place", "--wrap-descriptions", "79"] + - repo: https://github.com/asottile/pyupgrade + rev: v3.0.0 + hooks: + - id: pyupgrade + args: ["--py36-plus"] + - repo: https://gitee.com/openmmlab/pre-commit-hooks + rev: v0.2.0 # Use the ref you want to point at + hooks: + - id: check-copyright + args: ["mmcv", "tests", "--excludes", "mmcv/ops"] + - repo: https://gitee.com/openmmlab/mirrors-mypy + rev: v0.812 + hooks: + - id: mypy + exclude: |- + (?x)( + ^test + | ^docs + ) + # - repo: local + # hooks: + # - id: clang-format + # name: clang-format + # description: Format files with ClangFormat + # entry: clang-format -style=google -i + # language: system + # files: \.(c|cc|cxx|cpp|cu|h|hpp|hxx|cuh|proto)$ diff --git a/cv/distiller/CWD/mmcv/.pre-commit-config.yaml b/cv/distiller/CWD/mmcv/.pre-commit-config.yaml new file mode 100644 index 000000000..2f7fdf013 --- /dev/null +++ b/cv/distiller/CWD/mmcv/.pre-commit-config.yaml @@ -0,0 +1,72 @@ +exclude: ^tests/data/ +repos: + - repo: https://github.com/PyCQA/flake8 + rev: 5.0.4 + hooks: + - id: flake8 + - repo: https://github.com/PyCQA/isort + rev: 5.10.1 + hooks: + - id: isort + - repo: https://github.com/pre-commit/mirrors-yapf + rev: v0.32.0 + hooks: + - id: yapf + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: trailing-whitespace + - id: check-yaml + - id: end-of-file-fixer + - id: requirements-txt-fixer + - id: double-quote-string-fixer + - id: check-merge-conflict + - id: fix-encoding-pragma + args: ["--remove"] + - id: mixed-line-ending + args: ["--fix=lf"] + - repo: https://github.com/codespell-project/codespell + rev: v2.2.1 + hooks: + - id: codespell + - repo: https://github.com/executablebooks/mdformat + rev: 0.7.9 + hooks: + - id: mdformat + args: ["--number"] + additional_dependencies: + - mdformat-openmmlab + - mdformat_frontmatter + - linkify-it-py + - repo: https://github.com/myint/docformatter + rev: v1.3.1 + hooks: + - id: docformatter + args: ["--in-place", "--wrap-descriptions", "79"] + - repo: https://github.com/asottile/pyupgrade + rev: v3.0.0 + hooks: + - id: pyupgrade + args: ["--py36-plus"] + - repo: https://github.com/open-mmlab/pre-commit-hooks + rev: v0.2.0 # Use the ref you want to point at + hooks: + - id: check-copyright + args: ["mmcv", "tests", "--excludes", "mmcv/ops"] + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.812 + hooks: + - id: mypy + exclude: |- + (?x)( + ^test + | ^docs + ) + # - repo: local + # hooks: + # - id: clang-format + # name: clang-format + # description: Format files with ClangFormat + # entry: clang-format -style=google -i + # language: system + # files: \.(c|cc|cxx|cpp|cu|h|hpp|hxx|cuh|proto)$ diff --git a/cv/distiller/CWD/mmcv/.readthedocs.yml b/cv/distiller/CWD/mmcv/.readthedocs.yml new file mode 100644 index 000000000..7d5f1c206 --- /dev/null +++ b/cv/distiller/CWD/mmcv/.readthedocs.yml @@ -0,0 +1,9 @@ +version: 2 + +formats: all + +python: + version: 3.7 + install: + - requirements: requirements/runtime.txt + - requirements: requirements/docs.txt diff --git a/cv/distiller/CWD/mmcv/CITATION.cff b/cv/distiller/CWD/mmcv/CITATION.cff new file mode 100644 index 000000000..786117aac --- /dev/null +++ b/cv/distiller/CWD/mmcv/CITATION.cff @@ -0,0 +1,8 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +authors: + - name: "MMCV Contributors" +title: "OpenMMLab Computer Vision Foundation" +date-released: 2018-08-22 +url: "https://github.com/open-mmlab/mmcv" +license: Apache-2.0 diff --git a/cv/distiller/CWD/mmcv/CONTRIBUTING.md b/cv/distiller/CWD/mmcv/CONTRIBUTING.md new file mode 100644 index 000000000..a60cd9943 --- /dev/null +++ b/cv/distiller/CWD/mmcv/CONTRIBUTING.md @@ -0,0 +1,258 @@ +## Contributing to OpenMMLab + +Welcome to the MMCV community, we are committed to building a cutting-edge computer vision foundational library and all kinds of contributions are welcomed, including but not limited to + +**Fix bug** + +You can directly post a Pull Request to fix typo in code or documents + +The steps to fix the bug of code implementation are as follows. + +1. If the modification involve significant changes, you should create an issue first and describe the error information and how to trigger the bug. Other developers will discuss with you and propose an proper solution. + +2. Posting a pull request after fixing the bug and adding corresponding unit test. + +**New Feature or Enhancement** + +1. If the modification involve significant changes, you should create an issue to discuss with our developers to propose an proper design. +2. Post a Pull Request after implementing the new feature or enhancement and add corresponding unit test. + +**Document** + +You can directly post a pull request to fix documents. If you want to add a document, you should first create an issue to check if it is reasonable. + +### Pull Request Workflow + +If you're not familiar with Pull Request, don't worry! The following guidance will tell you how to create a Pull Request step by step. If you want to dive into the develop mode of Pull Request, you can refer to the [official documents](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) + +#### 1. Fork and clone + +If you are posting a pull request for the first time, you should fork the OpenMMLab repositories by clicking the **Fork** button in the top right corner of the GitHub page, and the forked repositories will appear under your GitHub profile. + + + +Then, you can clone the repositories to local: + +```shell +git clone git@github.com:{username}/mmcv.git +``` + +After that, you should ddd official repository as the upstream repository + +```bash +git remote add upstream git@github.com:open-mmlab/mmcv +``` + +Check whether remote repository has been added successfully by `git remote -v` + +```bash +origin git@github.com:{username}/mmcv.git (fetch) +origin git@github.com:{username}/mmcv.git (push) +upstream git@github.com:open-mmlab/mmcv (fetch) +upstream git@github.com:open-mmlab/mmcv (push) +``` + +> Here's a brief introduction to origin and upstream. When we use "git clone", we create an "origin" remote by default, which points to the repository cloned from. As for "upstream", we add it ourselves to point to the target repository. Of course, if you don't like the name "upstream", you could name it as you wish. Usually, we'll push the code to "origin". If the pushed code conflicts with the latest code in official("upstream"), we should pull the latest code from upstream to resolve the conflicts, and then push to "origin" again. The posted Pull Request will be updated automatically. + +#### 2. Configure pre-commit + +You should configure [pre-commit](https://pre-commit.com/#intro) in the local development environment to make sure the code style matches that of OpenMMLab. **Note**: The following code should be executed under the MMCV directory. + +```shell +pip install -U pre-commit +pre-commit install +``` + +Check that pre-commit is configured successfully, and install the hooks defined in `.pre-commit-config.yaml`. + +```shell +pre-commit run --all-files +``` + + + + + +If the installation process is interrupted, you can repeatedly run `pre-commit run ... ` to continue the installation. + +If the code does not conform to the code style specification, pre-commit will raise a warning and fixes some of the errors automatically. + + + +If we want to commit our code bypassing the pre-commit hook, we can use the `--no-verify` option(**only for temporarily commit**). + +```shell +git commit -m "xxx" --no-verify +``` + +#### 3. Create a development branch + +After configuring the pre-commit, we should create a branch based on the master branch to develop the new feature or fix the bug. The proposed branch name is `username/pr_name` + +```shell +git checkout -b yhc/refactor_contributing_doc +``` + +In subsequent development, if the master branch of the local repository is behind the master branch of "upstream", we need to pull the upstream for synchronization, and then execute the above command: + +```shell +git pull upstream master +``` + +#### 4. Commit the code and pass the unit test + +- MMCV introduces mypy to do static type checking to increase the robustness of the code. Therefore, we need to add Type Hints to our code and pass the mypy check. If you are not familiar with Type Hints, you can refer to [this tutorial](https://docs.python.org/3/library/typing.html). + +- The committed code should pass through the unit test + + ```shell + # Pass all unit tests + pytest tests + + # Pass the unit test of runner + pytest tests/test_runner/test_runner.py + ``` + + If the unit test fails for lack of dependencies, you can install the dependencies referring to the [guidance](#unit-test) + +- If the documents are modified/added, we should check the rendering result referring to [guidance](#document-rendering) + +#### 5. Push the code to remote + +We could push the local commits to remote after passing through the check of unit test and pre-commit. You can associate the local branch with remote branch by adding `-u` option. + +```shell +git push -u origin {branch_name} +``` + +This will allow you to use the `git push` command to push code directly next time, without having to specify a branch or the remote repository. + +#### 6. Create a Pull Request + +(1) Create a pull request in GitHub's Pull request interface + + + +(2) Modify the PR description according to the guidelines so that other developers can better understand your changes + + + +Find more details about Pull Request description in [pull request guidelines](#pr-specs). + +**note** + +(a) The Pull Request description should contain the reason for the change, the content of the change, and the impact of the change, and be associated with the relevant Issue (see [documentation](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) + +(b) If it is your first contribution, please sign the CLA + + + +(c) Check whether the Pull Request pass through the CI + + + +MMCV will run unit test for the posted Pull Request on different platforms (Linux, Window, Mac), based on different versions of Python, PyTorch, CUDA to make sure the code is correct. We can see the specific test information by clicking `Details` in the above image so that we can modify the code. + +(3) If the Pull Request passes the CI, then you can wait for the review from other developers. You'll modify the code based on the reviewer's comments, and repeat the steps [4](#4-commit-the-code-and-pass-the-unit-test)-[5](#5-push-the-code-to-remote) until all reviewers approve it. Then, we will merge it ASAP. + + + +#### 7. Resolve conflicts + +If your local branch conflicts with the latest master branch of "upstream", you'll need to resolove them. There are two ways to do this: + +```shell +git fetch --all --prune +git rebase upstream/master +``` + +or + +```shell +git fetch --all --prune +git merge upstream/master +``` + +If you are very good at handling conflicts, then you can use rebase to resolve conflicts, as this will keep your commit logs tidy. If you are not familiar with `rebase`, then you can use `merge` to resolve conflicts. + +### Guidance + +#### Unit test + +If you cannot run the unit test of some modules for lacking of some dependencies, such as [video](https://github.com/open-mmlab/mmcv/tree/master/mmcv/video) module, you can try to install the following dependencies: + +```shell +# Linux +sudo apt-get update -y +sudo apt-get install -y libturbojpeg +sudo apt-get install -y ffmpeg + +# Windows +conda install ffmpeg +``` + +We should also make sure the committed code will not decrease the coverage of unit test, we could run the following command to check the coverage of unit test: + +```shell +python -m coverage run -m pytest /path/to/test_file +python -m coverage html +# check file in htmlcov/index.html +``` + +#### Document rendering + +If the documents are modified/added, we should check the rendering result. We could install the dependencies and run the following command to render the documents and check the results: + +```shell +pip install -r requirements/docs.txt +cd docs/zh_cn/ +# or docs/en +make html +# check file in ./docs/zh_cn/_build/html/index.html +``` + +### Code style + +#### Python + +We adopt [PEP8](https://www.python.org/dev/peps/pep-0008/) as the preferred code style. + +We use the following tools for linting and formatting: + +- [flake8](https://github.com/PyCQA/flake8): A wrapper around some linter tools. +- [isort](https://github.com/timothycrosley/isort): A Python utility to sort imports. +- [yapf](https://github.com/google/yapf): A formatter for Python files. +- [codespell](https://github.com/codespell-project/codespell): A Python utility to fix common misspellings in text files. +- [mdformat](https://github.com/executablebooks/mdformat): Mdformat is an opinionated Markdown formatter that can be used to enforce a consistent style in Markdown files. +- [docformatter](https://github.com/myint/docformatter): A formatter to format docstring. + +Style configurations of yapf and isort can be found in [setup.cfg](./setup.cfg). + +We use [pre-commit hook](https://pre-commit.com/) that checks and formats for `flake8`, `yapf`, `isort`, `trailing whitespaces`, `markdown files`, +fixes `end-of-files`, `double-quoted-strings`, `python-encoding-pragma`, `mixed-line-ending`, sorts `requirments.txt` automatically on every commit. +The config for a pre-commit hook is stored in [.pre-commit-config](./.pre-commit-config.yaml). + +#### C++ and CUDA + +We follow the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). + +### PR Specs + +1. Use [pre-commit](https://pre-commit.com) hook to avoid issues of code style + +2. One short-time branch should be matched with only one PR + +3. Accomplish a detailed change in one PR. Avoid large PR + + - Bad: Support Faster R-CNN + - Acceptable: Add a box head to Faster R-CNN + - Good: Add a parameter to box head to support custom conv-layer number + +4. Provide clear and significant commit message + +5. Provide clear and meaningful PR description + + - Task name should be clarified in title. The general format is: \[Prefix\] Short description of the PR (Suffix) + - Prefix: add new feature \[Feature\], fix bug \[Fix\], related to documents \[Docs\], in developing \[WIP\] (which will not be reviewed temporarily) + - Introduce main changes, results and influences on other modules in short description + - Associate related issues and pull requests with a milestone diff --git a/cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md b/cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md new file mode 100644 index 000000000..00622031d --- /dev/null +++ b/cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md @@ -0,0 +1,274 @@ +## è´¡çŒ®ä»£ç  + +欢迎加入 MMCV ç¤¾åŒºï¼Œæˆ‘ä»¬è‡´åŠ›äºŽæ‰“é€ æœ€å‰æ²¿çš„计算机视觉基础库,我们欢迎任何类型的贡献,包括但ä¸é™äºŽ + +**ä¿®å¤é”™è¯¯** + +ä¿®å¤ä»£ç å®žçŽ°é”™è¯¯çš„æ­¥éª¤å¦‚ä¸‹ï¼š + +1. 如果æäº¤çš„ä»£ç æ”¹åŠ¨è¾ƒå¤§ï¼Œå»ºè®®å…ˆæäº¤ issue,并正确æè¿° issue 的现象ã€åŽŸå› å’Œå¤çŽ°æ–¹å¼ï¼Œè®¨è®ºåŽç¡®è®¤ä¿®å¤æ–¹æ¡ˆã€‚ +2. ä¿®å¤é”™è¯¯å¹¶è¡¥å……相应的å•元测试,æäº¤æ‹‰å–请求。 + +**新增功能或组件** + +1. å¦‚æžœæ–°åŠŸèƒ½æˆ–æ¨¡å—æ¶‰åŠè¾ƒå¤§çš„ä»£ç æ”¹åŠ¨ï¼Œå»ºè®®å…ˆæäº¤ issueï¼Œç¡®è®¤åŠŸèƒ½çš„å¿…è¦æ€§ã€‚ +2. 实现新增功能并添å•元测试,æäº¤æ‹‰å–请求。 + +**文档补充** + +ä¿®å¤æ–‡æ¡£å¯ä»¥ç›´æŽ¥æäº¤æ‹‰å–请求 + +添加文档或将文档翻译æˆå…¶ä»–语言步骤如下 + +1. æäº¤ issueï¼Œç¡®è®¤æ·»åŠ æ–‡æ¡£çš„å¿…è¦æ€§ã€‚ +2. 添加文档,æäº¤æ‹‰å–请求。 + +### 拉å–è¯·æ±‚å·¥ä½œæµ + +如果你对拉å–请求ä¸äº†è§£ï¼Œæ²¡å…³ç³»ï¼ŒæŽ¥ä¸‹æ¥çš„内容将会从零开始,一步一步地指引你如何创建一个拉å–请求。如果你想深入了解拉å–è¯·æ±‚çš„å¼€å‘æ¨¡å¼ï¼Œå¯ä»¥å‚考 github [官方文档](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) + +#### 1. å¤åˆ»ä»“库 + +当你第一次æäº¤æ‹‰å–请求时,先å¤åˆ» OpenMMLab 原代ç åº“,点击 GitHub 页é¢å³ä¸Šè§’çš„ **Fork** 按钮,å¤åˆ»åŽçš„代ç åº“将会出现在你的 GitHub 个人主页下。 + + + +将代ç å…‹éš†åˆ°æœ¬åœ° + +```shell +git clone git@github.com:{username}/mmcv.git +``` + +添加原代ç åº“为上游代ç åº“ + +```bash +git remote add upstream git@github.com:open-mmlab/mmcv +``` + +检查 remote æ˜¯å¦æ·»åŠ æˆåŠŸï¼Œåœ¨ç»ˆç«¯è¾“å…¥ `git remote -v` + +```bash +origin git@github.com:{username}/mmcv.git (fetch) +origin git@github.com:{username}/mmcv.git (push) +upstream git@github.com:open-mmlab/mmcv (fetch) +upstream git@github.com:open-mmlab/mmcv (push) +``` + +> 这里对 origin å’Œ upstream 进行一个简å•的介ç»ï¼Œå½“我们使用 git clone æ¥å…‹éš†ä»£ç æ—¶ï¼Œä¼šé»˜è®¤åˆ›å»ºä¸€ä¸ª origin çš„ remoteï¼Œå®ƒæŒ‡å‘æˆ‘们克隆的代ç åº“地å€ï¼Œè€Œ upstream åˆ™æ˜¯æˆ‘ä»¬è‡ªå·±æ·»åŠ çš„ï¼Œç”¨æ¥æŒ‡å‘原始代ç åº“地å€ã€‚当然如果你ä¸å–œæ¬¢ä»–å« upstream,也å¯ä»¥è‡ªå·±ä¿®æ”¹ï¼Œæ¯”å¦‚å« open-mmlabã€‚æˆ‘ä»¬é€šå¸¸å‘ origin æäº¤ä»£ç ï¼ˆå³ fork 下æ¥çš„远程仓库),然åŽå‘ upstream æäº¤ä¸€ä¸ª pull request。如果æäº¤çš„代ç å’Œæœ€æ–°çš„代ç å‘生冲çªï¼Œå†ä»Ž upstream æ‹‰å–æœ€æ–°çš„代ç ï¼Œå’Œæœ¬åœ°åˆ†æ”¯è§£å†³å†²çªï¼Œå†æäº¤åˆ° origin。 + +#### 2. é…ç½® pre-commit + +在本地开å‘环境中,我们使用 [pre-commit](https://pre-commit.com/#intro) æ¥æ£€æŸ¥ä»£ç é£Žæ ¼ï¼Œä»¥ç¡®ä¿ä»£ç é£Žæ ¼çš„统一。在æäº¤ä»£ç ï¼Œéœ€è¦å…ˆå®‰è£… pre-commit(需è¦åœ¨ MMCV 目录下执行): + +```shell +pip install -U pre-commit +pre-commit install +``` + +检查 pre-commit 是å¦é…ç½®æˆåŠŸï¼Œå¹¶å®‰è£… `.pre-commit-config.yaml` 中的钩å­ï¼š + +```shell +pre-commit run --all-files +``` + + + + + +> 如果你是中国用户,由于网络原因,å¯èƒ½ä¼šå‡ºçŽ°å®‰è£…å¤±è´¥çš„æƒ…å†µï¼Œè¿™æ—¶å¯ä»¥ä½¿ç”¨å›½å†…æº + +> pre-commit install -c .pre-commit-config-zh-cn.yaml + +> pre-commit run --all-files -c .pre-commit-config-zh-cn.yaml + +如果安装过程被中断,å¯ä»¥é‡å¤æ‰§è¡Œ `pre-commit run ...` 继续安装。 + +如果æäº¤çš„代ç ä¸ç¬¦åˆä»£ç é£Žæ ¼è§„范,pre-commit 会å‘出警告,并自动修å¤éƒ¨åˆ†é”™è¯¯ã€‚ + + + +如果我们想临时绕开 pre-commit 的检查æäº¤ä¸€æ¬¡ä»£ç ï¼Œå¯ä»¥åœ¨ `git commit` 时加上 `--no-verify`(需è¦ä¿è¯æœ€å޿ލé€è‡³è¿œç¨‹ä»“库的代ç èƒ½å¤Ÿé€šè¿‡ pre-commit 检查)。 + +```shell +git commit -m "xxx" --no-verify +``` + +#### 3. 创建开å‘分支 + +安装完 pre-commit 之åŽï¼Œæˆ‘们需è¦åŸºäºŽ master 创建开å‘分支,建议的分支命å规则为 `username/pr_name`。 + +```shell +git checkout -b yhc/refactor_contributing_doc +``` + +在åŽç»­çš„å¼€å‘中,如果本地仓库的 master 分支è½åŽäºŽ upstream çš„ master 分支,我们需è¦å…ˆæ‹‰å– upstream 的代ç è¿›è¡ŒåŒæ­¥ï¼Œå†æ‰§è¡Œä¸Šé¢çš„命令 + +```shell +git pull upstream master +``` + +#### 4. æäº¤ä»£ç å¹¶åœ¨æœ¬åœ°é€šè¿‡å•元测试 + +- MMCV 引入了 mypy æ¥åšé™æ€ç±»åž‹æ£€æŸ¥ï¼Œä»¥å¢žåР代ç çš„鲿£’性。因此我们在æäº¤ä»£ç æ—¶ï¼Œéœ€è¦è¡¥å…… Type Hints。具体规则å¯ä»¥å‚考[教程](https://zhuanlan.zhihu.com/p/519335398)。 + +- æäº¤çš„代ç åŒæ ·éœ€è¦é€šè¿‡å•元测试 + + ```shell + # 通过全é‡å•元测试 + pytest tests + + # 我们需è¦ä¿è¯æäº¤çš„代ç èƒ½å¤Ÿé€šè¿‡ä¿®æ”¹æ¨¡å—çš„å•元测试,以 runner 为例 + pytest tests/test_runner/test_runner.py + ``` + + 如果你由于缺少ä¾èµ–无法è¿è¡Œä¿®æ”¹æ¨¡å—çš„å•元测试,å¯ä»¥å‚考[指引-å•元测试](#å•元测试) + +- 如果修改/添加了文档,å‚考[指引](#文档渲染)确认文档渲染正常。 + +#### 5. 推é€ä»£ç åˆ°è¿œç¨‹ + +代ç é€šè¿‡å•元测试和 pre-commit 检查åŽï¼Œå°†ä»£ç æŽ¨é€åˆ°è¿œç¨‹ä»“库,如果是第一次推é€ï¼Œå¯ä»¥åœ¨ `git push` åŽåŠ ä¸Š `-u` 傿•°ä»¥å…³è”远程分支 + +```shell +git push -u origin {branch_name} +``` + +这样下次就å¯ä»¥ç›´æŽ¥ä½¿ç”¨ `git push` 命令推é€ä»£ç äº†ï¼Œè€Œæ— éœ€æŒ‡å®šåˆ†æ”¯å’Œè¿œç¨‹ä»“库。 + +#### 6. æäº¤æ‹‰å–请求(PR) + +(1) 在 GitHub çš„ Pull request 界é¢åˆ›å»ºæ‹‰å–请求 + + +(2) æ ¹æ®æŒ‡å¼•修改 PR æè¿°ï¼Œä»¥ä¾¿äºŽå…¶ä»–å¼€å‘者更好地ç†è§£ä½ çš„修改 + + + +æè¿°è§„范详è§[拉å–请求规范](#拉å–请求规范) + +  + +**注æ„事项** + +(a) PR æè¿°åº”该包å«ä¿®æ”¹ç†ç”±ã€ä¿®æ”¹å†…容以åŠä¿®æ”¹åŽå¸¦æ¥çš„å½±å“,并关è”相关 Issue(具体方å¼è§[文档](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)) + +(b) 如果是第一次为 OpenMMLab åšè´¡çŒ®ï¼Œéœ€è¦ç­¾ç½² CLA + + + +(c) 检查æäº¤çš„ PR 是å¦é€šè¿‡ CIï¼ˆé›†æˆæµ‹è¯•) + + + +MMCV 会在ä¸åŒçš„å¹³å°ï¼ˆLinuxã€Windowã€Mac),基于ä¸åŒç‰ˆæœ¬çš„ Pythonã€PyTorchã€CUDA 对æäº¤çš„代ç è¿›è¡Œå•元测试,以ä¿è¯ä»£ç çš„æ­£ç¡®æ€§ï¼Œå¦‚果有任何一个没有通过,我们å¯ç‚¹å‡»ä¸Šå›¾ä¸­çš„ `Details` æ¥æŸ¥çœ‹å…·ä½“的测试信æ¯ï¼Œä»¥ä¾¿äºŽæˆ‘们修改代ç ã€‚ + +(3) 如果 PR 通过了 CI,那么就å¯ä»¥ç­‰å¾…å…¶ä»–å¼€å‘者的 reviewï¼Œå¹¶æ ¹æ® reviewer çš„æ„è§ï¼Œä¿®æ”¹ä»£ç ï¼Œå¹¶é‡å¤ [4](#4-æäº¤ä»£ç å¹¶æœ¬åœ°é€šè¿‡å•元测试)-[5](#5-推é€ä»£ç åˆ°è¿œç¨‹) 步骤,直到 reviewer åŒæ„åˆå…¥ PR。 + + + +所有 reviewer åŒæ„åˆå…¥ PR åŽï¼Œæˆ‘们会尽快将 PR åˆå¹¶åˆ°ä¸»åˆ†æ”¯ã€‚ + +#### 7. è§£å†³å†²çª + +éšç€æ—¶é—´çš„æŽ¨ç§»ï¼Œæˆ‘们的代ç åº“ä¼šä¸æ–­æ›´æ–°ï¼Œè¿™æ—¶å€™ï¼Œå¦‚果你的 PR 与主分支存在冲çªï¼Œä½ éœ€è¦è§£å†³å†²çªï¼Œè§£å†³å†²çªçš„æ–¹å¼æœ‰ä¸¤ç§ï¼š + +```shell +git fetch --all --prune +git rebase upstream/master +``` + +或者 + +```shell +git fetch --all --prune +git merge upstream/master +``` + +如果你éžå¸¸å–„于处ç†å†²çªï¼Œé‚£ä¹ˆå¯ä»¥ä½¿ç”¨ rebase çš„æ–¹å¼æ¥è§£å†³å†²çªï¼Œå› ä¸ºè¿™èƒ½å¤Ÿä¿è¯ä½ çš„ commit log 的整æ´ã€‚如果你ä¸å¤ªç†Ÿæ‚‰ `rebase` 的使用,那么å¯ä»¥ä½¿ç”¨ `merge` çš„æ–¹å¼æ¥è§£å†³å†²çªã€‚ + +### 指引 + +#### å•元测试 + +如果你无法正常执行部分模å—çš„å•元测试,例如 [video](https://github.com/open-mmlab/mmcv/tree/master/mmcv/video) 模å—,å¯èƒ½æ˜¯ä½ çš„当å‰çŽ¯å¢ƒæ²¡æœ‰å®‰è£…ä»¥ä¸‹ä¾èµ– + +```shell +# Linux +sudo apt-get update -y +sudo apt-get install -y libturbojpeg +sudo apt-get install -y ffmpeg + +# Windows +conda install ffmpeg +``` + +在æäº¤ä¿®å¤ä»£ç é”™è¯¯æˆ–新增特性的拉å–请求时,我们应该尽å¯èƒ½çš„让å•元测试覆盖所有æäº¤çš„代ç ï¼Œè®¡ç®—å•元测试覆盖率的方法如下 + +```shell +python -m coverage run -m pytest /path/to/test_file +python -m coverage html +# check file in htmlcov/index.html +``` + +#### 文档渲染 + +在æäº¤ä¿®å¤ä»£ç é”™è¯¯æˆ–新增特性的拉å–请求时,å¯èƒ½ä¼šéœ€è¦ä¿®æ”¹/新增模å—çš„ docstring。我们需è¦ç¡®è®¤æ¸²æŸ“åŽçš„æ–‡æ¡£æ ·å¼æ˜¯æ­£ç¡®çš„。 +æœ¬åœ°ç”Ÿæˆæ¸²æŸ“åŽçš„æ–‡æ¡£çš„æ–¹æ³•如下 + +```shell +pip install -r requirements/docs.txt +cd docs/zh_cn/ +# or docs/en +make html +# check file in ./docs/zh_cn/_build/html/index.html +``` + +### 代ç é£Žæ ¼ + +#### Python + +[PEP8](https://www.python.org/dev/peps/pep-0008/) 作为 OpenMMLab 算法库首选的代ç è§„范,我们使用以下工具检查和格å¼åŒ–ä»£ç  + +- [flake8](https://github.com/PyCQA/flake8): Python 官方å‘布的代ç è§„范检查工具,是多个检查工具的å°è£… +- [isort](https://github.com/timothycrosley/isort): 自动调整模å—导入顺åºçš„工具 +- [yapf](https://github.com/google/yapf): Google å‘布的代ç è§„范检查工具 +- [codespell](https://github.com/codespell-project/codespell): 检查å•è¯æ‹¼å†™æ˜¯å¦æœ‰è¯¯ +- [mdformat](https://github.com/executablebooks/mdformat): 检查 markdown 文件的工具 +- [docformatter](https://github.com/myint/docformatter): æ ¼å¼åŒ– docstring 的工具 + +yapf å’Œ isort çš„é…ç½®å¯ä»¥åœ¨ [setup.cfg](./setup.cfg) 找到 + +通过é…ç½® [pre-commit hook](https://pre-commit.com/) ,我们å¯ä»¥åœ¨æäº¤ä»£ç æ—¶è‡ªåŠ¨æ£€æŸ¥å’Œæ ¼å¼åŒ– `flake8`ã€`yapf`ã€`isort`ã€`trailing whitespaces`ã€`markdown files`, +ä¿®å¤ `end-of-files`ã€`double-quoted-strings`ã€`python-encoding-pragma`ã€`mixed-line-ending`,调整 `requirments.txt` 的包顺åºã€‚ +pre-commit é’©å­çš„é…ç½®å¯ä»¥åœ¨ [.pre-commit-config](./.pre-commit-config.yaml) 找到。 + +pre-commit 具体的安装使用方å¼è§[拉å–请求](#2-é…ç½®-pre-commit)。 + +更具体的规范请å‚考 [OpenMMLab 代ç è§„范](code_style.md)。 + +#### C++ and CUDA + +C++ å’Œ CUDA 的代ç è§„范éµä»Ž [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) + +### 拉å–请求规范 + +1. 使用 [pre-commit hook](https://pre-commit.com),尽é‡å‡å°‘代ç é£Žæ ¼ç›¸å…³é—®é¢˜ + +2. 一个`拉å–请求`对应一个短期分支 + +3. 粒度è¦ç»†ï¼Œä¸€ä¸ª`拉å–请求`åªåšä¸€ä»¶äº‹æƒ…,é¿å…超大的`拉å–请求` + + - Bad:实现 Faster R-CNN + - Acceptable:给 Faster R-CNN 添加一个 box head + - Good:给 box head å¢žåŠ ä¸€ä¸ªå‚æ•°æ¥æ”¯æŒè‡ªå®šä¹‰çš„ conv 层数 + +4. æ¯æ¬¡ Commit æ—¶éœ€è¦æä¾›æ¸…æ™°ä¸”æœ‰æ„义 commit ä¿¡æ¯ + +5. æä¾›æ¸…晰且有æ„义的`拉å–请求`æè¿° + + - 标题写明白任务å称,一般格å¼:\[Prefix\] Short description of the pull request (Suffix) + - prefix: 新增功能 \[Feature\], ä¿® bug \[Fix\], 文档相关 \[Docs\], å¼€å‘中 \[WIP\] (暂时ä¸ä¼šè¢«review) + - æè¿°é‡Œä»‹ç»`拉å–请求`的主è¦ä¿®æ”¹å†…容,结果,以åŠå¯¹å…¶ä»–部分的影å“, å‚考`拉å–请求`æ¨¡æ¿ + - å…³è”相关的`议题` (issue) 和其他`拉å–请求` + +6. 如果引入了其他三方库,或借鉴了三方库的代ç ï¼Œè¯·ç¡®è®¤ä»–们的许å¯è¯å’Œ mmcv 兼容,并在借鉴的代ç ä¸Šè¡¥å…… `This code is inspired from http://` diff --git a/cv/distiller/CWD/mmcv/Jenkinsfile b/cv/distiller/CWD/mmcv/Jenkinsfile new file mode 100644 index 000000000..f0c19d9f3 --- /dev/null +++ b/cv/distiller/CWD/mmcv/Jenkinsfile @@ -0,0 +1,56 @@ +def docker_images = ["registry.cn-hangzhou.aliyuncs.com/sensetime/openmmlab:cuda10.1-cudnn7-devel-ubuntu18.04-py37-pt1.3", + "registry.cn-hangzhou.aliyuncs.com/sensetime/openmmlab:cuda10.2-cudnn7-devel-ubuntu18.04-py37-pt1.5"] +def torch_versions = ["1.3.0", "1.5.0"] +def torchvision_versions = ["0.4.2", "0.6.0"] + + +def get_stages(docker_image, folder) { + def pip_mirror = "-i https://mirrors.aliyun.com/pypi/simple" + stages = { + docker.image(docker_image).inside('-u root --gpus all --net host') { + sh "rm -rf ${env.WORKSPACE}-${folder} ${env.WORKSPACE}-${folder}@tmp" + sh "cp -r ${env.WORKSPACE} ${env.WORKSPACE}-${folder}" + try { + dir("${env.WORKSPACE}-${folder}") { + stage("before_install") { + sh "apt-get update && apt-get install -y ninja-build" + } + stage("dependencies") { + // torch and torchvision are pre-installed in dockers + sh "pip list | grep torch" + sh "apt-get install -y ffmpeg libturbojpeg" + sh "pip install pytest coverage lmdb PyTurboJPEG Cython ${pip_mirror}" + } + stage("build") { + sh "MMCV_WITH_OPS=1 pip install -e . ${pip_mirror}" + } + stage("test") { + sh "coverage run --branch --source=mmcv -m pytest tests/" + sh "coverage xml" + sh "coverage report -m" + } + } + } finally { + sh "rm -rf ${env.WORKSPACE}-${folder} ${env.WORKSPACE}-${folder}@tmp" + } + } + } + return stages +} + + +node('master') { + // fetch latest change from SCM (Source Control Management) + checkout scm + + def stages = [:] + for (int i = 0; i < docker_images.size(); i++) { + def docker_image = docker_images[i] + def torch = torch_versions[i] + def torchvision = torchvision_versions[i] + def tag = docker_image + '_' + torch + '_' + torchvision + def folder = "${i}" + stages[tag] = get_stages(docker_image, folder) + } + parallel stages +} diff --git a/cv/distiller/CWD/mmcv/LICENSE b/cv/distiller/CWD/mmcv/LICENSE new file mode 100644 index 000000000..f02314255 --- /dev/null +++ b/cv/distiller/CWD/mmcv/LICENSE @@ -0,0 +1,203 @@ +Copyright (c) OpenMMLab. All rights reserved + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018-2020 Open-MMLab. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/cv/distiller/CWD/mmcv/LICENSES.md b/cv/distiller/CWD/mmcv/LICENSES.md new file mode 100644 index 000000000..5de835833 --- /dev/null +++ b/cv/distiller/CWD/mmcv/LICENSES.md @@ -0,0 +1,8 @@ +# Licenses for special operations + +In this file, we list the operations with other licenses instead of Apache 2.0. Users should be careful about adopting these operations in any commercial matters. + +| Operation | Files | License | +| :--------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------: | +| upfirdn2d | [mmcv/ops/csrc/pytorch/cuda/upfirdn2d_kernel.cu](https://github.com/open-mmlab/mmcv/blob/master/mmcv/ops/csrc/pytorch/cuda/upfirdn2d_kernel.cu) | NVIDIA License | +| fused_leaky_relu | [mmcv/ops/csrc/pytorch/cuda/fused_bias_leakyrelu_cuda.cu](https://github.com/open-mmlab/mmcv/blob/master/mmcv/ops/csrc/pytorch/cuda/fused_bias_leakyrelu_cuda.cu) | NVIDIA License | diff --git a/cv/distiller/CWD/mmcv/MANIFEST.in b/cv/distiller/CWD/mmcv/MANIFEST.in new file mode 100644 index 000000000..622635caa --- /dev/null +++ b/cv/distiller/CWD/mmcv/MANIFEST.in @@ -0,0 +1,6 @@ +include requirements/runtime.txt +include mmcv/ops/csrc/common/cuda/*.cuh mmcv/ops/csrc/common/cuda/*.hpp mmcv/ops/csrc/common/*.hpp +include mmcv/ops/csrc/pytorch/*.cpp mmcv/ops/csrc/pytorch/cuda/*.cu mmcv/ops/csrc/pytorch/cuda/*.cpp mmcv/ops/csrc/pytorch/cpu/*.cpp +include mmcv/ops/csrc/parrots/*.h mmcv/ops/csrc/parrots/*.cpp +include mmcv/ops/csrc/pytorch/mps/*.mm mmcv/ops/csrc/common/mps/*.h mmcv/ops/csrc/common/mps/*.mm +recursive-include mmcv/ops/csrc/ *.h *.hpp *.cpp *.cuh *.cu *.mm diff --git a/cv/distiller/CWD/mmcv/README.md b/cv/distiller/CWD/mmcv/README.md new file mode 100644 index 000000000..25d290f3d --- /dev/null +++ b/cv/distiller/CWD/mmcv/README.md @@ -0,0 +1,161 @@ +
+ +
 
+
+ OpenMMLab website + + + HOT + + +      + OpenMMLab platform + + + TRY IT OUT + + +
+
 
+
+ +[![docs](https://img.shields.io/badge/docs-2.x-blue)](https://mmcv.readthedocs.io/en/2.x/) +[![platform](https://img.shields.io/badge/platform-Linux%7CWindows%7CmacOS-blue)](https://mmcv.readthedocs.io/en/2.x/get_started/installation.html) +[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/mmcv)](https://pypi.org/project/mmcv/) +[![pytorch](https://img.shields.io/badge/pytorch-1.6~1.13-orange)](https://pytorch.org/get-started/previous-versions/) +[![cuda](https://img.shields.io/badge/cuda-9.2~11.7-green)](https://developer.nvidia.com/cuda-downloads) +[![PyPI](https://img.shields.io/pypi/v/mmcv)](https://pypi.org/project/mmcv) +[![badge](https://github.com/open-mmlab/mmcv/workflows/build/badge.svg)](https://github.com/open-mmlab/mmcv/actions) +[![codecov](https://codecov.io/gh/open-mmlab/mmcv/branch/master/graph/badge.svg)](https://codecov.io/gh/open-mmlab/mmcv) +[![license](https://img.shields.io/github/license/open-mmlab/mmcv.svg)](https://github.com/open-mmlab/mmcv/blob/master/LICENSE) + +English | [简体中文](README_zh-CN.md) + +## Introduction + +MMCV is a foundational library for computer vision research and it provides the following functionalities: + +- [Image/Video processing](https://mmcv.readthedocs.io/en/2.x/understand_mmcv/data_process.html) +- [Image and annotation visualization](https://mmcv.readthedocs.io/en/2.x/understand_mmcv/visualization.html) +- [Image transformation](https://mmcv.readthedocs.io/en/2.x/understand_mmcv/data_transform.html) +- [Various CNN architectures](https://mmcv.readthedocs.io/en/2.x/understand_mmcv/cnn.html) +- [High-quality implementation of common CPU and CUDA ops](https://mmcv.readthedocs.io/en/2.x/understand_mmcv/ops.html) + +It supports the following systems: + +- Linux +- Windows +- macOS + +See the [documentation](http://mmcv.readthedocs.io/en/2.x) for more features and usage. + +Note: MMCV requires Python 3.7+. + +## Installation + +There are two versions of MMCV: + +- **mmcv**: comprehensive, with full features and various CUDA ops out of the box. It takes longer time to build. +- **mmcv-lite**: lite, without CUDA ops but all other features, similar to mmcv\<1.0.0. It is useful when you do not need those CUDA ops. + +**Note**: Do not install both versions in the same environment, otherwise you may encounter errors like `ModuleNotFound`. You need to uninstall one before installing the other. `Installing the full version is highly recommended if CUDA is available`. + +### Install mmcv + +Before installing mmcv, make sure that PyTorch has been successfully installed following the [PyTorch official installation guide](https://github.com/pytorch/pytorch#installation). For apple silicon users, please use PyTorch 1.13+. + +The command to install mmcv: + +```bash +pip install -U openmim +mim install "mmcv>=2.0.0rc1" +``` + +If you need to specify the version of mmcv, you can use the following command: + +```bash +mim install mmcv==2.0.0rc3 +``` + +If you find that the above installation command does not use a pre-built package ending with `.whl` but a source package ending with `.tar.gz`, you may not have a pre-build package corresponding to the PyTorch or CUDA or mmcv version, in which case you can [build mmcv from source](https://mmcv.readthedocs.io/en/2.x/get_started/build.html). + +
+Installation log using pre-built packages + +Looking in links: https://download.openmmlab.com/mmcv/dist/cu102/torch1.8.0/index.html
+Collecting mmcv
+Downloading https://download.openmmlab.com/mmcv/dist/cu102/torch1.8.0/mmcv-2.0.0rc3-cp38-cp38-manylinux1_x86_64.whl + +
+ +
+Installation log using source packages + +Looking in links: https://download.openmmlab.com/mmcv/dist/cu102/torch1.8.0/index.html
+Collecting mmcv==2.0.0rc3
+Downloading mmcv-2.0.0rc3.tar.gz + +
+ +For more installation methods, please refer to the [Installation documentation](https://mmcv.readthedocs.io/en/2.x/get_started/installation.html). + +### Install mmcv-lite + +If you need to use PyTorch-related modules, make sure PyTorch has been successfully installed in your environment by referring to the [PyTorch official installation guide](https://github.com/pytorch/pytorch#installation). + +```bash +pip install -U openmim +mim install "mmcv-lite>=2.0.0rc1" +``` + +## FAQ + +If you face some installation issues, CUDA related issues or RuntimeErrors, +you may first refer to this [Frequently Asked Questions](https://mmcv.readthedocs.io/en/2.x/faq.html). + +If you face installation problems or runtime issues, you may first refer to this [Frequently Asked Questions](https://mmcv.readthedocs.io/en/2.x/faq.html) to see if there is a solution. If the problem is still not solved, feel free to open an [issue](https://github.com/open-mmlab/mmcv/issues). + +## Citation + +If you find this project useful in your research, please consider cite: + +```latex +@misc{mmcv, + title={{MMCV: OpenMMLab} Computer Vision Foundation}, + author={MMCV Contributors}, + howpublished = {\url{https://github.com/open-mmlab/mmcv}}, + year={2018} +} +``` + +## Contributing + +We appreciate all contributions to improve MMCV. Please refer to [CONTRIBUTING.md](CONTRIBUTING.md) for the contributing guideline. + +## License + +MMCV is released under the Apache 2.0 license, while some specific operations in this library are with other licenses. Please refer to [LICENSES.md](LICENSES.md) for the careful check, if you are using our code for commercial matters. + +## Projects in OpenMMLab + +- [MMEngine](https://github.com/open-mmlab/mmengine): OpenMMLab foundational library for training deep learning models. +- [MMCV](https://github.com/open-mmlab/mmcv): OpenMMLab foundational library for computer vision. +- [MIM](https://github.com/open-mmlab/mim): MIM installs OpenMMLab packages. +- [MMClassification](https://github.com/open-mmlab/mmclassification): OpenMMLab image classification toolbox and benchmark. +- [MMDetection](https://github.com/open-mmlab/mmdetection): OpenMMLab detection toolbox and benchmark. +- [MMDetection3D](https://github.com/open-mmlab/mmdetection3d): OpenMMLab's next-generation platform for general 3D object detection. +- [MMRotate](https://github.com/open-mmlab/mmrotate): OpenMMLab rotated object detection toolbox and benchmark. +- [MMYOLO](https://github.com/open-mmlab/mmyolo): OpenMMLab YOLO series toolbox and benchmark. +- [MMSegmentation](https://github.com/open-mmlab/mmsegmentation): OpenMMLab semantic segmentation toolbox and benchmark. +- [MMOCR](https://github.com/open-mmlab/mmocr): OpenMMLab text detection, recognition, and understanding toolbox. +- [MMPose](https://github.com/open-mmlab/mmpose): OpenMMLab pose estimation toolbox and benchmark. +- [MMHuman3D](https://github.com/open-mmlab/mmhuman3d): OpenMMLab 3D human parametric model toolbox and benchmark. +- [MMSelfSup](https://github.com/open-mmlab/mmselfsup): OpenMMLab self-supervised learning toolbox and benchmark. +- [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab model compression toolbox and benchmark. +- [MMFewShot](https://github.com/open-mmlab/mmfewshot): OpenMMLab fewshot learning toolbox and benchmark. +- [MMAction2](https://github.com/open-mmlab/mmaction2): OpenMMLab's next-generation action understanding toolbox and benchmark. +- [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab video perception toolbox and benchmark. +- [MMFlow](https://github.com/open-mmlab/mmflow): OpenMMLab optical flow toolbox and benchmark. +- [MMEditing](https://github.com/open-mmlab/mmediting): OpenMMLab image and video editing toolbox. +- [MMGeneration](https://github.com/open-mmlab/mmgeneration): OpenMMLab image and video generative models toolbox. +- [MMDeploy](https://github.com/open-mmlab/mmdeploy): OpenMMLab model deployment framework. diff --git a/cv/distiller/CWD/mmcv/README_zh-CN.md b/cv/distiller/CWD/mmcv/README_zh-CN.md new file mode 100644 index 000000000..d9a81ebf5 --- /dev/null +++ b/cv/distiller/CWD/mmcv/README_zh-CN.md @@ -0,0 +1,164 @@ +
+ +
 
+
+ OpenMMLab 官网 + + + HOT + + +      + OpenMMLab å¼€æ”¾å¹³å° + + + TRY IT OUT + + +
+
 
+
+ +[![docs](https://img.shields.io/badge/docs-2.x-blue)](https://mmcv.readthedocs.io/zh_CN/2.x/) +[![platform](https://img.shields.io/badge/platform-Linux%7CWindows%7CmacOS-blue)](https://mmcv.readthedocs.io/zh_CN/2.x/get_started/installation.html) +[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/mmcv)](https://pypi.org/project/mmcv/) +[![pytorch](https://img.shields.io/badge/pytorch-1.6~1.13-orange)](https://pytorch.org/get-started/previous-versions/) +[![cuda](https://img.shields.io/badge/cuda-9.2~11.7-green)](https://developer.nvidia.com/cuda-downloads) +[![PyPI](https://img.shields.io/pypi/v/mmcv)](https://pypi.org/project/mmcv) +[![badge](https://github.com/open-mmlab/mmcv/workflows/build/badge.svg)](https://github.com/open-mmlab/mmcv/actions) +[![codecov](https://codecov.io/gh/open-mmlab/mmcv/branch/master/graph/badge.svg)](https://codecov.io/gh/open-mmlab/mmcv) +[![license](https://img.shields.io/github/license/open-mmlab/mmcv.svg)](https://github.com/open-mmlab/mmcv/blob/master/LICENSE) + +[English](README.md) | 简体中文 + +## 简介 + +MMCV 是一个é¢å‘计算机视觉的基础库,它æä¾›äº†ä»¥ä¸‹åŠŸèƒ½ï¼š + +- [图åƒå’Œè§†é¢‘处ç†](https://mmcv.readthedocs.io/zh_CN/2.x/understand_mmcv/data_process.html) +- [图åƒå’Œæ ‡æ³¨ç»“æžœå¯è§†åŒ–](https://mmcv.readthedocs.io/zh_CN/2.x/understand_mmcv/visualization.html) +- [图åƒå˜æ¢](https://mmcv.readthedocs.io/zh_CN/2.x/understand_mmcv/data_transform.html) +- [å¤šç§ CNN 网络结构](https://mmcv.readthedocs.io/zh_CN/2.x/understand_mmcv/cnn.html) +- [高质é‡å®žçŽ°çš„å¸¸è§ CUDA ç®—å­](https://mmcv.readthedocs.io/zh_CN/2.x/understand_mmcv/ops.html) + +MMCV 支æŒå¤šç§å¹³å°ï¼ŒåŒ…括: + +- Linux +- Windows +- macOS + +如想了解更多特性和使用,请å‚考[文档](http://mmcv.readthedocs.io/zh_CN/2.x)。 + +æç¤º: MMCV éœ€è¦ Python 3.7 以上版本。 + +## 安装 + +MMCV 有两个版本: + +- **mmcv**: å®Œæ•´ç‰ˆï¼ŒåŒ…å«æ‰€æœ‰çš„特性以åŠä¸°å¯Œçš„开箱å³ç”¨çš„ CUDA ç®—å­ã€‚注æ„完整版本å¯èƒ½éœ€è¦æ›´é•¿æ—¶é—´æ¥ç¼–译。 +- **mmcv-lite**: 精简版,ä¸åŒ…å« CUDA ç®—å­ä½†åŒ…å«å…¶ä½™æ‰€æœ‰ç‰¹æ€§å’ŒåŠŸèƒ½ï¼Œç±»ä¼¼ MMCV 1.0 之å‰çš„版本。如果你ä¸éœ€è¦ä½¿ç”¨ CUDA ç®—å­çš„è¯ï¼Œç²¾ç®€ç‰ˆå¯ä»¥ä½œä¸ºä¸€ä¸ªè€ƒè™‘选项。 + +**注æ„**: 请ä¸è¦åœ¨åŒä¸€ä¸ªçŽ¯å¢ƒä¸­å®‰è£…ä¸¤ä¸ªç‰ˆæœ¬ï¼Œå¦åˆ™å¯èƒ½ä¼šé‡åˆ°ç±»ä¼¼ `ModuleNotFound` 的错误。在安装一个版本之å‰ï¼Œéœ€è¦å…ˆå¸è½½å¦ä¸€ä¸ªã€‚`如果 CUDA å¯ç”¨ï¼Œå¼ºçƒˆæŽ¨è安装 mmcv`。 + +### 安装 mmcv + +在安装 mmcv 之å‰ï¼Œè¯·ç¡®ä¿ PyTorch å·²ç»æˆåŠŸå®‰è£…åœ¨çŽ¯å¢ƒä¸­ï¼Œå¯ä»¥å‚考 [PyTorch 官方安装文档](https://github.com/pytorch/pytorch#installation)。如果你使用的是æ­è½½ apple silicon çš„ mac 设备,请安装 PyTorch 1.13+ 的版本。 + +安装 mmcv 的命令如下: + +```bash +pip install -U openmim +mim install "mmcv>=2.0.0rc1" +``` + +å¦‚æžœéœ€è¦æŒ‡å®š mmcv 的版本,å¯ä»¥ä½¿ç”¨ä»¥ä¸‹å‘½ä»¤ + +```bash +mim install mmcv==2.0.0rc3 +``` + +如果å‘现上述的安装命令没有使用预编译包(以 `.whl` 结尾)而是使用æºç åŒ…(以 `.tar.gz` 结尾)安装,则有å¯èƒ½æ˜¯æˆ‘们没有æä¾›å’Œå½“å‰çŽ¯å¢ƒçš„ PyTorch 版本ã€CUDA 版本相匹é…çš„ mmcv 预编译包,此时,你å¯ä»¥[æºç å®‰è£… mmcv](https://mmcv.readthedocs.io/zh_CN/2.x/get_started/build.html)。 + +
+使用预编译包的安装日志 + +Looking in links: https://download.openmmlab.com/mmcv/dist/cu102/torch1.8.0/index.html
+Collecting mmcv
+Downloading https://download.openmmlab.com/mmcv/dist/cu102/torch1.8.0/mmcv-2.0.0rc3-cp38-cp38-manylinux1_x86_64.whl + +
+ +
+使用æºç åŒ…的安装日志 + +Looking in links: https://download.openmmlab.com/mmcv/dist/cu102/torch1.8.0/index.html
+Collecting mmcv==2.0.0rc3
+Downloading mmcv-2.0.0rc3.tar.gz + +
+ +更多安装方å¼è¯·å‚考[安装文档](https://mmcv.readthedocs.io/zh_CN/2.x/get_started/installation.html)。 + +### 安装 mmcv-lite + +如果你需è¦ä½¿ç”¨å’Œ PyTorch 相关的模å—ï¼Œè¯·ç¡®ä¿ PyTorch å·²ç»æˆåŠŸå®‰è£…åœ¨çŽ¯å¢ƒä¸­ï¼Œå¯ä»¥å‚考 [PyTorch 官方安装文档](https://github.com/pytorch/pytorch#installation)。 + +```bash +pip install -U openmim +mim install "mmcv-lite>=2.0.0rc1" +``` + +## FAQ + +如果你é‡åˆ°äº†å®‰è£…问题或者è¿è¡Œæ—¶é—®é¢˜ï¼Œè¯·æŸ¥çœ‹[问题解决页é¢](https://mmcv.readthedocs.io/zh_CN/2.x/faq.html)是å¦å·²æœ‰è§£å†³æ–¹æ¡ˆã€‚如果问题ä»ç„¶æ²¡æœ‰è§£å†³ï¼Œæ¬¢è¿Žæ [issue](https://github.com/open-mmlab/mmcv/issues)。 + +## è´¡çŒ®æŒ‡å— + +我们感谢所有的贡献者为改进和æå‡ MMCV 所作出的努力。请å‚考[贡献指å—](CONTRIBUTING.md)æ¥äº†è§£å‚与项目贡献的相关指引。 + +## 许å¯è¯ + +`MMCV` ç›®å‰ä»¥ Apache 2.0 的许å¯è¯å‘å¸ƒï¼Œä½†æ˜¯å…¶ä¸­æœ‰ä¸€éƒ¨åˆ†åŠŸèƒ½å¹¶ä¸æ˜¯ä½¿ç”¨çš„ Apache2.0 许å¯è¯ï¼Œæˆ‘们在 [许å¯è¯](LICENSES.md) 中详细地列出了这些功能以åŠä»–们对应的许å¯è¯ï¼Œå¦‚果您正在从事盈利性活动,请谨慎å‚考此文档。 + +## OpenMMLab 的其他项目 + +- [MMEngine](https://github.com/open-mmlab/mmengine): OpenMMLab 深度学习模型训练基础库 +- [MMCV](https://github.com/open-mmlab/mmcv): OpenMMLab 计算机视觉基础库 +- [MIM](https://github.com/open-mmlab/mim): MIM 是 OpenMMlab 项目ã€ç®—æ³•ã€æ¨¡åž‹çš„ç»Ÿä¸€å…¥å£ +- [MMClassification](https://github.com/open-mmlab/mmclassification): OpenMMLab 图åƒåˆ†ç±»å·¥å…·ç®± +- [MMDetection](https://github.com/open-mmlab/mmdetection): OpenMMLab 目标检测工具箱 +- [MMDetection3D](https://github.com/open-mmlab/mmdetection3d): OpenMMLab 新一代通用 3D ç›®æ ‡æ£€æµ‹å¹³å° +- [MMRotate](https://github.com/open-mmlab/mmrotate): OpenMMLab 旋转框检测工具箱与测试基准 +- [MMYOLO](https://github.com/open-mmlab/mmyolo): OpenMMLab YOLO 系列工具箱与测试基准 +- [MMSegmentation](https://github.com/open-mmlab/mmsegmentation): OpenMMLab 语义分割工具箱 +- [MMOCR](https://github.com/open-mmlab/mmocr): OpenMMLab å…¨æµç¨‹æ–‡å­—检测识别ç†è§£å·¥å…·ç®± +- [MMPose](https://github.com/open-mmlab/mmpose): OpenMMLab å§¿æ€ä¼°è®¡å·¥å…·ç®± +- [MMHuman3D](https://github.com/open-mmlab/mmhuman3d): OpenMMLab äººä½“å‚æ•°åŒ–模型工具箱与测试基准 +- [MMSelfSup](https://github.com/open-mmlab/mmselfsup): OpenMMLab 自监ç£å­¦ä¹ å·¥å…·ç®±ä¸Žæµ‹è¯•基准 +- [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab 模型压缩工具箱与测试基准 +- [MMFewShot](https://github.com/open-mmlab/mmfewshot): OpenMMLab 少样本学习工具箱与测试基准 +- [MMAction2](https://github.com/open-mmlab/mmaction2): OpenMMLab 新一代视频ç†è§£å·¥å…·ç®± +- [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab ä¸€ä½“åŒ–è§†é¢‘ç›®æ ‡æ„ŸçŸ¥å¹³å° +- [MMFlow](https://github.com/open-mmlab/mmflow): OpenMMLab å…‰æµä¼°è®¡å·¥å…·ç®±ä¸Žæµ‹è¯•基准 +- [MMEditing](https://github.com/open-mmlab/mmediting): OpenMMLab 图åƒè§†é¢‘编辑工具箱 +- [MMGeneration](https://github.com/open-mmlab/mmgeneration): OpenMMLab å›¾ç‰‡è§†é¢‘ç”Ÿæˆæ¨¡åž‹å·¥å…·ç®± +- [MMDeploy](https://github.com/open-mmlab/mmdeploy): OpenMMLab 模型部署框架 + +## 欢迎加入 OpenMMLab 社区 + +扫æä¸‹æ–¹çš„二维ç å¯å…³æ³¨ OpenMMLab 团队的 [知乎官方账å·](https://www.zhihu.com/people/openmmlab),加入 OpenMMLab 团队的 [å®˜æ–¹äº¤æµ QQ 群](https://jq.qq.com/?_wv=1027&k=K0QI8ByU),或添加微信å°åŠ©æ‰‹â€OpenMMLabwx“加入官方交æµå¾®ä¿¡ç¾¤ã€‚ + +
+ +
+ +我们会在 OpenMMLab 社区为大家 + +- 📢 分享 AI æ¡†æž¶çš„å‰æ²¿æ ¸å¿ƒæŠ€æœ¯ +- 💻 解读 PyTorch å¸¸ç”¨æ¨¡å—æºç  +- 📰 å‘布 OpenMMLab 的相关新闻 +- 🚀 ä»‹ç» OpenMMLab å¼€å‘çš„å‰æ²¿ç®—法 +- ðŸƒ èŽ·å–æ›´é«˜æ•ˆçš„问题答疑和æ„è§å馈 +- 🔥 æä¾›ä¸Žå„行å„业开å‘者充分交æµçš„å¹³å° + +干货满满 ðŸ“˜ï¼Œç­‰ä½ æ¥æ’© 💗,OpenMMLab 社区期待您的加入 👬 diff --git a/cv/distiller/CWD/mmcv/TERMINOLOGY.md b/cv/distiller/CWD/mmcv/TERMINOLOGY.md new file mode 100644 index 000000000..07411b777 --- /dev/null +++ b/cv/distiller/CWD/mmcv/TERMINOLOGY.md @@ -0,0 +1,30 @@ +# English-Chinese terminology comparison (英汉术语对照) + +This document is used as a reference for English-Chinese terminology translation. + +该文档用作中英文翻译对照å‚考。 + +| English | 中文 | +| :---------------: | :----------: | +| annotation | 标注 | +| backbone | 主干网络 | +| benchmark | 基准测试 | +| checkpoint | 模型æƒé‡æ–‡ä»¶ | +| classifier | 分类器 | +| cls_head | 分类头 | +| decoder | è§£ç å™¨ | +| detector | 检测器 | +| encoder | ç¼–ç å™¨ | +| finetune | 微调 | +| ground truth | 真实标签 | +| hook | é’©å­ | +| localizer | 定ä½å™¨ | +| neck | 模型颈部 | +| pipeline | æµæ°´çº¿ | +| recognizer | 识别器 | +| register | 注册器 | +| schedule | 调整 | +| scheduler | 调度器 | +| segmentor | 分割器 | +| tensor | å¼ é‡ | +| training schedule | 训练策略 | diff --git a/cv/distiller/CWD/mmcv/build_mmcv.sh b/cv/distiller/CWD/mmcv/build_mmcv.sh new file mode 100644 index 000000000..6a40dda04 --- /dev/null +++ b/cv/distiller/CWD/mmcv/build_mmcv.sh @@ -0,0 +1,26 @@ + + + + +#!/bin/bash + +COREX_VERSION=${COREX_VERSION:-latest} +MAX_JOBS=${MAX_JOBS:-$(nproc --all)} +PYTHON_PATH=$(which python3) +${PYTHON_PATH} -m pip list | grep "^torch .*+corex" || { + echo "ERROR: building mmcv requries the corex torch has been installed." + exit 1 +} + +export MAX_JOBS=${MAX_JOBS} + +FORCE_CUDA=1 MMCV_WITH_OPS=1 ${PYTHON_PATH} setup.py build 2>&1 | tee compile.log; [[ ${PIPESTATUS[0]} == 0 ]] || exit + +if [[ "${COREX_VERSION}" == "latest" ]]; then + COREX_VERSION=`date --utc +%Y%m%d%H%M%S` +fi +export MMCV_LOCAL_VERSION_IDENTIFIER="corex.${COREX_VERSION}" +FORCE_CUDA=1 MMCV_WITH_OPS=1 ${PYTHON_PATH} setup.py bdist_wheel -d build_pip || exit + +# Return 0 status if all finished +exit 0 diff --git a/cv/distiller/CWD/mmcv/clean_mmcv.sh b/cv/distiller/CWD/mmcv/clean_mmcv.sh new file mode 100644 index 000000000..afe4df7bb --- /dev/null +++ b/cv/distiller/CWD/mmcv/clean_mmcv.sh @@ -0,0 +1,14 @@ + + + + +#!/bin/bash + +PYTHON_PATH=$(which python3) + +rm -rf build +${PYTHON_PATH} setup.py clean || true +rm -rf build_pip + +# Return 0 status if all finished +exit 0 diff --git a/cv/distiller/CWD/mmcv/compile.log b/cv/distiller/CWD/mmcv/compile.log new file mode 100644 index 000000000..a35e8435b --- /dev/null +++ b/cv/distiller/CWD/mmcv/compile.log @@ -0,0 +1,229 @@ +running build +running build_py +running egg_info +writing mmcv.egg-info/PKG-INFO +writing dependency_links to mmcv.egg-info/dependency_links.txt +writing requirements to mmcv.egg-info/requires.txt +writing top-level names to mmcv.egg-info/top_level.txt +reading manifest file 'mmcv.egg-info/SOURCES.txt' +reading manifest template 'MANIFEST.in' +warning: no files found matching 'mmcv/ops/csrc/parrots/*.h' +warning: no files found matching 'mmcv/ops/csrc/parrots/*.cpp' +warning: no files found matching 'mmcv/ops/csrc/pytorch/mps/*.mm' +warning: no files found matching 'mmcv/ops/csrc/common/mps/*.h' +warning: no files found matching 'mmcv/ops/csrc/common/mps/*.mm' +warning: no files found matching '*.h' under directory 'mmcv/ops/csrc/' +warning: no files found matching '*.mm' under directory 'mmcv/ops/csrc/' +adding license file 'LICENSE' +adding license file 'LICENSES.md' +writing manifest file 'mmcv.egg-info/SOURCES.txt' +copying mmcv/ops/csrc/pytorch/pybind.cpp -> build/lib.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch +copying mmcv/ops/csrc/pytorch/cuda/cudabind.cpp -> build/lib.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch/cuda +running build_ext +building 'mmcv._ext' extension +/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.common' as data is deprecated, please list it in `packages`. + !! + + + ############################ + # Package would be ignored # + ############################ + Python recognizes 'mmcv.ops.csrc.common' as an importable package, + but it is not listed in the `packages` configuration of setuptools. + + 'mmcv.ops.csrc.common' has been automatically added to the distribution only + because it may contain data files, but this behavior is likely to change + in future versions of setuptools (and therefore is considered deprecated). + + Please make sure that 'mmcv.ops.csrc.common' is included as a package by using + the `packages` configuration field or the proper discovery methods + (for example by using `find_namespace_packages(...)`/`find_namespace:` + instead of `find_packages(...)`/`find:`). + + You can read more about "package discovery" and "data files" on setuptools + documentation page. + + +!! + + check.warn(importable) +/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.common.cuda' as data is deprecated, please list it in `packages`. + !! + + + ############################ + # Package would be ignored # + ############################ + Python recognizes 'mmcv.ops.csrc.common.cuda' as an importable package, + but it is not listed in the `packages` configuration of setuptools. + + 'mmcv.ops.csrc.common.cuda' has been automatically added to the distribution only + because it may contain data files, but this behavior is likely to change + in future versions of setuptools (and therefore is considered deprecated). + + Please make sure that 'mmcv.ops.csrc.common.cuda' is included as a package by using + the `packages` configuration field or the proper discovery methods + (for example by using `find_namespace_packages(...)`/`find_namespace:` + instead of `find_packages(...)`/`find:`). + + You can read more about "package discovery" and "data files" on setuptools + documentation page. + + +!! + + check.warn(importable) +/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.common.mlu' as data is deprecated, please list it in `packages`. + !! + + + ############################ + # Package would be ignored # + ############################ + Python recognizes 'mmcv.ops.csrc.common.mlu' as an importable package, + but it is not listed in the `packages` configuration of setuptools. + + 'mmcv.ops.csrc.common.mlu' has been automatically added to the distribution only + because it may contain data files, but this behavior is likely to change + in future versions of setuptools (and therefore is considered deprecated). + + Please make sure that 'mmcv.ops.csrc.common.mlu' is included as a package by using + the `packages` configuration field or the proper discovery methods + (for example by using `find_namespace_packages(...)`/`find_namespace:` + instead of `find_packages(...)`/`find:`). + + You can read more about "package discovery" and "data files" on setuptools + documentation page. + + +!! + + check.warn(importable) +/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.pytorch' as data is deprecated, please list it in `packages`. + !! + + + ############################ + # Package would be ignored # + ############################ + Python recognizes 'mmcv.ops.csrc.pytorch' as an importable package, + but it is not listed in the `packages` configuration of setuptools. + + 'mmcv.ops.csrc.pytorch' has been automatically added to the distribution only + because it may contain data files, but this behavior is likely to change + in future versions of setuptools (and therefore is considered deprecated). + + Please make sure that 'mmcv.ops.csrc.pytorch' is included as a package by using + the `packages` configuration field or the proper discovery methods + (for example by using `find_namespace_packages(...)`/`find_namespace:` + instead of `find_packages(...)`/`find:`). + + You can read more about "package discovery" and "data files" on setuptools + documentation page. + + +!! + + check.warn(importable) +/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.pytorch.cpu' as data is deprecated, please list it in `packages`. + !! + + + ############################ + # Package would be ignored # + ############################ + Python recognizes 'mmcv.ops.csrc.pytorch.cpu' as an importable package, + but it is not listed in the `packages` configuration of setuptools. + + 'mmcv.ops.csrc.pytorch.cpu' has been automatically added to the distribution only + because it may contain data files, but this behavior is likely to change + in future versions of setuptools (and therefore is considered deprecated). + + Please make sure that 'mmcv.ops.csrc.pytorch.cpu' is included as a package by using + the `packages` configuration field or the proper discovery methods + (for example by using `find_namespace_packages(...)`/`find_namespace:` + instead of `find_packages(...)`/`find:`). + + You can read more about "package discovery" and "data files" on setuptools + documentation page. + + +!! + + check.warn(importable) +/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.pytorch.cuda' as data is deprecated, please list it in `packages`. + !! + + + ############################ + # Package would be ignored # + ############################ + Python recognizes 'mmcv.ops.csrc.pytorch.cuda' as an importable package, + but it is not listed in the `packages` configuration of setuptools. + + 'mmcv.ops.csrc.pytorch.cuda' has been automatically added to the distribution only + because it may contain data files, but this behavior is likely to change + in future versions of setuptools (and therefore is considered deprecated). + + Please make sure that 'mmcv.ops.csrc.pytorch.cuda' is included as a package by using + the `packages` configuration field or the proper discovery methods + (for example by using `find_namespace_packages(...)`/`find_namespace:` + instead of `find_packages(...)`/`find:`). + + You can read more about "package discovery" and "data files" on setuptools + documentation page. + + +!! + + check.warn(importable) +/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.pytorch.mlu' as data is deprecated, please list it in `packages`. + !! + + + ############################ + # Package would be ignored # + ############################ + Python recognizes 'mmcv.ops.csrc.pytorch.mlu' as an importable package, + but it is not listed in the `packages` configuration of setuptools. + + 'mmcv.ops.csrc.pytorch.mlu' has been automatically added to the distribution only + because it may contain data files, but this behavior is likely to change + in future versions of setuptools (and therefore is considered deprecated). + + Please make sure that 'mmcv.ops.csrc.pytorch.mlu' is included as a package by using + the `packages` configuration field or the proper discovery methods + (for example by using `find_namespace_packages(...)`/`find_namespace:` + instead of `find_packages(...)`/`find:`). + + You can read more about "package discovery" and "data files" on setuptools + documentation page. + + +!! + + check.warn(importable) +/opt/apps/local/lib64/python3/dist-packages/torch/utils/cpp_extension.py:344: UserWarning: + + !! WARNING !! + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +Your compiler (c++) is not compatible with the compiler Pytorch was +built with for this platform, which is g++ on linux. Please +use g++ to to compile your extension. Alternatively, you may +compile PyTorch from source using c++, and then you can also use +c++ to compile your extension. + +See https://github.com/pytorch/pytorch/blob/master/CONTRIBUTING.md for help +with compiling PyTorch from source. +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + !! WARNING !! + + platform=sys.platform)) +Emitting ninja build file /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/build.ninja... +Compiling objects... +Using envvar MAX_JOBS (256) as the number of workers... +[1/2] c++ -MMD -MF /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch/cuda/cudabind.o.d -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -DMMCV_WITH_CUDA -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/pytorch -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/common -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/common/cuda -I/opt/apps/local/lib64/python3/dist-packages/torch/include -I/opt/apps/local/lib64/python3/dist-packages/torch/include/torch/csrc/api/include -I/opt/apps/local/lib64/python3/dist-packages/torch/include/TH -I/opt/apps/local/lib64/python3/dist-packages/torch/include/THC -I/opt/sw_home/local/cuda/include -I/usr/local/include/python3.7m -c -c /home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp -o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch/cuda/cudabind.o -std=c++14 -DTORCH_API_INCLUDE_EXTENSION_H '-DPYBIND11_COMPILER_TYPE="_gcc"' '-DPYBIND11_STDLIB="_libstdcpp"' '-DPYBIND11_BUILD_ABI="_cxxabi1013"' -DTORCH_EXTENSION_NAME=_ext -D_GLIBCXX_USE_CXX11_ABI=0 +[2/2] c++ -MMD -MF /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch/pybind.o.d -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -DMMCV_WITH_CUDA -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/pytorch -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/common -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/common/cuda -I/opt/apps/local/lib64/python3/dist-packages/torch/include -I/opt/apps/local/lib64/python3/dist-packages/torch/include/torch/csrc/api/include -I/opt/apps/local/lib64/python3/dist-packages/torch/include/TH -I/opt/apps/local/lib64/python3/dist-packages/torch/include/THC -I/opt/sw_home/local/cuda/include -I/usr/local/include/python3.7m -c -c /home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp -o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch/pybind.o -std=c++14 -DTORCH_API_INCLUDE_EXTENSION_H '-DPYBIND11_COMPILER_TYPE="_gcc"' '-DPYBIND11_STDLIB="_libstdcpp"' '-DPYBIND11_BUILD_ABI="_cxxabi1013"' -DTORCH_EXTENSION_NAME=_ext -D_GLIBCXX_USE_CXX11_ABI=0 +g++ -pthread -shared /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/active_rotated_filter.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/assign_score_withk.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/ball_query.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/bbox_overlaps.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/bezier_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/border_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/box_iou_quadri.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/box_iou_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/carafe.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/carafe_naive.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/chamfer_distance.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/contour_expand.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/convex_iou.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/correlation.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/active_rotated_filter.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/bezier_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/box_iou_quadri.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/box_iou_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/deform_conv.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/modulated_deform_conv.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/nms.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/nms_quadri.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/nms_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/pixel_group.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/points_in_boxes.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/psamask.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/roi_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/roi_align_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/rotated_feature_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/voxelization.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/active_rotated_filter_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/assign_score_withk_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/ball_query_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/bbox_overlaps_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/bezier_align_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/border_align_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/box_iou_quadri_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/box_iou_rotated_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/carafe_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/carafe_naive_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/chamfer_distance_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/convex_iou.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/correlation_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/cudabind.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/deform_conv_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/deform_roi_pool_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/diff_iou_rotated_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/focal_loss_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/fused_bias_leakyrelu_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/gather_points_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/group_points_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/iou3d_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/knn_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/masked_conv2d_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/min_area_polygons.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/modulated_deform_conv_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/ms_deform_attn_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/nms_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/nms_quadri_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/nms_rotated_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/points_in_boxes_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/points_in_polygons_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/prroi_pool_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/psamask_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/riroi_align_rotated_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/roi_align_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/roi_align_rotated_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/roi_pool_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/roiaware_pool3d_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/roipoint_pool3d_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/rotated_feature_align_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/scatter_points_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/stack_ball_query_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/stack_group_points_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/sync_bn_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/three_interpolate_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/tin_shift_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/upfirdn2d_kernel.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/voxelization_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/deform_conv.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/deform_roi_pool.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/diff_iou_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/focal_loss.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/furthest_point_sample.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/fused_bias_leakyrelu.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/fused_spconv_ops.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/gather_points.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/group_points.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/info.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/iou3d.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/knn.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/masked_conv2d.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/min_area_polygons.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/modulated_deform_conv.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/ms_deform_attn.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/nms.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/nms_quadri.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/nms_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/pixel_group.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/points_in_boxes.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/points_in_polygons.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/prroi_pool.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/psamask.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/pybind.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/riroi_align_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/roi_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/roi_align_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/roi_pool.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/roiaware_pool3d.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/roipoint_pool3d.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/rotated_feature_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/scatter_points.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/sync_bn.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/three_interpolate.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/tin_shift.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/upfirdn2d.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/voxelization.o -L/opt/apps/local/lib64/python3/dist-packages/torch/lib -L/opt/sw_home/local/cuda/lib64 -L/usr/local/lib -lc10 -ltorch -ltorch_cpu -ltorch_python -lcudart -lc10_cuda -ltorch_cuda -o build/lib.linux-x86_64-cpython-37/mmcv/_ext.cpython-37m-x86_64-linux-gnu.so diff --git a/cv/distiller/CWD/mmcv/docker/README.md b/cv/distiller/CWD/mmcv/docker/README.md new file mode 100644 index 000000000..60d5c9de5 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docker/README.md @@ -0,0 +1,70 @@ +# Docker images + +There are two `Dockerfile` files to build docker images, one to build an image with the mmcv pre-built package and the other with the mmcv development environment. + +```text +. +|-- README.md +|-- dev # build with mmcv development environment +| `-- Dockerfile +`-- release # build with mmcv pre-built package + `-- Dockerfile +``` + +## Build docker images + +### Build with mmcv pre-built package + +Build with local repository + +```bash +git clone https://github.com/open-mmlab/mmcv.git && cd mmcv +docker build -t mmcv -f docker/release/Dockerfile . +``` + +Or build with remote repository + +```bash +docker build -t mmcv https://github.com/open-mmlab/mmcv.git#master:docker/release +``` + +The [Dockerfile](release/Dockerfile) installs latest released version of mmcv by default, but you can specify mmcv versions to install expected versions. + +```bash +docker image build -t mmcv -f docker/release/Dockerfile --build-arg MMCV=2.0.0rc1 . +``` + +If you also want to use other versions of PyTorch and CUDA, you can also pass them when building docker images. + +An example to build an image with PyTorch 1.11 and CUDA 11.3. + +```bash +docker build -t mmcv -f docker/release/Dockerfile \ + --build-arg PYTORCH=1.9.0 \ + --build-arg CUDA=11.1 \ + --build-arg CUDNN=8 \ + --build-arg MMCV=2.0.0rc1 . +``` + +More available versions of PyTorch and CUDA can be found at [dockerhub/pytorch](https://hub.docker.com/r/pytorch/pytorch/tags). + +### Build with mmcv development environment + +If you want to build an docker image with the mmcv development environment, you can use the following command + +```bash +git clone https://github.com/open-mmlab/mmcv.git && cd mmcv +docker build -t mmcv -f docker/dev/Dockerfile --build-arg CUDA_ARCH=7.5 . +``` + +Note that `CUDA_ARCH` is the cumpute capability of your GPU and you can find it at [Compute Capability](https://developer.nvidia.com/cuda-gpus#compute). + +The building process may take 10 minutes or more. + +## Run images + +```bash +docker run --gpus all --shm-size=8g -it mmcv +``` + +See [docker run](https://docs.docker.com/engine/reference/commandline/run/) for more usages. diff --git a/cv/distiller/CWD/mmcv/docker/dev/Dockerfile b/cv/distiller/CWD/mmcv/docker/dev/Dockerfile new file mode 100644 index 000000000..a4d9e23fc --- /dev/null +++ b/cv/distiller/CWD/mmcv/docker/dev/Dockerfile @@ -0,0 +1,31 @@ +ARG PYTORCH="1.8.1" +ARG CUDA="10.2" +ARG CUDNN="7" + +FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-devel + +# To fix GPG key error when running apt-get update +RUN rm /etc/apt/sources.list.d/cuda.list \ + && rm /etc/apt/sources.list.d/nvidia-ml.list \ + && apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub \ + && apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/7fa2af80.pub + +# Install git and system dependencies for opencv-python +RUN apt-get update && apt-get install -y git \ + && apt-get update && apt-get install -y libgl1 libglib2.0-0 + +# Install system dependencies for unit tests +RUN apt-get install -y ffmpeg libturbojpeg \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# build mmcv from source with develop mode +ARG HTTPS_PROXY="" +ENV https_proxy=${HTTPS_PROXY} +ENV FORCE_CUDA="1" +ARG CUDA_ARCH="" +ENV TORCH_CUDA_ARCH_LIST=${CUDA_ARCH} +RUN git clone https://github.com/open-mmlab/mmcv.git /mmcv +WORKDIR /mmcv +RUN git checkout 2.x && git rev-parse --short HEAD +RUN pip install --no-cache-dir -e .[all] -v && pip install pre-commit && pre-commit install diff --git a/cv/distiller/CWD/mmcv/docker/release/Dockerfile b/cv/distiller/CWD/mmcv/docker/release/Dockerfile new file mode 100644 index 000000000..d5e25e9eb --- /dev/null +++ b/cv/distiller/CWD/mmcv/docker/release/Dockerfile @@ -0,0 +1,23 @@ +ARG PYTORCH="1.8.1" +ARG CUDA="10.2" +ARG CUDNN="7" + +FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-devel + +# To fix GPG key error when running apt-get update +RUN rm /etc/apt/sources.list.d/cuda.list \ + && rm /etc/apt/sources.list.d/nvidia-ml.list \ + && apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub \ + && apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/7fa2af80.pub + +# Install system dependencies for opencv-python +RUN apt-get update && apt-get install -y libgl1 libglib2.0-0 \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Install mmcv +ARG MMCV="" +RUN if [ "${MMCV}" = "" ]; then pip install -U openmim && mim install 'mmcv>=2.0.0rc1'; else pip install -U openmim && mim install mmcv==${MMCV}; fi + +# Verify the installation +RUN python -c 'import mmcv;print(mmcv.__version__)' diff --git a/cv/distiller/CWD/mmcv/docs/en/Makefile b/cv/distiller/CWD/mmcv/docs/en/Makefile new file mode 100644 index 000000000..51285967a --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/community/1.png b/cv/distiller/CWD/mmcv/docs/en/_static/community/1.png new file mode 100644 index 0000000000000000000000000000000000000000..1837fbc8ca1dd46fc169d3c16fd2aef73645af92 GIT binary patch literal 84328 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

( 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 UYHVGJ!va4UNkxf5aYNt#12M`t82|tP literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/css/readthedocs.css b/cv/distiller/CWD/mmcv/docs/en/_static/css/readthedocs.css new file mode 100644 index 000000000..9e3a567d5 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/_static/css/readthedocs.css @@ -0,0 +1,10 @@ +.header-logo { + background-image: url("../image/mmcv-logo.png"); + background-size: 85px 40px; + height: 40px; + width: 85px; +} + +table.colwidths-auto td { + width: 50% +} diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/flow_img2toimg1.png b/cv/distiller/CWD/mmcv/docs/en/_static/flow_img2toimg1.png new file mode 100644 index 0000000000000000000000000000000000000000..12df0a17ddd3290f5f05072c2bcd38ae79d9f100 GIT binary patch literal 94702 zcmXtAWl$Vlu$^ULaSy?ROCY%W;!c3z7Tn#P#RCLSa1HJdAUL}LJ_x}R+(`&-L4z#& zc=hW2n7T7lQ#Ez#cK11by6;WU)>6jDp~3+G0AE!_K^FkfpKd{ISZGfJ6U_k8(*X97 zQ`N)5!dlsSz4`Qr?Wtny0{{d=|9gQxauQGj06n0pAgdQxaMWkoaoij9;<}f9x4`AN zPe%1i-nS~F6S_UCa>_54s-L+=$&XQvzuK7kR7}*ps8>`o+cXKuuROOqZ`tNXGYXAP z_RNpV4O=AQIBS?PUa5yPweJ+52S*BEXV7D3Y!-wLQ-%0MA(F`Hu_bxV&`M-N*@)0E z8kf=HHrx`PWg7gGv5{>@DO+261A^v5=t7O%cWOVpb@y!2bSW@+b_a4^u~yF&ejxnt zvq>f7J;s4Q$=xOH`tFti7g0X`oP#p?@`2RrmS~nYqK}~m_+!?eU-*!fE1sZTJs-E( zvertG;QmU{vZc}aQzONI>Ek2#Pn%M4d z80CvUJ9nt|v}Og;jhcpqTO)@DmpROq#+fWy_p36B6w{E;H!;Yi;~W@s^5%D8 z=#STyTNYMI-t&fBVrK)A`%c#D1$f$bYO>HzJPcdAA4am5 zpucPEs&=<;IEqRBl&O-m-Jy<*(DL)qRainn?!=SUaW`Q>I~|MyV=>R{KPiz0ISXMp zjpzFv+Nqp0Ttn|DVGj};4?<>G7rpS6hV^6Te);#oq4#Jo+H?vz+ugYA{|XxB&p-Hz zfCq+r5BuB2W?k_oKTrGFL+0y9^)1laZ(sr~gV@$1z4ZbgtgqUcuw$9Y+ii%>Yi>gY zbE8(+|GW0;$OJ|e{cL58_G0PY7PK5xSlN_$(~V*{!{tUtTXxZhSE#_Hp>pst0C{g?;IMw=6CtH zx0ByV_7pOuJQOboR+V0w=)^^Lh(@&r`zOh-h7)_x-OI0fC6!DpTh|B{cR-K*QdEH(~l<7f_S?ONm8?-eXQ z+x(nEnNxJ50;VSo2=#T$7?b#7Lw|Dm)lRXeRo8wb%PZooH$}o>=^tG4MTpU#t;R{( z1)Y*p`dGJ6M?I8~#f2V*7PG_PqZR|$(nj&y3!nL2(Qbpd7xxA^Z@Du8>hE5tPXVjX zvW)HW%i1R6tZ!>zp8f(I#mN86%p?D6QN6~t9LwvlQXfVPo58G!buMtzd+~e0K31I1 z|4X5|#_V7s-f?-%Y6WEkXTFvzU=8^E!`&~cLdC+q;SX?-Tes6Ol=~^M)i(0AXpana z670<$iP3`S1^d7ArtwRSo4I1p(A>B0`Xc!PE05CSDScTUn4GVQf0tmJGHRLVh=;cS z5>JZG4r7kYXxvJND}9kt={?Dcy!bPmBw#K`qo5$5cj!I;QZM;Vy`C4$8?t|~zj-l( z4po@&uzPuiw%E9%>bd*hMmj;RP}CrA{JD*7%G!@`)p}8yqQU0BW@QVRb-q6b4@4xn z(kdO(6QYmk{J;qEtRtHjx(F82w2B+FJj~qc7T)WRfDaR=o&OP*mA?t^l*Rp^t=4*- zt!n+ZIsVdw-0B$xHP${QY$>FGDW)WGD-Tm+A$dz>4hZna7Lycdy+9+eK99!OnT>8>&nrmXz7xg4*)YSTk z{)Qw+YH9Fe=LrMUYeU;A1aWY%PY_7aCBsx`r}8zXaQOlKSv#3$OE^nY)7O;!oc53+ z^?!`=%MBS0fqxxBagM7<>qTD_lktqJ<+65Tv0$2dVw^eF+hf`C#rboRF~jT`!prg2#Bx#$#5@~h65 znEy4Syb>GVO2!TiLxulPLFOC&35!1_&m%KB*Emde$kvAAdD*V17SpAKSH~0XhF>LF zas9{zFHOYy+-sXO{1OlG0i*c71>4g@%C5LkCvXr9^|+x~l{8f8?EOpbb$)35hlwV^ z!YHl}1d-Z4)#klNr!aAQp z$XWB|3t5*MzVTBQI?W%9Cyuf2-kBRO3VS4NXh7&u%2TTs^%OVgV_&F$PXOj@tv5AX zKNj}KT1yG9eu;4P(lRwKJm)l=>eQ$bmOyld# zyGTMbD4g$Y18JpLc2499FYv0?{|}5Bd>;0N}(aV4ykJQGIbnKdI6mxkn_P6wk=b)cCl(21{KcNDEPneAS`oX@+7u@ObMD7I> z{Bfr}ZfK^!DjxxE+9;o~ZsfS^YQF9kJbT?-73W+4;hoZZJi1UWB?{m@Dn)-to64XN8jr$Gbip&i8WO75Liu zI25@kEZ03d3o@y?$bk3%oxBVuTr56+Fhcy1l5e_Gsjt2*uU~7j@5lIVa{ftwHrLp{ z@i_k%Quft3ha32-a&C#%-Y!Z7pg+gM|L;C*>bW6?50WsVa;%Ig7njIS>owko0{&wJ z68et$2%e_sQP5%eMjX4-o1u6wuu;cTfiqEiaF>UO zIGG_zHqe~{ThQ-eEbNLd=O|$$#U}b6XASM~7{LtkplKmjcZlWsYFyH~10ekFJxwH| zJpfTr$Dg^g`MXLw^5Q+2fpYyX_wdX|$-{}M@yBJ`UOdDgwu2pjxVd(+LG=-vIWXLk zn^9O!+W>njW&cpK(mk9(F?)W!u%`uXI9mhW4VzK!SOM>KZIvaTUcF%SY|lV*`lUJ0 zjmtdj&_)el^U0b>?T1kUr-wqo+R0=4p-Ec_<)#+m+Y*e`UI+;Old3_@=8FL?VUeAL zK&f(Dj3+XryB?{9fSvCG)L_dG+!DXiWAUf!&@VpKyMpU?!?F<{)Docv#=Wl-ew>T} zSsC*`Lx$9r&Xp^g&;Rz$Xpxo2q{y5mZem0($j@gBp%wbZ5$=D@j8B z2WAhfvEFtkALB!HQzY(N^GK?Bud8+HnEb)82AYza!l%D~a-)O=Xl|WVvOC%Ga$V4c z3Nmw*PRHJm?dCp8n4VfEL54R642-rJ zthKrDyZ}dK75zvG^?_r};Mh%l#kE}>kitCFW zdm7_vqAB2^m}c;x4(`7*?L@G7d5z_eB2wTq>5Ir;clfYT0iY)16w9i;B0rrn{>gl> zRj{odjp^!wwgRBzWdje<6HeZ}qe0Oa=vtXJG~0$h8Nwk5D!{W#`c@{NT#xXm%YOk~ zLKr&1RGqsn1n_VIV_gaRwot0{z>yV*`G-jN-Hj z{WuwOi&y?&4jZnZGH+zL$kX4%GZ>;s9}5J{j6AAz3Q!JvZQLgePsu`Hq)Y7}4J>DS z*oJ)4Ss`e#4K&SDesN6$fxa!WAsJUI&v41-)}fV`xkm`vz94Ja)S$@Y|?8n27me|78u@#^Vv zHnKbaP&>1<7q?GkWvOLO{Ld=Eu9MG^Jx!x5HtflPEcqf`?ujdI{jKp~#Xj>u;4Ao_ zwx*PxtwYGEYdh$23Xam@@or$|Tm*i0-vr^qr1u3VfkB1;6xX^zyiai+3tUpQZ4TgFHNolzk6uVHd@&lHK5-Zvq9E9Iyh_G+kxFxk>14bLCU zF9N{yT{JU)Idx7zbIv6a3#Auerdkn(U;Ho1)(0B-f0GcrmP^)adElJEL(Cf5y?Kfz zs_QIq;nyeDyswEALU>00t0gHlK{nw zFv!-5Ag~$HdTUv$l+O?BkcLDUr3ewMz2bKSG^|j~5NP()Yr})DwqsPc1*aOSBB?rKVsib>joX z?jG)x!K0W~8nwRVVtp~937TN~1pXH9xZSqTpftw&m;CNi079YSi#_m){=q$MpBd%? zoK2T$)dlplZK4NxocP67Q2^Y|!-$F#>1XpU^K+wvbPBGC<9M)n%#U#S2;bW3cOABX z#s?w?psfqA0-~GnGs$O0w|F0gsS)@OSH%P>?}j#+XaBl9u7#Oc%Bx4X*2*(@F`5tNA<$rJX(%Js|LiAHtm$7{^sFvzsV1xCubX? zAS|nGk(v3N`q6j5=%(3e=}&Pj=S+8-L_Hy6T#(^X;Pc);s#h^>fvYvBEa{UHSLj8DV~uvF`Fp9hRslT1gBgrS(oLV>2P zjJBcEU{Z)y40PV;MXn{8;Er26yf6iJ9vK9Bn59^x)iKQPypHuF=d*U)YId^8W z{V;qF;tk@~zDfoQHpND4A+fO{BhFBlWG>>m0c$Vw5e1I_i8mIKPFHwB$Rui{Uv7+~ zH(0m+l2-3ycz>4mqHuj|+$s4ws-Wjj8hRGs3c zeS!1bSNzmJsZSiG`<<3kX8C#?xi%bEdm3ma=L&y_M0Dm1Lp=M8^RR0evhs+r0E#mg z`EgkF^9B~(=MV(Z%dcbz?2r2-LR`^ZVn1ob*@%ZRE8VDovQ`Vg=GjU=sM*s(B)-eY zCTW%BIQdd_s5+ow0;1vuwAr>liwa8pf|<43lbd<|WN@mtt7Raf@~f>gdrMmlv`daH z%jXkc!v(cy{i|rV{dy^mU$M@_H|mW|SrcpkDcX9iSjW3gf}n zx7TGYuR94#a`!|0_8?!E|+7nY$uF|*ee^^ESFIq&8R3GKZ)g4WU-Q7c3H_mtCfm^W8b zoUhTgoq^d37LvXKd|p$nRw`gk@mrP)f%ef39*pc_O;k4{#?g4|-4X?GW%yEumSxAL z@Yg&an6)3EO=FeCn75)nfzX6J9pfH(4*7?VrMN@+9UX5>sB3U|Ml8kejOSb z`JiUfhGPfFL}IhED5zZ(rp@AOLkp%aT&3m(;=cD|f`Px?Yo9>P?(_NoaX_G=?hpuc z6JPDuEidMsx5-yX&OfyA59T0?$geGo5W5+BZ`Y{r9wPw7E9qT3AO!@yQewGwa5U;Z zcK8XTq2>wjtKZ^@WsH-p*h69@HVg1!TLdrMOaT_{N{nq}w%(3p&Ymk{<@`A~V69RSC^#MZ=^naP~ zVTwf_CPxt9eA-IF$oV&JvfUoMsvoc- z{7_8eB%E9~s=?!pQE!x3!0G8kO+Uu{O0>GghM?Y}FY_$|N+{l--4#aCwNE-^FaeuU zwbP!E^h6CGiWC0ux-p)yrn+NuCA;>c4Y?fFF=Y*$KoMBKh<|S63mt2*prYzO*RC=#?w(cUvdiF%l{N$>Tb-sRO(WVC5Jlff3Z zWgHQlZ9FalC4|v6+Y0l>HrMH`m?D;h8hYIVLGak=^aAO}5w2Z8)G!+JUQ?x~Ra-ks zFUy&szwM-cw9oTbeuUk>CKMUZB$h@5zKu+03kkQ}fBSwQwF}jDnM2>tyCi)YWh9yE zo(%@3atHlVyoY|o^PZjS19UH|Qx!Ba`UKAxcp0RxS%{vQzDfmp8E9Hb#$!T}Kf&+p z#G}=qGTFD}61o~0ZHoEepWBrS&RU1v%GcI$VL#rR#M*sU;|er0uci8?FsU)RkCbWL zpc+{_WSAu{{ZrMG9f92N&!yc_ctb#p^{*YSTRcw@!-5CH9y(!kjmZ%L-XsagwCBa* zO*pmr+Ak*N;=%TeTs}2!u_t$J6uB(}2&E4+$;C(#fXGu4)cn5KZ20sde2N4XaClgZ z9pE!MI{g5F-7IGF1G>2CF9lny1xWu=QeNoc>#7viJp1_{2|6Yp7O?7{nu)%V4N8L{ zZ>~P4lb{IzVFNWmTjb^TU|%|l)ue>53wJ={8$-+VI6mx4Omt=Qc~yoF1yGcOPX&-r z>k5%X9IFS4g4&f#MP+E#r(#Lp1lHvB^y3hS4kPev6~~I0*p%|Sxl7p$5*bM@gjIvonmiy8okKiwUh^lwm10_COvYUAaBr1ohInLm5 z32a_BqW~RnNqQh_e}>VKns2j2*)1L{(rZC>1Qy1e2LTG^EkFPBYi7_7c@ntZjVJ@P z7zXB~k?9tDEP@R;@ehB3g|?^xdp8Q3-~rf58(d;Yll{dkKjBQ$By$5{kTICP?;GAO zdzQJ4z$qfgFbfxZ>ZJ5N>6|^@YAk5_GJe16{xOv=8u_Tt+ds0oQa0D<0)awJAi@Y= za0%BZK7ha{m8gSx1;LD{#DiH5ltK_^dz>Y12x*cYP@2FxN(xw~;StbmE5Bzrc-zB` zORdbxV9y2WXd*=;B9d%jNm~Z?f_jsvfdmW($4{?ZfJIji8%T+H`148OpA~bjB58VI zm4`$hpr@$6IhnATy{eJc2QC>UJ)s7vnK zh7sg~X1_JHN9o_DDog{=Z$`@s`V_9}EA-ObOEOT~sjzG?%5yXwMh}ORu&Yx~{0MX7 z3apGOp6&uO@{lJqJx2XI68RPr`gixPXW175MZGzmu+yr|Ui;?GQNu|IT!>Ez@|zew zT9WNdi;W`0Fy!(k&5;6uhmA^(e8A&JgyZ#w+=vZ}@AXJSD~KW5Dh*^=A*S4hTxO@X z3~r)HON*LI<^_hgS99rIs4b%*P=T#Z{iEAAqhfe~U@a#qxZ27Ghx%c40kpQxk48*@ zSDk!=+tl?OO>Wb(`4wIL*MGDJJe@xWor)9zPFIq_$JC}U9RT2lrVwTnNc}s%kGy#q z3nIGWwfUTrd%!|eT$=E?7StT`oRR{Fe#5*VhPhDql7vJ{p{)lH!h^93%f$3lecZhM z<>pL{Hlv25)ft8$*ahg3%n0`p>kL-}OIu zoi^mz14GgXmD>xSr3a+jXA0LB`KPbCw;h1Xs>z>#3M0pi!cZWeIRsI%g+f1q6Wc7J zM{T5cq#*D42FWK$tge*Vu_JD(sBqeu{xU;x)B?PUuIa&+Mvufg0_~t>#d-*`IoJ zX~~0c+GMtsxa3Xwv@*b6qB9FLd3&kcC_ZQiB2i`w#Ibnu2fwa~A#vst@ zhIg_ZAeeS^v(9!CD&kTf293FS0T{_Foyu&1Q?D2zM9Uu0u@<(fevqTR-`Zbl!GRfi zT+TynRb|*dD7$eu%6}qZcRs|l^w}afHMD@TNptvAZ8;DaLSG;`4>-OrzIt?JrOUGY5VH(KaLIMxL$y>Q z?}pmC{+SKFpqM2^O-0y~J`^5P0bYOYf3ar{U9(ttky!G9>2pFXu!KbUI_bbr#ueR% zxu$B?tLV5x+|W~6=}WZ+z(3@EpyF|7Mq-u@@3n{2En$JZ@ z;JRc#+e|h7M|C@!4APl)%IzspYJ~Ksoc>^T8KbPRN}8|&d?cm4EAT!sU-)nEIkmM< zP0XAFz?d1Z2u42TUDq2_k#~%jaSG~=`AvJDL7^fH3lPg-IYiPa8|q^*PTkrN>e3-x z1Fa1NQ{q#mcLeb4P?|bF8SxWEfetG`@FI~$r;W#|JAhT9jpCtiPY9U)m(`JihkH&J zZk&va*dqgo&X8<+WYQ1A!+al1S|VWR=xrY*s}Y{p_JUIR^Y4O%XKgtAhcI*cG?2zbwq9nYBfGXo(=Hra6d^ zl6Q>$T8N)U?)`_i$(VRqb)U1?F}!oD%8L|&*mPa6UZKtP_zqBH-udIhtP=PcPHMLC z)YfUc+yQ2LRN-o$A==%SqrE#yzPB@0;8}afay{A+Z-3;RJa3?>(n;tjOW6Ddu9EMXz_UmN!u zT=%GT)Bhe>B(JAnXn;jg!z43;(=#&r$(#t-KCo!9J!3H{oj=d8efXSe2}JTei*=75 zJ$Yp-9ZHEqzad2&_cOrR4BrmL>>I!sA(xEI+0rMiPDyZjrb<9O z`VY-OkIP+3AvljUOw8f*UfGG${vY~oS{IH1&$j~{<`~C&z`ZiY%TZW*Z1eZq!FZYK z_3G@pD>S*|nLV$n3xO0u4ry#X8bDMzNVn`U?P#@a%GT6XmL2Qk^r%(-o6>yOlj5mS zPAoUYZ>a4cG_=PPC|Z=ZeyzS?BKen~k2TwRh`-eic9BG(5&@-r0 z#o4m;$=*fc6ws{m=-Z6P!H(K^(WNhV^dN8X3ORedI%&-xpJwoPkt?zk>q}CAeh9h~ zAn4>PWzg|{UFG=GH$vK>$9!3)@l*sa97Q_exzvxD964+oMQkxKI3vMned3|3D`(LqLn&iU`L{V7Y9cl48@(y+PS zTM+MD+jm|uHqWhE4EvZ`-JcjcP+0Bf8mMb1mwy{#p%O`<0*{-_JM! z$$s5*mQ%Jq0;7M8hH_IX)h}dUV}$P9?5m47f-PO54?CQniU#VIrc)ABZWHC_4>=aw z333qDQ}-(j`l(*$s!b&03hCv~zmb<=+UFKw(`UZUpHV5r?PtsIGal#jXc-@QlPi86 zS0dBdppg`Mdw#I=wI5)~LcoHqt#66=N_VeZwnoY$T0|ePvdaU=nt6s|d~l{Qzg9z| zucX%HlKXs{ttPhn3@;nU4zzc*fo{fmf0fmEn1UGl@4%`@H%vc|X^;c3#Dv0NzoS!_ zS}iAcO3T?mSY#gNs;{JypdD^t%QtPFu{swRK^LsM=ot&I86(Z(WVK3`Q!S9+Uxp26 zH(tvH`lktr~RuKnJ)U+_XdD8#9jDypY+$jbX~-YDyPj}daF zsS(QalyF7lK-g3@Ij-NbSJA5G5!yfW^D%~hoY{g;;q!jiC>@Tm<+YlfINOc~^Z*4C2c(^R*VA4D8-9YrbCJM>tzw^*f6x_=ql7W&2i@9#_<4j@JUE*;M(f(ieW+Vgi;)!hri4UfSYz8$x(yr86Z0{rD4@zeXU=0T{Z* zEDh8tkmimy(BT@jImUF3X~WeCQ}|W|AB4aJLg?jiqgE=>4sNv&s=0bf)sY?wt1;2062+X<&YGxU@Mh5(!I~?OOTfQb@x`Fbc z!G43Pz$q*#EJg|ECGNz)z<#*}9SMD@9qD&8mYU-CHLX~)W@z9X@f5^3HxU&5hw|t* zCmgc)Edh8y=INe4uA-?yIQwe0ukwz{L-SrH%7o(UME!w`siUtJx$KeeQH(bO1AR-@gXU6qs~Yn(SFFJ3ckq8L06E8;>h4`&M$Fm~TqgYYHE-j_i(kQRCR4@JTW?QdLsIbCd%&^A>JH{D*C8jaU=aLv zB3&3EgEXi^`|8=D07r5Wor&xiCG%n>d^HRX?*HMd^R1g9R_NM=e&req=LbCq|l|JBwz7Yu|uA&$>Zw)XP! zOhlKduoc2ck8P zWs?cdpfy48PKmo!?!LE4ocj(h*mAomZm&0=_=Xaed-iBZPrwe+i4wezuUV$L&#p7~ z!+nLcD8hh>I^En2bP|HnR+rlt&@DjFpwFo%n5UlXA6~^-#I*4FL3F9g=T;H|08;nVlZ5_b^)qj!?^qN-pJX6j>g()g zf;MZg?E=%D=&il<;@lj&OA9jY$(=1z8c6uBN znqboHhQihvcM_9QDW)kaXJWJP7oaOF*mB#*zw2*@3l$t|gk8zlTVu0g84;{4-To7R z69(Ei*f0{g2=wF)#H+k-YZqk8=Oib1~ehb7?a+CLPnR^65)bl@8@u{#=SWXJD z%VHFKZceuONKE9bIkl2s_xyeN>}xV%#?6m-J;wd_KhX z=*V6@gg@Fup6NZ!uFYr!LXqRbb@!A{jIi}Xh5`GVzj_b=vt@cQ!l}@T`Q9P+^bn2r zdir`M$KS)$sH@@gR; zZ|Vn?0(ryZ7nj#IW?m@!ydpe1&x`CM2%eY7`ueE7GkE_N!^RQ=nuW|)I6|Y3z|;-e&dpCvNBG%+h~|0eqlo?;!OO3gV4E;q z_ix4>#5s$R8x(nFmLq1K201CpV^AZB+>?EGCZ#B_j1x4)>X&pb2Hx7MZv!l-*tN;>(7}qO*Aw+It&yxyJU#Z@IkGvj*W~SWgiO6b z7<)O2HUC8RvH3FM5@+W3$FQ8<;FJ=!#8 zm>YUb@M|qfoMd6|KOB#KPf%J%u#f(IG}NKd%jR16R!e+`L$7TYUvy+> zPZPs&#`Mh&6-R_irrG$f0aiOOqre2y{xF#$g;*i);k^Mj&BoGyh;6kb&vR%!L&#*W z#R%xoQzf@A;N?{&B78M|qSuHKfxOKo%R}Y*gxJvFMz~wwk;89;|LIv`0_(Zoqa@~& zeDfIJF-~c>U ztZ}Nc32+`Ap@ZIwxqx%*QQB4SM}PO#a@Hobmox@Xy-o*+LnV->j z=s-n5;s?_xxp?*dMslzo`NJk9877P_D4LG%2!089OgQuO?S-|~o}29Hej`#uUirrG z7KsJFO3>KfuCXYg|lJ>@r{pZ&pYlZO2@hr zCo~ysUbDlKXzAxvxqe-79xO6e_ixU4pObnfIy+4*9!dVaV^%jpMGd!d37)Bo98`0N zZF#W8k~tq1UL1OejM&_=4LA%ijPgQb6MEO^``prY#i8{kBCI*_8HS+=`Es|V#fXmi zM`;qfQZ+U7VQt=CNzO>J1!Y=rs`3XGgf_O`$xf;C)q=jAz%!bKR&Vi7B)@=boFn4m zM-FME-4H_r<41U0^z_tQa`v-T<5%b7)qgvfD057U`#y9Z`QTaU`_4LXlr*zhl%lCATGo77S7A3eZizVFJNIre;D>MC zPXR{=IE`<%=yQXX-8y-kg2;#;clj+Ss_3RvbmGk+hk?ITKW4_Q0b^_>x?#js`q}$P z;-aFt?dVP6ctf@`v<2Ko`(5qQhZ?g3LMWCwY0M$n0-I-Hj21ma$vM5*SFoFlnm&Rh z-r8Q0t7>3USSsrb7f@0!C%E?5 z%mr!DQ!TLW$o$Pl%Xd1Yz>)qnfz?Qul0nK5(ebz0Tr0O>N1j~j^sp$Pll`snuR16Z z+7aLn>x`o1x{qIlw0ZU;)j}RHS4=^jN5!x1BZ9yFjt9f-Ajw0jKf_p;`h6^s zp9PCI3=G6z>@~ZZEZS~6Ew_*B@+I~Df3?yqoA89^(*% z|0PW%*{ewE#tCU(yqKn@r2~?B5D`n#xXjG5Mve1<1IpaF&6albG1^0cNZaZAzUbOdJtE^TDEXFgpGfgJ)F)03{PJT^vf+5Wc=4|HgrRHkUz z=y?d9M5OvVftcx(M|+h|KeSL^ufJS#^fYuM>M(C*{^?)%k+yt^0e~%Ebe#Xj-qQWO z{gRel}tu9@~8f;f7HjKDkc)la`v9NRsdWY zyl*coDHXba^qaSP25&QD<^RzxU2#B@>n!d|laTiwa;b$xqbOd;a& zp6@m`bt>TS0-)9p5kIkAyXf0`lZUK}P;G!>M855fjF^lBcfvfE;K0Y_Li0G$fw>?= z%s{%wFUoM92fOwYAs^veu@`@>SwW)f&h8TvpUo@ve>jk1IlQ8CmsLfn1KK%Z;m!&$ zZGB*F2`(Fi=wa&%1n4*CI3;@_pwsoOedEy}BvrSGJ{h($KA>2dMWl!KF@zo_LGBf6 zNrX;wbRLIup#5d)k^55%L%0v2tLsI%&tPrGrxnS?>kEEuE@MLV6!uqhja9R$nf_^i zrt>AGQI(HxmLjU5xS8=cz;&Qa$O$MP}4&7{N4ulk@GF<4$?gpGrDbhw*&$d z8QIs*mv@(R98k+178b2#4N8sKZTta_X0Yv)e<^e+kya@GK=E&n6^r!uJoIfZgG86H zs-oR=FlyYcDm>mZ%$KjR{()yqCK&-eTg+rjC`)pKf$0p#YOy7Pbh5y7JM5o5Si4jH5hLcsDGwnL zqDz;f&rEPFAT$tVQ~o$|30dREzpzKHP$MAS(k zptOg{@PQJFwz+v1W6$en;^X%(Af@v!;nmVOxsdMlEh(S)Khs?K&N6q45g$0XoRoe9aCtJ`qgG!lN^MbO(%aXE z#ZaflXNlt_Cbu}VTK5}x=yJJ%ma^P+qpL_y$0#D~qj!j!0MSVbvaA>>A-10+ zea-U`6kUDP8|i5jY_%wZKo*M6z3iGahO_#xtT=5`79QQp}v>|##Ab~Dc6~k_^WnOwN3?1V{%ai zRZBAMK>iFf^sX*)_eYc~7m}duX1)Wjdm)NV-rX--u2_}-AOtgwr`1iRKb$s^?p|Qv zha;D@SwE72%Uj9%!w36MQ>bS|yAPx?43_Q~oDuFFlpY_(78C%~!%C|Lnky|M-2O0} zcNVhveQ1CUHT@%uTSg=PGJiPIXY*4ElCdwo?+FFzV}7@v_LebA0odgo{V~S+N1r1= z+AyTNJA3V+`44M@#bnXCBogj#reBBK3C^=0P#=TaPjO4P4Tv=xbNwr zrPa$gbp%~b6Q}i)vaPc7IHj{K-K@`a3N~RdeDV*~MeU1on}y4ZB9V0TM*77Stn}EwaQ6Q(e*e&3 zIWCc{fRZ^$^fCaK{a=OCCke-sN6Oddk=f}5rx#Fs(0RmWyxjN*nLum*2>TSsPkB6| zI)fMv2df4FoTDI|PB#8oyC-ph*RKGfor|CvTwZ{L9sv;m@cO}d00ICWN*L__KN%J^eeBR5`1S$>?xO;G+0F@B%*8!6XaoK;-aPO;t zLLYtQHkFL*dTw&3qy-@JDj+xnfD+>BKX)xe=r6~0s+zb2buR&OnZw(%XKP@kr`d0#hBAW(#`_6efRR$0>06BXNtliQ_KepLYV7UZSy>1tIfPH@c(nrq=O{{5|7C$v z?_OFJcHoY`KsaYJgVX|O=&2QAcVz=$=e`bhW1xDLN$K*1D0Hgw-*|E>~@^awqCj~z{m37Y*o{M(XdIcUwDwx|FK zOR3e_UgqdAm$RG8MoU8ani?I9IV#v%J^&}YoN+qgd4<|v{*Kn1{YID()UKQZvaDFp`} z^v|kRAN7&4=)FO2gDmc>w+3kr&s#0YMemPr0hDkW!5{(zom#?Me%5ZZCG2|MjfCy7 z+C$pYk0I+(G5TSu^z%RA$^5Nv**Fu4PHlYM9SCzf%RvI&B*Hg=;$?~jKk{LD4ODBf zf~3i4l!zrCRy^|5Y5|NW_$R;NyS_Bi3xIQV&X*dgXWm_yA#(u$OzzL4hsos#df|Wn zf`bY>T|j#5zuAT;6lxf|x;l#iNS%ab1PeWKC5(}w4HX+ls5P=KJoYa%tp`ZccN6_+ zypaeHc=x1!Jv^ujMt}g;;9%I4)k7 z7E0JH#2OndIS%Xp`s|z`GQ1&%c;g{l1ajEFhGPHix<b~CByf9!mTb`>qU48$tkvQl0Clw zK*`iWW5&2Joso6&DXryDd##GXSq9BiBQNIxq-)Ug3m&u=kTFPvKuKVPg212#``r;Y z=(3aZL|6rOuo`fqij2&`2oFb;5BTiwBO1*zjYJ0YC|Ox<6y*QiGH$nc<4fjlq}C(2 z&2xr&e@2k+u#olyG4?>sgoqc_mGjuoq?P@{VgDh?kT%}Ata&X~kf|9>XazIq&I1sk*Y$o7Q}9oG1ArQRud#p29l19UK$_xLn#8-Q>;|A5 zr1$7#&i0A4==04r6;$+SsO9Q0CSviTa>()ow!Tc-!xjSxW;U~)e`p#%zs0{UA5 znA)Hdq^Udu7&y0dpS19jsqJdy;sI%v$PIvqJM3Rh2wZjYnjIqQ^co6qqu;_XYsoJ^{c7U!yEh9>I)@6aWG{*l7*HJ^3<%dr|4Lz({)X z6ly9!R`L}P1*p*GgiuOK4X;-_ub~oGD59_OgIWv?LU{sv024Sc5TSfjMf*?g z)CNG1)ZSPLQ)9OWZX9(3Ai&EzAAQ&Ge>?f^dX*ZBbO#LfyCHF}YwSxMs)Ts3;|OnJo>vWX5uLHxk9Bs*~dw`4PGIWE80n0%e&5M^w%4 zzgL?*%@wm$--Pf%`-SSc9q ze`6a+lR!@hNcL}Tfl!tp0u^9D#Q=GsS-$cP0>Hos1pq=(0EFWKAg~Gypc0~TDyKw6 z`iw9@aBvJ=5`bI$a`sW}BnZ;V9m|89e+R(ZKA=w7`^LP(KN~hfhY$*ewr9~3LJ@KL z0wZt73v5=)=YFDjJAk31?~%8t5mM747>C;91KP{BJ>PD9f-;vzB67S;DHh9UbGY-G zsTbd&r|!P^W{{hhXTS@Ag6YPJ*?-*&gmw^e!7l)zl17DY_vEm>JpT5{Z0!#KD4pFi z<>6muU(wp|zcdEqPCMi?Z&NPj%xc#*J=mWN1)XZrE>29>BSPHPErFbpdPa-yO~B)g*RIJ;E?(4x7~-1443|KfRDX_TN2?P}iqZ)I@Ch zbDe~Ayg2hZ%v`;>VT%9$H|$S$4}QSz?r;8ec{5BD`ch-Obfs-HeVx<>urDB zeBV5Rfaj|-qA%0}VgXPEQ2@Zp8OH+vh^svs45+`r!KYkf|3)i!qVoCTka7V4PiHIK z^oXQ)8hv~~#VxUBq&D-hO6f6vnaW)UES#0W)+4CY7rNOra|E10|N+E0V?%V6A(ZpAb{d(wUyI8GHH3hX9mv$+^TVX!$r#$)c3bzcG&hZ z$bDV(u=5ti+`;~-J=HMuy)9uQCr(;?+OTorn=)T(yIWRHJ;TzsavpT6tFAGZcFGUrMeeG>ZzLRjN%9NMq#j=s5)$Fovt1 znz-nT#|LoD{%hQX^hjA#m^|7SmDqx2H-?t%Yi5^CIPlFnRy*1eo;4w_x}KZ!&UV}AN1xqjCr->j+aA^^qa;(js2UAK4p?KppOPKCI@%6 z{D-smPFX+zfBvjf3-HSBwn-I42>=JO=7iA1*NSSMAm;qp?TI8^cG-XX`}%yg0@cC; zy#6k8-U7sBY8^vFitFwgf3cuSh>ru1$i}Q~>0TLktC}!Tthj zX+&9ofCF#^u1uXhtRAu6_^7;i9|J+HHV*5u@a@?E_Xh#HU5^O?aFR?{TLRLr-OK}+bGuAB(!Mcf zlwFwzl4U+9KYn)%9?pJ21%nW{nx&`$oa0#9cCwJ{pMe7xp;Aftfc-+roLb20&({u@ z2yY6)6chT$-rxcTyN{>iH~(-_-Z+2$7s}Lmxmfm(?v_I@{|&U`CNH5GKh!*cGy{zJ zL;x2kw9k)R2h1x7fC*(DTshbgf*b>nl+C-wvoCxrDt3Fqm-x>4{N`!cUvr@O_i4|Ht89t9(Q$X+ zAB_gVEC65(*Jl-acmROw3k0{#yA`Q3s*G*mOf|?c^&>+?X0J;N*HOn#O~BdZ)0uXt z%>xj5${RVvygc5$*lXrD+<*B;6*d3P_wnH$aheKeS09)rL|2Qc0n%(9aN-vrctie1 zMS?O0v60d~Uk)vn_*?7yt60;u^Z33aO=lqX<}Bajt#2e?OS zmp=@mGX{l`oKv_+2LHzFj* zm0u^s?LtQ6+ZNbymgn49fD|rSxP1~}M+b!7A4cLL08I)_%OHpI8PnVB2=y}{O{cm% zEAB4Y|K-I}PdNXY&3u03jb})3j$`4u2?1)B;DuW+_L?UTA+W`#gnKqw?Zw;0L0we1Xtl^JArM+yQgtPF1qC1opB`@m+z&IptHNf4gq1!` zRDgL?C@|^Yj9|S7X4USGarf`M-MrHp;?zb=s-Emx3KEsJ8QAiqMvVOf_`?kM+zkN<&frI{Z7 z7jpPtD7Sl|`z~_v4*wVW94@Ij)5m_v1+VTJ2EoEc4q%7ppI$7l|K4-sB{I2? z{Rx1H`UP6LbYYf2koNqMC;rOnE%bIn1R`86C{8F2;8$J10#7mvXIewqT?8)FssQN4 z#6}G`3y~oL&F^sB(+9Q)Guu%^!W!S7oIz+8ptcHXU+mk6=v@2HZDiGtdibp=B2*fd zTgWU4NEpcey+nT6$R=Axds_u=d4^ECStWq~B6KWqkXOan07C!QYtPI#x-3U1XB565 zR&UGlp9IKX!{jh*yA}xG+9Z4qzvsddWtY;s{GOjpA^^BN`;!^ESIvm+A~GIenogt&PXa@dN;e5(V?OzJXeGP?RXRbB+O&E6(}ZHhv`CX^sH! zqpv~0x4&znfA|CV&{0M6*}fAfY+J4N{Ukd)2t)UUO|EtXDttMzHuR34X0xF31b(($ zpPa*hNmrJcd*K|fOHW{}Vy%H^s%88nfKfk?(M@Bw1nQW(E>cx@hL3F(eF9@3VHVrz zCErGTo0Fj(30p%NK{2U#Yr;eTsXL>NN<>$gHTT67y~1N2TZ z+(9og8k}`9 zK*a#y#Tng~|I2mE|IT}gG{1VSlKiC)gukS=KEo5 zXPX5B1@O0iJSyvWxLvzghE2}ge%u=&&c8XnpC@8xw}kgx>@GKrGjwfQIUwycH||UV zW2p3@U57^q;PUL(toGd}?S)?wuG|sD^$A}eiuD zQIxHsCklwbD+mrSfPpi6)&YRiBaRO^J}M!F-mLRm-_^;D4vs-0FYO@-XQua}P={#R94TfXenij^w>;7y6AD+GB-WHjj!#7#W|5D?Ch#sc`oNj3mH zE$}{MxQ|lm=m4#7Tol+1M-Fb z!nZr$?6?A$4l>OC`^>rCz~B6)&B)EPTctnM3FLiQ%d{l$q1pU@%N(+d-?N zEu=@Q&Qin^U+;EjjKIwab>Ym-)LbjclMNpHV;DBqH(hffEq<}k{=2!kihkf4G~_R0pLmR7j!64 z`C4&m#?X;_IUM7O2o2k;t>I^3*B@ zjWqz|v_7?4ooqXDgP>LcjfNuDW(WpGXfRC4Xp3kZ`=69V!)5<(9Y5L*k%KE)Kc=9} zSf`-qGK$8r^gJMI@uyW^V{-WhVPoRMTQZbHr( z0{j^O%114h0HGPV;pO^OD2$gm0HD;Y^wp#CK{_~$w%$xJZ?jI17JDVcU^;fCyzQvNWLr(=b0~GlKNb5v&$$szxoVfG)erT@U%Yxj(zGBTM?^(bqA>HUS6Qw7et1px@MUP;8fkNFpVuUVeaxT}vZ5@BOt$CAjc z>X+BYX_*GTimuJjovxo{rYm>6k9#0(w7@ouX8*t4Is9+swaawlzt!FE(AK5vNjb9G z?5IT74R+#{L1kdekHI+S|lyS{>FdubI0!W@Ez8tQ&s0=(3X9#zzPg2cN$?+*byw z^E>wh zMe&Qm`Vh&=A+oas4@M!bw-3^ytTyDCc?Yva64Vrr^j}JC1LQ`x^1*Hi>{thS5wJfN z5_>(0ZBy+>$bJ|TGUN-2ir6BsqfW-nqSo1e3stqfW23n+$zKd3vA$;iA9GZe{4~WyPHv2d?~4dbc$&y-&b+{YN=^kTW)C%r{{!u@!_2gXHVl}| z5g@{wM_p+G#K0JeQtkFbOgjQO_78-5H_8K!2WJu> zQX9MN$g4YA>)nKJxE3{tn|4L(6xf#hSAN3zF%50A0RfxGXaDi}$Cy~nXEdUQyJt2Q zVrDC~rT4%)cjOG|*3U?7$fKyN8Biy{U;bPBPzt8*GVK%ZnHeEQE1Z6zV1U4z*MPJ4 zsN0&Ew9gd?cva%H*=ffJ|lVZynr(1OV*VLZw|dG$2V*$tQw6Fghze9_>d$~Ph#-W0Ose1l z=ZpH`)=APy0GnHKp*MMW5!K$b#)^w!qFo`KS&lIY zIt`mP18Fq-Z#w_fgmjb0+TC}&KmXv15C~}m4XwNx92hf9(Z0IIwO08V~YahG->1}^Z(^@i{snyom2uR9#zA6nZ!}hHLH=ol{ zMX*l)n$8M0w($12bm4j!)_tg)X7Iq2Q&3F-Ka&6&B6UFu?^ZpPzIWC2Ag#Dc{}cc# z)#G4lI}oEk zHRisDO6#g&r@dNe9w4GHH^K|sk7ZZ}H&Tr^0rl4FN5ZxL4>|tj3d~O;cLWkBoO6HG zVt^M-ul1gi^}ay=HuD1?c;jhRU;FEHC^hnJR|p7SNy15=+AG~}m}89y0V+XeblmvL zv-$)@z08{H+rtFRHE=HKO0vQ$yxDP0Zn#PCoTKEwMQwXivbVw@ob|eDE>Bk|!AN=g z6opz0PzhA}xjaAXMu4fczsD2!75oZTfH8o9oKpoXr0c()>sV?MK$ml?+$k&Ekv)*M zc)3;9!uo{$69X*2x54TZ(lj1dYC=~403ZNKL_t(WqUH4-&skfJ$Ldb&UN@b8A{);h z_TR3RxuX`?C1L;V4=7mWu?CXgB6YV?K^x$=zugt52YGzl3(ctSh`$A10YR@08DpnnqTsTiw z*U9w>#RZJv-4leK0k~Em0u?9@s00otuoB=XNY4yNYtZZh)KrWuzp23O)7E7{jlUf` z0%)8A(0p0qICtwS*8cj%(8{_MF@@_#M~Y|CpG&v!SE9LrM%z!B=j)agX3dzbft_7) zWT2Nk)a*nyLMi6~?y}L_Cjo$aeDv>sLtRj#L6EGM^$CkT@UeGeY`t%TO0Uy?Oymo6~QhZ&_f=Kp*R8nuHHtU7Qq%$^L{r+ zc_oz*)L45!wb*@-S&;Yhslp3~FuOIhba)qS1_%x=)DAzk@(Bz$zf~o3H)(x(!l6L* zgzAUjfZ({E!5CPHO9jSo(5t$s0ujK~9|`;QdYj1t807^tswuc%syctMn@m}QpH#m7cN$2Z2#w2KGy#unK?%Q4Hb^fWLzFUR!GiLa|32F*zMreezMW>b+ zku6O}nKDQzRy2UE2#uf6zVZa zeatjS^%oEVRDddwz~O|FaJ_<&3YV*>&DKl;DBBfV5X*7XduR$e5wr^S?&OZ3&jHYI zId=#9@BXQRI$xxgv5y`(llXc_U`*OT{SZL-+>f_rHm+r<5C2DhiQN&yC2BDB?w=jh zKWIw~;{DzDn;-FhM%C>dH)8ib2@vt<*H_~Y7DlFW}t6xH|0}iGy&Q_56V9lUI zjdla?xqknhO}E$A7%>DY9HRnGH{`SzYW*t%JGPc95FVoBK^M?wpji?irwF)n^nvXZ zS`;x000=l70@J)E#AW|V!NM_(fb$P=y&_-A+}20lX~JL3~EcpH#wso%2vC9 zy-nWXp!Ug_YvoK&HqOhn9*GqYKvm&zz)^3oW5pWZdhUG1+VGHPfxUU-rScSO1e%R^ zu9afOm6q%tCJ-nW2d|tRjR?f`8rA@Nt=EsIgHVl_F#C-yEP;w|tiORw&VDqAh!0^8S2*pKRv(g5`X$;LE_Ukusndwx9 z>subL@5(5Wkyji=0RY7b0H^}=MwU2)gbVGbB>X@CLLGl=LRwvwe3_(YKMabZb!*XP zSxx@DQaZOK<@(fxvOvWlDzz&s2|Qi#_(3(6Pr&nAfN-sFD4m>4z6?b8@FOaK2n7d8 zN3RDk0xDduD#f(~yXa@(s9G<^ngb+#R^5)gFs@}asrn!E%I{+fCTO)&j7SB!6xCOe{`6 zoJCJ9>8SVTzz?&FhIW$6!NQ{p)fO03>~lXp{t=BC{&(`K#eCa&?r(3c_Syr%%51B; z4(cDws43h8{*Av30KfeIv-d7Nwk+9s*ta5c@2Wb_d+)j3eY@FwHYrkkh=wUjlmJ@P zM6iE=Jup0Svke0_V8f&}FyNU61~l@BZ4W%~$bb#QFa%rFz%nJ+GC+!?K{hFqY_hva zHrcoD<2G*YgIRqpi7YrMTIJg>_uR6yIHCbUZsaCL>|Q>ZKJCv^5Mu3iFw25Le@(1dyo z0`wx(mU-^p8%mbo7e-G5*yrazK%Qod!C}|hFh#!GTu%8-tAXe{$JByS&)JmJdK=l1 ze0^kUlO+=MGl~5tHls1@zyEaPCHQ>1>tO=>AF9kzO2|ej_n_dyahhM~hB!$Vm!0Ee zYAGT8ELpWGnQ~)(Tsfbax(-)rXQ)0T^)pKbk>=C1J(x7AI5jg$X)HmO-WM900|D zm_qR8H9*O8u)aoZ+<+59RrvV3ahcfOP5?6&3an8P)(a>GYb;w_*SKEe#Ts}FW?VeR z&8KLVcvOQmYCscKi5D=Z1vDDS7=NdGf>iisoGMPEojy3It`^Opk2P-OT2tViyHl=m z);m&$&YNg+_MhOZTd!p~$@@RKeE00X>#0(9c{k60N3YPnyOEuxfAH<$J#@$$)ye4) z2WK*`%4&j9{(WgV!zOVN{Ok<1L}3R;DNU*6*K z7L`lEEDS2QXfTsKm~G0<5(GeF+2Y1cAiiqx<_(|$M)eo~-Zr=aZY!*kwPIsUDGE9C z1}A@0X3Thq$W-_~q?3Th-dc(`NGr$OGcu7*zCKleo=i6>PZ?dS{%>Rc?^E02Yg5^O zZ|EotQ2z~tDdA+yx05lh*bldU9v%|&vnRvKoBsvdzFkN6GRJmk1{2mxELI?dX|iYU zxV!|hK7U?%$A;QrnSz|M8w~|GLRT-W^9-Spm*2K(*VZR|9}0Z%=f1I5v4_%(y>vECbqe>eTEF zxCJFA+2F&*d>x~QBgVv%?BB-^oBmFLoJCf=H0rc>DsY6X9yVbA#W9)jYFKArmTXa& z|6r=$e^-{9V(vY5g*&auE#85XdEz8nX#j@YQ!rx_07e_%Wkw8Gqh0_2X*Zp83G#c^ zGHzc2!0I)?IDhUE7xr(vrBvei)6p_Vbl?2gS^bl#z(BjOeoYmi$@;0=d$aw{(i-VG zjp6siNsaohL^_^xRaNOCLj5n2Vf+j%&unqtz5z2d+izr>>jq`3+vwGkr_@aP;4>v?lFV#J?$O2ub=KX?v!A z^AzqKIp488bYgLLpet& zQ&&GSuH`wfPifW!W*i^3d|$`k9xnshokYUnHaGuwCo)onAbFJ8=|{=X8-t=Vi;Ww# zF4zB!oqsS+V=2b$JMGpVwhA1#E8NDfdvRsM?Qvjzn84hT6){%}xj&{VjNvvmu^Zg3 z;v2m;`4S1NdE1Q_c=mt(4uEV{sIVpHfypT&RX+$=R!+`jAt0Z!$g!sI0KWlf@C^@V_1g$$KtqnICYz_I$ST4Z`7JZ~7Jk{bp`EFqR%ueqz>H!06cSKk% zY#lBdyMaKC1)&CRRY*L6(QZsSwcMn6uz&}RSra%Z%nx!W7%>7c;;R`&>9$rOx-uBg zPzR!AR%(O4zp43uB>V5b%CR(wYtVRws`Jz(vSaq&p;7FR{U2`|aF+_ky(=^KF2G0} zi=0Ii8foXeQ3VcPh^7?4A%=3c?K9^+a`rA@Sa`=^f^9v>=NV3sv@-<(ZDi^8#%O%Zg6oInxkeCJFNud6rp$_N9x1p~LYP-LBg9zS-M zMKr+Xm5%3#5dg&Nx2`?=cdH25hZ}1bm#cVS!LN3zLZrM~JleK4$E*p=m|;M+J?mqK zBTV(f`Rqi6kS4B)sSVthcUKNOWdB_ZV?6T+2Cs?r+5ddI(%Vq8>P~YoWP=F+Jx0J& z!$T?Oz2SJ@B`>z|1^2vAD^zhDO{G>;#D`%2>M?FVjXd3@`Clb%7j@Xwh4MfIT{8c} z2bvy70dBtUty!7g@$!{e>H1?J^jGvr361F2O5ms|7+5e>XBVqqM`u09w zAm4(Q%G^^A<=P&4zLVI0p61@!|DL;}eK!Y_)8C@J_ujPaSAdfvCL4l4a(&FaS{#id zf9kzl{PbU7xwco-W9T;`9m3i3j+{jth}OVoM7^FQgy8LC|GJ;qmKbEm1TL!V&a`~u zH1YK>wS%=M)9$L-|7#`27VNT{49#fbF^9&v%kYRszR_rPmvHn*QmlkXn*R5LFzTUhKes{F}Bd8SI5gR z^_H$&rX(?zxpt?y<-04{{~-05X8!MxZ2U7S82`qR^`2z&G>@JA&v>vn#zBC;`Oop> z!X9h3E4xY8`O4Ym*Q?0%Yd7%H)|gMgV&$x1jP|u9i(vuKIN!wK$7d~dh602D1VDpo zfT4vS4go6-GON^yL~hJ#_sW(_CRNO*ZJ_EPNQfyd;<7~A+QhsbrFFEE+889SkXJ2a z8q9XyGbjuT0C@B?Gxj?hzb%w6GKZWPsMoeM+7W%3U0tDR0WM9ND%zalwZv)kcX98w zhV9^sc;w}n@vy;J3($pZ1Yn{j+)3<4)9ZoUD0B&9avudMm^AXFHgotf{ z>~yojQgSka{ST)j!?QH+p8fBswLYLhfUP;{y?1E)5?~K({od;43A$s#0uM(srxHp11F0%hY zX5iWXAO_Wgeq}(Sr%L-DZhmi1U@_iiEBws1|7m!DMV>JQ=e2!Fns@?$L6a@3kGOFq z1fP%9603z>72c3kGYJ?F{z5(=(KifV^gE7qzqf&?`?ddt4x>2e1D7f^m5<{IxVmJ# z3Ry4!yJJAIL4l1dNV6}A$p*_%e(+tv5@2?HjbDkMXrmAz9zkNP>|P;l~(=MG*$ zzXZT0S*3T3-i>P@%@IcBX$krx$^uK+*!JJmv~u<<#_7Sx8t9C+9sAE8^vDEruM^B?RP7-@miCJ#?f6r@C>06yC4HonEB<>Om@z})EEeteEZsDy%4RjA!2#H2*J2I*{W zd)4b^zVxSrao_l?2^=)$2eT!NH>Ew7u=bLQ$ds-NNH|7@Zo^V7ufSh8RLU8m(MJsG7v+I_& zr!9d9&CK_1ba$-LXgVoDc}T(F_K)(=z-e!MWF0x zbN#`^*yg1yx89>Q3LoBY{x8083Hu+<`$wW*;J#?%9u2x1HY&x~mi-ez_{wKW`Ssug zTCAx!xgzhfy*|0h*%(Dt-*Zig<}76~3#SsedvN{&3~T#OKU;yK|Bpy!SmL@8O^V<1 zi$HE8Fqxw{JnvrP$T4b1aFfQ$In0pz>mzt+7X$!nIODgkD7Qs%+NKHrpCZ+cAV*82 zI^k^jq_AE&p5LNgSgl~aN|TWb`1sKSiAqHkYc4iTJStIqNNz5;k{V@oq)C*Wf8+1oxzf5;hO9;Y+w z!9bVhV1m?f+z;81ef7h5S49zLOv5+WEcRUOtKlhaQ8BK!#`QntF(H&4dGby3T2=CnLK`TD1+0Ez zT4qMuf*F;Hs6P-noO}uZSZaIek-{sfV8n$@a+h;h%@M;g*2*~EWRF%BL3O-fI*Zwq z>^G?zkc1?}ouL`bIC~0qGk|4+Z(c@=w?b6WEdK=ImdD?$z_BSkK#IPs#SBzqkDMU6x~! zVLT3BT0$WDMOhOgZitdC_ihh*+YoWLCCYa7e38v4yGE%W@hyg@;LmCRcvc0E6jfZ$ z-Y1?derjQOtKUOF<_c5<7^fEo+-mxk|0;2NX82c*n(M(Xm&2F?GoXPw5O>{%l4)B99QJ3!jF3hh0O-L@qtv6VWY5j;ayP|B*{zYrtiKJ^D!~T1iM`sOhIgg^3Jq(5yq#C0B z1MKQyb~q2S)Z;PNkHF9Vb39w(w!yh+%Ol4T`~PiaeZh@$xN?p_5GsMSvOjhAif)Iz z{|^;7qK{7uC~$grcwU~hn+G!H?B@i=H{86dP>^H4eVbaxImia@}Z-T?t$zX~6U> zF*8d6r2miQ*(9z3OEFK^Y$2>l`xT%Rl7NyUvI~3`;~TG~)c+?D)#u2O7@jbnE4*p| z#Pfj39&%jg_Vx+@-oC|?=TSZQW3Br}kb|QRXY8MaOOF#Z(Y^?g+9sb)x%1VLnjtG; z#_mAbZ^mgOf8v8Lz|705LqI=AE%s?oN`QP~BQ{?e)Gj$|h+Naw{u7dv$`y`t5l99<$ zd9j#}Or&zh%A4dnP{E3O;d;&_a+}>NoBiPZ?@pQRXoHE?HmGXH^Ve3^#N^KeQkM5e z+k3e*wVU!m{>He*jH;&Ua4!>3yAg&;JdR4x69NH$@1J#6&KU4UzXyYnq;SR^W6V<+ zB==Jv`c zBACS_SvbV!&N2zgih;=r*A=>P&C2z|dQheg<5|F-yZEFd4XoASHOt>|R zOz?L!K=?qRMG!3bwNq$&W%o+}$2*Hj`7G%rx9BGTggLb=2E@a{M@~HHPj8e5D~Jm7 z8O)4cW3cb!-;6K3z_&jJRnRR+iG@d{w1ih5z-__)0t!d`J{KrlH@K*5vIqMKY>Xo}LyUPEM^r>#oUt;O)Y$EFe?W*7fRWs86tZS$ zfYuKrR){^AerMuBw*P#z`9ER*J9+223}&OMrI#-bq_8FXr}XMpbU!KbL;MWyq11=a zmmh)*lW>RvcWeW^THvhlQ7jC>RRj%u-}7)g1Wo?}qXE8~+*!<7=m3?7nbcC=%AJXB zM?3cHiM2QhBE0ft@$U5mW+;XxkPha3a;yC?B9%sw^$!w@mqy}M!kXiCD#?|l?!y{u zU?I2ErOw^Z3`c+d6mQl)&mMo zaQc!)`jBW1UVzr|Gk4`$wNbUqI38@=V%_DF&WXm@+=a^Ad8s$A2aRkauwrK-BaAs6 zXUm+R5@b>hreD?vx=YuOPWC^v;GMjMyH6#$1dJ&1IQ^=4sb>|Ydtv{5S#F9wHC_8| z5$C?O4|BU+!ms~)SSV&pt7v{<@dv^WKf@0{0|9>q0Qh#%wUWZ$#Ox+nZ|(u#C5CK9 zj6y;H5tNFSuki-{cNXO~-TMESS--+}CG~Z&t8Su3VF!RDHFB+U6Rt!urw|FIJAX-n zLIB6>3lX&05&;0?%||x)^+$N~3hgxj&=N{vQHMF!=_UYKae^M@A6zPCRIZ>O3ie-l zIfaI{Y5zIn7(sXVE9O28oc%`UwP}`jlGMhjjpz{MB;dGm#`DWGUMcFx+Y8Y;R;QVo ze$wR_81w(8?l27i03ZNKL_t(wpS7j!UpCPlE%ubeM^t5Jl(;hGvl`X1@4NYbuzkxt z75otNjYE)O5)M#c1zdRhxBZ8+RctbFG5s&T619*Y#$S50f31&S#rONjR5%U2vZIxi z7`QObZ=bHL3?Ur&xUq`CD>tRVv)jUha9Oio1<27~BGf{$3EL8vR`>UMgd8hqk_r*0 zjhF+_zfh)k_W9!bU=7w*=P?(e*%SSbKtsP0ftoR6m)M71F(ZPTRW-4$3hIHV@G*&vq?=>7{$L1|WE<)H zQ}Fv27-R$E=>qpU7*O=zSoMs=qX~O$j-dW|VDg6evt610dv^9YaU_K4o}{=(j4JXW zy&i}5jFPX_o|X*5=8^)w_nC`nX55O!UdrtvLAPm6UA7G6Xm`Sf+qJ!VBTV(ux!fnO zgg#>%F5ef(qQg0+pI?^Qf5+8gNS9ENcpGv3f_S~MO+}B{X;kEmV)pA-U8lakq&(0a z=l7<8ZegFE9Cv^{^eV^U1$5ut>7jAiGVZ&U4je>bNgt2ZS;3;<7yp54Ri-u9z6lbp zj}f1a7n{!`7@XHuTt5Ne{d2s#bd8lTRlL6dfR|$Dtvod)g0zCp_xc3@)G-4#@R~^D z)D^R&4*@GiW4wTTjp#z{m;{^5^6%H^G<5y>6OiElebpk&d{Bw8PN+GuV-x#&~sBx?Dy8>!>C5JHan_eT50&+LLhx)hIt zjP4L~SL$$dkN%(p?rI^fopIMo>vsY+18&|A#}mFUp!>BX%Mq;~i}6}vn+|~Wh)OZ; z{vk;M{6K-T^h=fWltb2yCQ**>c3*$i*Yy7M(-?Gh)2mCknlY5}0CoE6`VA(&fgmzUBY;NACJ zSqKEYYno8+Fho|3@oK~6TP$i@85b8Ja#%0b-N-<@wqn@3of^={b^Yagn^dNo4-mQx z6^0im9-O&j9L~3PN;uS(b;jMHPF{iu?0*DC8B3-PLw7`=>;mOiyOE5R8}{GR?nIZe z)O+@lEZm-_F}->Nzo#suH{t$z%R_SBpE(+g#zSs_9&*`B*!(Se@EE^1V{Y$B=zb2f zUZl=<*v)sja#AFnie#L|TgfjR#E86!i15*^6UWKgxo8ifi9_V%2_8WdD-!H>01)yd zkgFJ_dt_<^J9#OQ8^U=ao=a0E_1=3~DSR@FPd@<>SlbbRXOCPQ9StUE^R;Lviy{3^ zE3n=~BvOwLrSp$pQ4|Uda7K3I0gSrEs2;IJRW2IA7uXt67I4A`w!?badj7JEB4<@{e9qW?EQJVF^+`=ZY$@|&39Z6 zhg{iK7tI6!zk_d8M^{bm z2^;n>VIQyJAmOyLCe$S^>rY!T0?;q#7!)7tN=FgO2^QZ8wstO2-yi~MH+z^YWsf!w z_G^YxoRS}QfpyMdpjp{dj-n=BLWSd~APZ0vGOQK+u#KwYk(n7YX7pmTS>`^`u@PAD zbTl{Z3dyf+#{T;SOCoH*{s$jh(eyQj3UsABXonkdy%3{^{r9U(GGzDEznIy6a3B;d z!odl2C`cdHF;vunykK(8mY(Lzh-!S|)4|`tEKn$Fl2^M1)nK4$P%YBPooPxhBV!fv z#FqiWI=v^@`#t2AT+;qg>GBF=ELO>uYJ=UVm~0%FDFG&u-@_QugKt|@70yBufE%4y z`+39M+fPYO51cK)3{`0k+Xi2ZZy?dk*5tCaoX zm<7qYtzt#t(@SJ6O!8``UYJ7OteXD6BLJ7xL=TdC~&}eE5-Fl!wJO0)ES02HxJJsa!l3rBEVc zktN5fkzXFPjb{QtJR_eqfK?3z)Q#vOTyiGlfBE?|of$J`94WG$fb&!8y;?dghYV>E z)7U?i1?x%Smxs*%UF^Te`zL{W76s~cJdl< z4EvE>c;3tk=r)m%j|Mc(&&OY&Vrj)`C1|nLI$ZnM_kLy9`~pWyXU;DovbQ;PqK-?~ z3jK#$5m}OW_aB>RI@P=^BNT}>2sraAell8R zm5MiGb{5?Oc4U4m;NHL788hwxJ)ckS2tWtP9{d_}d-Isxd|BZ3HMHRU$pnCi8T&>mPK)9==NikzTO~$Yp3$78*3%^rV3=`K zgEp2S&`SWG_jlk%;Vl3NFCdcwqAAY#a6AF;y>NUTAh$5+ZR?aMMytVY{eEt-a4YjD zu{9X6_5bmk2^jgC7IkG~as1rnM78xYh^No3N@fQuw5tSmlY{RHRCq^b%$PA5Jx#rx z1CTaMQ$D-#^t9)eK^9V4vL3WEeuv7GpYF@> zpJ&#Myr(=&Oq25{igX}2!n(T0mp11~q|3G)a_vydZeuJ0#3Gn~7RRsZbT{9`vB&HH z(5&Ot_bIsD`!>%^|4m0K$T^=dwCCS3?g2fWmFIUt1>pTkFg8K=ouRIa+5Q6JvS4`=unjQ;gU zc>2O6A=Lm=y4G#ad=^4wiEYXRFfJ9Ix}ga#{~6!62 zC|HB&{flutAWGNDB(cY>tV**AP(A{{X~aB_a)7z9USQ>I(iv0>C}@V}Xsh62YgUAD z@o#pr2)&d$1M5N-t8ACwBs~T$TC6ItTcFc;93{)Me&!h%c&D<8N|X@;ZZff1`DfLF zfMqR=_Y4M>kI}rgPuC<*8eniGmi`0)G%YF{LrnaT>qN0n0v8Rg-JlJ@n*SN77_4zq z;i3UEKGo&=o4?i>Gma58F?D^QNS%qa#Hnh>bS3mCGE6-%=ieS>4yYIksIP!GAknOG|7`-CothAx?eZJcgEe|UadS=arDDuZ8L4zg;-K_w zl$b9ob20&EC6i5B3BuWifk)ac-tPka0THwg+S+&i5~u(|#rUG@q|919OEd45(6#_$ zxv)Zdk08065yhPoyZ(ciCr7}$T#?lFG{^&v#D$=uZ^m`88Zxywi|p97`G8v7e=?T1M0!J zbwc~IBJrO&{-w%$7pCbpLwZquIcNO-_%7UjaERaiozk+M7XNsu@C1}< z>_HTK7bvzKl)2ddzOqa28>-g=>e9wf3_9Vg1`r(96=5N?h1$9P%l6aS&CS~XLI$nF z<^!AyogvwzrsmMNMT-vk1IMQ$`MbNRr1Rr^!6SfxGi4_LpyP$~TF~tpFEtpr6iK~% zj(5)h;QBhMB_q|h{~QGT#dpBk&X8UZ*4i5WBg*cE0$5hGNy_;JnIdp&Gin>_+;4P} zWH==`HeBC?zF9-X>^~Wxm@#9<31GxVV8zq8O`U4~kD^Xr?I|>F-fSEfEZO*0+Qp5%-;mlULF#C{`kT3qiv?R!{|!is;Q4e|vwy_H zGf`eM7+AGYxLu52?C<-@4IV$j>l*<0q37-~5eWFf??nrI{YkU-__;l#gr(#&i0-J4`Uv{9me~p1L1=E_cMT4w%f{ zQKP?y8hEhX)$tbmE+tRixCKXz$9p$;@7gZ8;|;pzpmDb9KPxWcY4m~kk}22PZBNUk z^?x85Ofv{jQ@B^AV{ai*3_(MKv7ewhvi%S04n5%st4hig>SwJ(2m|XC7^oh*h;BZB9l>x9OSiVJ>T7_(j6d@u31TcD z8IcIe0HDaK0e&=K#*7)KgpQ5Cx}ujZY-0YOGI}r&Qd&Dgvj1PnR{HmtWcc4W>3GuY@3d+tYkrgDJ0~t1{~0Pc$pBaqR*bdT1*|x9Kw*P3`M1>}{)-EI z`(ts76YraU3Pt$d@3A4ut>6i_CznZ~Ca^}^V&S*#@jgEQfV1~RU}d$kWs9}gy6kgL z@TbL1-3S0KZlRVTSh;s2i~x|`L}JE_87BjUAqt*Yqo+371yg-D`yaeL3ZXLlm&o_| z^5EXnk(V}zHeBQpRa6M<>fXjlwQ>A0GHipL_c;6Q!uCn`PP6kJQDdiB@SWm+|G8j2 z&j$`aJ{MOBbrrdGsQyPl>6s5$wt%qo+i=GzD}`3f7AS7D8&nI^xp;-iXq650 z`<=OfNFG8|2|ndKf=@wnT3t2;?|FE;}S?E#~ zz`*x?9|-uzjEk+X9ro%uBXbSU;nW0;NQ9sAxInJM3^FMRQ8nEoYzO|{4Pp;JS z8UG(Sy5e6CI~vgOYR#B&2sqf+a<_u*yqJZZfG1@;N_iMcWPFq!BdZVd=KrbeKQVyi z(MG10$kUI4f;2kv)Xerf_xE5w!8^mr)xh2j*e6$GIqq^atk8OhkQdh=0$*6FXILE* z{>m->@Ip*Eb@2_Z{df(KiX=IwbM)3 zt?9(p$VD2=AVw=@U0Wp~9q9mTklT&e%UYZ^Egz!U^Xu~(w+s*}vZFnUtqah03x>>? zu`lGqk6YS|PI9cPSg6$cGs$2-p<^qJ9!xd=6Viq}Phn&BFHiHHuLqM}l)fUD`lwMg zylZ~3$*Z5qaC+a*0O&4?{NQTU;iwCKH^NH;t^XV=onFl+cP6)Z6ph8EM>yAj_e~d; zWd^W_ZfM;;xN@P)erN)lHGcpAN<$^SE5gbiN>^$;hnvRS>XWA;V~R6&5u{<=l(%hz zAwN_OP)AEVQL*a-tq`>Y}RZ&T;)t_+I;x=0a2*5WQmtD8-DoEq%g0h2yFvxTZ zaC)Cm8JXd2#xU;vy*)Yj8ohDm-smrd17@_0*15lbV{PNnE#M6B9&(W%*@Z}lc#c~q z>pJ4-CZ|*u$Q@TQjBR5H0NRd@#t(EPvu{a=n+$+7vRQRiK^gmx4E&DVdwn1+3*!er zWAl<)mZa}?34gY=7uN5u!ump-RZ39XDyMb0zsq$vW$p43V+bbXFO{3%>t^~YHwbXu zLJ=;iD182KXUsSmWPW{{a>|t5Qs33#+ehEoZ~N!&j$|A5KVGE1z%3P|p$X92U~J{w zRd29!V!g8j@4P>}dmZC&w3@?_WCPrR@C}22i_BO+qOnnayRu1kDXr@iJI{n zpLzfO$mCDaftluTGK+y8bxSg1#;zbX0-M4|`%Xuw5TnShNM}s^$3mCs;r%{BS9rh9 zu&ah+V+Dzl^WMl~Qr;Y=(G_fik*s1yf`|I%?DgF+?d1({6Su+dU57aDU)xKHp|mBJ zl0c7a;#xs2wOFy!)@q51#a}PzA|wMpn>v^li`%v@cp%F$2|zJUA-Oq8?`_AWvdx+Ujl%S&cjmo z6i)>X@d@<`wci!ELt1hx--oO5%9RrAlmvfmY@epQIfnHl+=oQe~T_Db#`f(;ASUKHhVa4jY zT3fnbdEQT!_pgAJ1_PHmXaX~4%ovZ|GKFnY%kNdic6RdV2&@0d)TWLec#P~>H|T)3 zH2jl1>ga?vNN$pue=7SQDZ^c2=geuV1ZSJZX4pl&9lH*&SC}^D${hoExr}uK0ulZN zLlJ%hAmHOgnaC#o9)8y_239Rt_^C?=7ywXq5lQc}-ZipnZyfPf*hMV?);NzRIRIE? z`cIdUg~e^TY2Tn0+vuX>ee;TqU6nt}F&YD50MHr?{NM|hyHCFXknSdCjwJP$ms{uI zQ`aH>jl4OI|FSNqE9U(CCUyN^xuJkYyFmcq4m7uXr-b=wK5z_g1U3xnIh&H&2vwx( z(#TwTsKZWJMV}ZY;yxyk+?Y51c5{5c?EeJm+E5MLL6MJg5Mb_Y0POAA{ck@50&0p@ zb|Zv6tqeu}<173>8U*}{SdPRxVfV>u3c7*$n@p=UXWkvinEXw9)#&X0^w6b=(o2%H zXwpt^4k~HIk1s`9L2iVRBO$Rs9Q|kUX#*ggkl%PS;Fje7I{<*haUzf%Q$KzSX&oz9qXXxRB%`9NOt;Q_sY z0oIB2R8Gyc%2Ua)$3<^BI!BrJkHO)Q3Hs8Vv;VZlri}CK0|zk(@IV@d!^W{|m3xw( z;-AO+H|}cO%qAW$5I1V)kdlZ^@u_TA{Z)3eip|xt${vvGFY@C15W}CVtYGAJFHR^s zjca2USqR7eFjT6IB0i00?!wh-K22F7)Dp*$2tWR%az?D}`~=;Kx@It=UIIXK8}yB2 zG=oK!PnJOmlrek-ez(Hq8kZ|n2+lv1n-5SSOa>r@fAsTZX=lusaj@v>afUVm>q@Vq zrQ9U7jmR;Hqn^>;k-UFWf7}(hAVpS76X?E-K*YOCMHpPh&-)U5AbS2D#04YxN z{n;4%czgsmueaB_{~0$G*!&dmBwpRU*lfxW=J+(DzcQpvU0X(@B!su_hbECiK`8r0 zpzM&-2$dn+rPsBqHwgy&BuNGs)P}`?+Slog5_KhR6e(!25^FLpq2mkZ$+!VWoI*R`CXbhMiaS$ZgpHXK;VbWNdana-DT7SpP%-vxnJMhX*hAGF_)9egJ1>H_VLx-0 ze&58BGr;E*nMLFt@jRt$gmpg|0Wg27_-cQHJWvTGoniAoMd6bkn`~xBqCaL{x((@m5}`xa z8iwgOr{2|_)PZ1spXC@LvdaW_f#Vni*xUQ_K-%c>kVgHa!Tih(K00%82%o#QT+moF zK3#^WmLR(7Ej~Tlc)AtqWpk<-H*T5y{H_p2Vvg)YtaX{zlV~$#jmPA=W~b&x08+{U!iGE-{b-0Qi<6`fmDf z7!W`(|IZTuP7iYvn&Uye%Jb8V z$gy@OO=tH+_`R=Nd8{mKE7snjgD}iul!L`kOVI`<6gcu@5p4T$BabhoIj9t%?M}uk zjf(6-Pax~W#nd^>GGj~3^?KUKTAF)9B8ie0l6c{0`r=>Z)HbzeN7gJVg^x>d(#X#E zDU;f}001BWNkl*izK;?OW96Lmvd#Kl?wl zmvaN`un3QwhtD;GfLE|?9-qc5fqs0B4=>zU0YNd|zs>C5#=j+=Je$x_tEXLJd~U&=Ly$Fa_%W5S&vWWjc&ouE-TdHNnM z0l-I}+UdWkf!`cx;aS80P%QvpxkLhDrvoUPc(O0DEvXZ%im$%^7`1}tXc~YS6EHC= z;D7krJ%yPuw zcT7S(BTmBXEft|wcyoid4W3oO@b3o!P5^UrF=K{DX%4{9cRto&Plc<4D5o|$6&^6T z#F58FEQ!z|(geES5xTkgzk3X1%S5K7uz&1N9-jWnjZN^hFi@_$E%OOf@=l6i{9!5% zuHzOI4AS$lVgs}UsEQ06F(!3qwWXbv-!NfFv|0XGoRBgDtO-BHbbrb%SI4q!KMWa+7 z(Apk0uk8x024DLlr(7}Wq!ad~j{Jc@T-aqS^$YS4e7p&&>Lft zu9ZMfUF5YRouk7JxYV)L!(lPt0}|z!u>C_+g6OA~Zvudq6;$PR`PI(DoS@|T`tD%m zlP!^8vtS3pMv8Zf(Y|!LV^1nMKD;3-zMk@qBeC+EXDWJ}h<&ytT^h8`? zt!hIyj7x(LL=oeb(`SF@Yc|U?afk&ylky}n84NtCMP#EPWF;bTlX25Bb9t55RorDo zcz%J)YXJE87LRMxW;{WoWvdCym~l{;$8$D-Y*$niJiY%ZP*N&4-1+HX(qpz6E<5cE z-8l8V30C1Le0?}VcEk88O4xsLUJ->?>bycnqY`Dlz03$;xwymAXu z`uzSL&kW702XU|j!`Zooeh;R^xtH7V$g5K@|D^ zB{+I)^Bk44)+@3eAl`Cen?r^os1{lYo2~{C&Rik|Wx#vvaEXXIi51XlunL!21_)X# z5ajRGk}C_yUVuuZ+~YeMpC>!GQ8OB{t}IES1T=nyQ&BdG|iog3F zY6WO~W{FDd5Nu-qgP$!Gd&Z0r=o-zMalcUI#%vrS%0AI|s59Fkd8Q5{z}cuaeE&KI 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 ULi1oC2><{907*qoM6N<$g3>9UX8-^I literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/flow_raw_images.png b/cv/distiller/CWD/mmcv/docs/en/_static/flow_raw_images.png new file mode 100644 index 0000000000000000000000000000000000000000..b60cb9af087ffe69d56f9f124a86e4166c1198fe GIT binary patch literal 1515531 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

8}i;3hwWGPrw&D}jVB$k%qtu8GNjC&)LO1! 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�#rZ#2;4rOio^RCw4Uk<(3D@wY^$DG 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%0Aj4yP=Rv@3T8$jE8-1kL6&~k&A^7VsA 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 z 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

-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

Sl{v&|E2~Mm9Tmw&uSj^3-j2#3gV3D&px^U21JE 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

$k9t7E%kn`1?eS>D;F&s?CxE%K5fTcQC>oOW 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%0Dk}xlTx5A5!O#Xo8q~9 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

uu1m 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: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

;{Y1* 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%0Ac}$R(f(0 z`km_N_24V<@^?#;%&#=NN;Wx37XDUNU?d)@(apnYF)T_Lc)2tZ{0hm+n{L3BxZ;wL zfbt~inx-HUP-K#23aGbI$hg=7 z9f143@?}Jo(X!8LDh=%hPnJRri=@@ys&uvv=SaF#k}Q(Z&b&0Mq-p|#A=`JL3hW8b zobE%?;8y^R2rZ3p_iv+88M5vYU%Mu)L-ECVyL=nJe!AIoi=YdYQ}TRp3hAG6dz(1+ zIn|eIs|=BeNkSsVA9ax~K#oY47*~GC>hB*~o|6Ot7(iYeywy!Jet$ z*&4r?-wP|kyEl63M1%2)hV133x<7mUeEnjE6{Cdu6(w~dP&#mT#Qq&r-NC=KRsfl< zsTd3wSa}mN2)H*6-oUL4OYmk|vtZ_i47Z_30$@y()|i>#7cXNyA}eg8hRp;vM~tH}V(O{_ZN{&xPvC4@L`ist^mp zs%m%~X3d|abAB_y73>d{Uw7ywCh?=y+>hE`@m+6Pj}BzNdw z4)0)fS4+~M%4Z(OnXEGrc6`g7u$-arv0=%Wwvdgg+09>#E>Snl@4nI0+HF5>VVkq3 zf)l>@rC4iIYqMu)vo2<_LbKdE({}#-{>H`>g@sAmoKt>AV9C63xbBouue&*>xYCll zF0|cM5Bc4%Xk=tP@2zE=Ghv`S7`}dtJP!<4JZ7VAuOH4`WxB5Kb&UpngL>^uIWj{7 z(s)(-x|y37i&#bD`A)bDXkcjNm5ydqf?o05^^#L-pV}fvFu;)^tE2`$DH@E5@myb9 z8>oq%3#mKSJ@dKfuqM6AjGOkgG$ z2+0sS>GqdI&~P_OI*mTW1-L`pInzZDX%ylteIxn9w*8$ndiq*x)s5Ll43cB^p&CR3#Vscjw#4M^w#@APu z0Sl1diFNafCDHtKPfy{SB-ypNrGNYVHkvAimVP*u*f#QmOW&||uy&p1;4p_9wqVIe z|CptMa<*BeTr$(bkCz0|0p>o^q*|9`z;pu*N_M?}&Un55v=O9=EnTpa9~xbIOht!2 z^rUZxGJS0eWfC6C{lGN=p_y$lL40z0y>x(*MtR(07s&m zxtAl6w2#B{jJty3_0_oG@4!v3X=oxoTbfB|V<0slAO%`f_;#eVTR&Fbi{Xe*4Hq=O zf8scz0P5vB7Y3lri+pW+mD8EDgO@LyMTIdW-qnHTP$hsf6*8W83fvTOSf zhD%}s^ zP2iXPluY|~J0L3P@Rx%F%N?PWRsBQ4T_kgvj~$s*DeQB<13QADb)DVdz~h(tZtsLRuDjcveWn8-LhItt`anbK*1y!ef1Wp4g0$#)MO&MltP=E#`@ zVs^2xPcoL74hk`wqR5r@yT!T7?3h`OgTjzd(xzth(_<;{fj;iwVcdMBO(2HQPgI@V zZbwr9JcTMVOrkq_Kj;cR7WdO-JZ#s>jZ^DQS}}9Yow{P`4O(v$3@=H}MlTg)1ngk( zp;)GB_#^(U%YCm_I{Jfa(7q_&kX0h+jVpwOmGch%6@T+(QAg2pmnttpQY93&fzra!RR?1j0j|Ehf*}$@84) z-kDk|9{Eq&iQb#s`1-Q_g7-(BJ;lnQDFoPSVF7E$W0@as9J0FiwdeALaeLu15NHAA zIby^NzI%VQ`QQ1OaQVji;YpWMt8+b@y|m~M;)zrlvt6u(LDf_w;`wmM-iM2$mG2XEc6Wpu*>vh? z?fiyo-)V{m3q;uw-!z$~!w;9=(oGNsZwtg=uaGDUBhBw|ms9Fb`qiunx3&3&L|6(* zx~Y_;UvdztPH9r;`ds&F+bj}_&#OE$>LssI3Z%S8um8p2$Z4eVGG7v1{3Az&O~0{q ziarI_#rx2s{OThOMj)zI=IM7)=nQ*HQrsVXt+$k#lzV^rA{-u?yT34#A!ix9-@*6K z;Z2@$d%->(mVHAnpPdFL3Lq^9za_lxJ`b|vVxp5D#7u%qtLh?n1UkVFH{2&kcD|$T zXLkF0SXnjUq$Scvj9@?QtjuT82wl>*9g?l(xf?lc8~5s#I~zlCb*^VV+UoY@aUswW zZLZzB5n}tc@<6yP);#ti{=p0XCDv)%s^3T5^ z+?5FZNBvQM_m!Rf@hRpNe;4uvMNp|TQe?OcWdM8_z}@DntPLU-61NvcMk0pIq^{^H ziN_*e?nbD=I4EcwTtY1t5evsw&#id(^z@`?PozW`cQ6#;uqs zQj!7^_3=t9D$qjWOA^Gf1+M}5m9zbub*wHd6&njW)m(eZO{P{e%+vGih<4XVtxJjb zBDc>_OE)kCV|R(DC5%;m{-K9x>QU1+Pq3OB>D0A=KS+9gn#n*sdBLb4xx~f6Go?iy z;DLM(g#oB11TP-fN%)4qG~@PRI%jfpOk#Bh#jcnmU|{8<@7Nz=BpfkMEh?ZBPy+)4 z%AHshwvI}Yt|&?NYT3wfEeyfPQVg!{X)a@@!Lq<9+dsU^jR+}KP`ZPK!EeL%&7$jT zDxDHF^PUvOwZI8FDg<59LpSC~mJ~-md11m-pFXH0cMAm&N+sdON?;C`?VuehfCbcdZdmW~#O z&(B2F$1x02M zpMALE$>U^@Y0n3fl{e0|wzYoA3rACwO=YkUI{Ibk(R?}-7(0_di&gAd3&G26K|%QD zvGsna`dCB6EU?ji$fmo$K* zS9cJ@SN!~dY;7h%z@w$tHh;wS{BY{j)tCgZzqa|>S)w3jpm5r`@s046FefMH>XRJ0 z!Y&;ZZBL6dvl~m-o}1@OC+|N7e-H`b?^TsSURyHLy&}7#-AqO$Hu5^woPOFi#6j^@ z@hibw@7&FJ7B?a^XQK9UghPdxc%7@w@lmr_w^p>;HanFJLdB}5F{fmpYB^nTb%1wL zFM2p6X8E4e4Q7LG+p4Fgl>xD2_3Dq;tH2WZ>b`NtshY|YeXmz)a{*Z^Tokjp(h~z% zo^!>ntK9X*y)l!3Kl%TE?Yds$y0LZu1o7J>--KK@OO$G&Qs|3OS|$Xh`>9KNEDZ`Z zLnwqlU_Kl}VR5TgWaZmIy)njac6e&!%YQWIxT`7v>){gC5d1wk1h3 zyWNdB{ODf+!J>FtkDpOxb)PVatBfydnpq0%oEQiR%N{SD5xNG?{(cA|Pn6x!X`2JL7wHQM@g?mq_h6yL%Yh*gJHyMYdqm!go= zIiL(V(oFD5mz9Wx;EMtsAEi8!Z4c^Ab`70r$X%an1B|r|K>qnJ>vRhAL1lpAtijn% zokzQ$WxobUqY~=5D3(1_dFCs-=by#$802u0r%ljOsC>Tbp2Nl;su=4r_`kZ!!~yXZ#3K`W~y~|{ZGn9 zOG=cmn_ZE;|Ne!cASL17>&)h-^D25kuDpIAW_5O*RW~o`m;E$#@VQ)AcsT4Qc%0H7 z{G-c>i=Fz;Gk-T%v^H{b*FFmrPlb+-JKHe0duIoZ{_$e}1MmY3D){D-S0q0|5#;5+ zz5QaACY#2B;#yt{-e*0QFKpte#Ky(-5kZZAeB616?pXFh?B{~Vx=L>JTw(1Jy$29{ zlS?1_%jfA6ORS1gG(%oz9!z!=8;kghE?H^yZ1S1xd^OMU3gvh24etE&7rg#Cmv=`wK;#-RE*uFDK1c2wkghRj&x^n?(vPLh{}op8wF!-p7u)KCUBkzI1QFz>B_& z5Au>v)8)t|j|SNTAX$K$$WQH#7vf;nC7NHo2DGgrpG76F^P6V z?y026t+(|cl>2!pT(3mM)sDTG}u2|EgD|;ME~aj9M^GYF1g2b zIZe-aeY#o8<+9;SfXhyRA*J5T+)IYwneDM|KFsojJ!IwQ8Kwzk5Lumk*_kT9ojO*Q zz_1UQT|Fh+w7%pK7BWYUO-?@%wp?s(>Cy$SB05r$U`C6_958s;Yw`Y|k+ z6qZb4UVs%gX7M>Eo;zRm(bB9y2DU=Hm_Q~J`&-PdwTUC?#cY0W28U3P;ssP3EFppC z+e1`&Fwv6ahOc$;!>ZdmsUnBTs8DkL;`Hd!SDt8f&WlYm{j3Jscn@OaK@Sf%5|4vW z5S30gHt$)-ZLEA)+!qPp;>r+b)L+d(;2eaVl!@he&rsi;)qno*Y1PCGlY6p59a7!bxlSr?)PQ$9K^giFG zH*Fs2fss#hpCA{~mNz05rPSx{`5%dgJ)Qp&4tY4g{~u4^Xl3L;Nz_Cz5e*OBNg9K=TK|Jl@p3)p1YSMsg{(Z;C?;#qx z3%!A@MSy|sQ4}#FDHPlPf`;-{qqxWUoNnJ-!^J2~ z7VHTvb0BXr;1IL>d0tyUuIOZ%Z%#JDJ`;L^{Fb;VeI)1(il9OGL)CdkzzbKxGO=ZL zJwfNZ@tO^U%zqbO9cZMR+q%%gql1As2k%pS!PsWIl+eZd`(znEe=)j_w$H9LOx{8T zb*Dv$9`khMItMf~*h7a6^yWvUymVo3TfKVDd}%~V&Jji{BMeW67|`(dD8pad1)&j1{aa0EBZC~+(exP`)Y9R$T<}=#9PiQJss8D z@v*>?>fgyBr(P?`Ft>bqW6LN<$XzYllSZ+a~ieuWoCG z5fiayJ!7dz)(g%D#X`r}XW77&&Y|B(32|Fs$a<-?Z_1a+$`jmqMvvp^A3}aLJfkb2 zj7)?76f(=R&odW2j0&=quT?0X-U{4@11e6fMr%g32BKXf*V9F_#(hEyP~ZT&!FG%o zDv#9{#M9Ao4P9^Ws|{>RQewtyW)i)%y;)D6=3I953$#I^x<23x5k+VAp|`-Tnwl80 z6d9Z)5`BlPPBzEm(PM6%WjLv>F?%nJjKqhEK6&fYuHHq=DmvUUwZ)n6eP1%%)4BC@ zk5NtSH*|%Evk>ptVn}>!R=OuSmVNK1kVVbswCm5@hNzvH_u%jX@QiZe_9m$$T#=Zv z*FCi}`_4I~Qa^LHoFT`dLQ=Tc%we_KrF+I}iktlov&OIHE00()gO1%k*XO!g9K&zg zIQ8ZAOKI5ED?^J`&d4~oxVuWa{~juQr)voxxO5tnr{aJTfNkQXgcX-XUBdf*Vc5%{ zvUNpyZ4PX7)>HWsMc>9_Rk;}#Zmf1tO07hIrxh@L1C;Cjt@A zJO*KXd=Vmb{=xqJ?_Jx1aM@`n_j=;uhi~NjHxLMzXXyV-m3Jj2N$tXo$PF8aZ-dW? z!SCHjf~Z5nAL(mnDtjcQrhWF~Ll;J@LbS9>yo#C$D|sq_sO$-C8bAQs+pI<6$Hic^ z;Uy21GjXOGrp`T<%0*Jitc$S}oCINeDomMJ1`?z=DQQZ?H|HE$14j~H%sehH<$K>Q zajPwA$4w2w`vh&#=a!Dz2S^`6K*)a>@=zO7FgF}` zG3!dKdR1qOkpU`ok$zt+)1dqF0NABaSeCeUX|~Q&NJbSdEpY!zj+MZZ*{4&Vm+w*11HM6-j@}nw53&OiJ(zO6i;h^wSJJ{kpvZk3Pdz`)rUnWF{`aoy zBK{uytpWhlG;w&qFL5}Ba^L|0zx|0*ae4t;782)F@TNnmKf)Eb&8S}3sF6Vq#>gV%1rNrW#`aq$AG=zW$%X_IYl?p>9 zOWi{v!SsZl6`Jnvl0gj!aK)>t4)2zRk_&R`CB@1AiW#b4Wgse^83S-rFC~nWIgEr- zqRWw`yo)8`_B*ATT#rL;jhofyGJZU%Fsg^ z+#93?fvi#s(fbe;yUqLwo$Og813}Bme9XT2wJAx1S}HQw4nvBQOQHl%U1J0@k|3~;kKQ<3 zx54dKj9i;MU(x1p+HZ7@w744G(-tjS6_vA(%5HE1%B-VV#wM(TP)oHw~-eh|{D} zFj5CxcuoCRzl7QFwn-|ibK_IMIr)+3jWbyGn(Qggv#RBt1qR^2-TX!|e{s5%lU1*+ z{+!AXp8!{4Q(U?`&Q3yB+r`xB_h|=zwFIPX2_}V z+vmKzrCH?(*jvV6&F^-QU_yA!$4fCS35Ujywbe6*0#Qo!tM{QD7+Q^zSpN@0zfP-SNV5`SO}C% zt(eaE5Z^(McFi{>qSc~iUbpWiYqolo6R}qhBwji48dl8b;wY7O&=wT41 zwHFKu3-{9IFZ*WaK7Fc?(z&oSHC89m+T6(9=*V*DpV4p4c~7sJaHj*4u34i<*uQh_ z<6|fFKwE8CbSm_BvFoOgEmE*$NdISa)CAHxlsEICHfDcCzq1b~=c|y zn(OkrwwPs$Q-OkC9xfSqZM{)PSeX7t^Q)3tw*rpap7%}*5PrCfms@d>hJlmEWnYK( zj=c^JoraQ8F_E|JGnUtWEpV3&T4-TP3qPA4CtOnzSPjvED7dQ0|PKJ6|JrJYx{xM zsn%&QWdsTjB^zt5gD$5y#rahEk7d-boQ=mZn?p;bG1FSFPX%$AT=Q}SBoJ*gMoqfR zD6@Pp+Ffnf+eSgawYm7O1rTQ-+T4|7&PANL8G!%zwDi2*VHVwy#%!w<5^Ofcy|rMW zp;b|{_3=gaPmBg=QJywA%#LLKhT9~i-+r2%QW686hhh>2BIZ&P_GhHG{eKZmAEHE@ z+m4Zq#oGH-jyT)D=Zl(2lT!a+yZ*l2pA6E6R9Pjg)JHLSby*p4@{-TzJHN%DD4s^) zsIU2pQ3F*>A5>1-xpmwI64y=$fKV=;c6CbJBf1IHLp0;fFF^YI_gh8n;!^^CNaWn=Y@?K>i$N0;HPtYF;J_MlGndD~ zu4WKUoI3H%<}e07^}+CU&uSl797`hs0%37&9T=@$PA&~|eD9dcd#pH`&3RpZ19zAu z{k3;I%wMOf(+ADEC#$0e0m)POi&SKYt^#90AsCpF^d)?HR}e3}hRD31eSUj- z-?#T=T;=E7J}<$Cfgoq$d#nuQi)Ua-Nbn&cn4AFIht~D!{k=`? zy-of-B8|^DsM2V5eC_rt@;9UaLF4K3b22zEQ~?m*)l}m2Vz2`~s6x}AfI86P`NL&) z+`UKx*mlmySwhz2RGvJ}a`L`Pa;EhZUjTko$Fu%H#tL1WoHEWRnG{%NPN=HsRis{w zvIYI%ikCiU_e@$U@n0|oP<_M-s@|aA%DAY)Ir}kuvaQXg)g~qI{fzI2L7@|{W@_|@ zr3MC6xTBRCFt1pxfmPLm(YIzlStuF_KC~-) zG12m5;EU&0YzJ-?KGl?EPh|hFz2RHOPv1NLJ!bkZXGUMx=o!QxZB52}*BIL?956g- z^bhjEX!x1=-KPQCciK2Bia;| zuYfl)YAU&B5L6Rsu9e-UF~X9yl44B&?%J07A!=iCDyVn{m<&!QYE>`R%=UOlfH?B= z9b_!(!vLrGn(*PRko@!yPaJ)&y2T;xY#j-$c_nSY=CoFX7Mwv&Y1b-QU7%ss?A^q>0|CsfNX%KfpL1`A9E| z=R4a3oZePV;>O?KuJV=^yxD#RH~+qJf=HvDH1j@Y_Bb<*VramCv^~-*F#1r56Bejm zPsRyZ=0(R;A4^H68ivsV%!f_G?PCkGG?-|UWnwru-m?Y?a1!7B| zirh>HR2Cbe#R8QSnN%~WR7AmOqaghmVasHCf8kKrrU?$ZUs^inavp+iLI%;Ev_IGh zvVf_#z%QzzOQ)4#g?=vWaROqALsyZBV1=*LDuR=_PdTZj$@bB4ho1heT%sjJ_DX@= zKVBLuZbi-fGVmb07_uFY^aRB-nuYdG5TYcnQkDggqdayVGBB_Sghb(4XYejg$x?9J zi+C&F*p+OnMB=Mwqk}{-^aB*?J1#D@#k5^jPfxtF`X~8UAjRHG-ft_6#p=w@-{Ygl zVe|H-wwtCIb#nu3SohiJ&yTgN0RJ|mZhqr#cD4EGuROe&BY))ov;aj)bjKlvC-Hu* zBJI802}l%>FWPI$*x zO$IV)(5uNHEqh|5$;s^Su?f_fvaS0caR19Sk{(KVpaQ17iVYZhG?amwd}ys_quX`k z(z@`^waoF0-Zs%?y=%<6731jje933En%hxQRRR!M|0825FSV8OQd$N}Kq}pV$9=?* zwDsa-pSOSN%Ur(0(odDkCb@|-@B6xZtEP5xej3>JtR5Xv@3&WdX*IAArrFo3s#eFE zO3|x-T-YDKx;##L)@x5pl#(?qI-B~ypjRfrqv%MT}tQ zUBE7w%seJl01dcR>bT`CPiSlNsL)^b$pEy4p&ko-v|ylY&}@w+icJcUoFvFsz&J0C zc+OU_cPi@}gU|EyHLRqe=Tg(0@v)}LJMEa#?T~%R_S*|?GRrk@K%i8{6S<^w_396z za>c`gF?Y*&Kp6e9*#$p83j3hR+Rr?eD(FrPJf6?)w3eQ)u5>D5rAvHm;aHQas+RR_ z%&q4sl*cUwS!_8c?|Gp6wiKStOP~gNx4XOU6!Tp5e8Vy?ZgM8TP1DZnRJa%A;eeA{ za*|ZiHZQ0OqOhAgP$LL%#CxafqA7(}yJ?I=pDB$PFQ&LM4)#o1>HpDm?(t0b|Noy^ zMVG>IB@#0e>q=ybLK`j32u+_36Y7eEWk_-g%cUs95SAi`k*k)%oaRu;*$A1-VZ=m| zNe;stey_f_+wZS#x42<@zxR4S50A(Fk$#C9@7DK~bif)cxn!fFt`k1+hT`3bo=>lD z=bTEb{=A(8l5?#w2i!K|l(s)6g9_`!$ro(2n_J;Fy&UF>SF>{;m{0VfL12KPvj4m^ zMpY1RWX(Pb=k(6dU-;4ZW zfrkLK4;T(4$!v!v-i*9rCA(P%B*pCinVtNdRnk@b5Q(tk;uDi40h=$5 zM%=kHBpRxIn^h3}w5Mg_$MTEWXja2EjXS04_f^?tR__F!w`&9)^R{a}LuOcM2d7<$ zW(=T41zAs0fZrUrOF<8ZvR9mWXU@3M1*zI=@#OLK-I!U43kki2jKZ@ahh_f<% zei#YbeA7fO$F4|bNM zOW0qMZ4V#m_w@fS`kwibx0eW!l}u73okhK;6K zkO#EaCt}lhI7ISKg2v__*i8(`um9ajE`Q~gSEbr;`jZXrlMvOaL`L4|%`V{+Ldn6d0{PVbEbGYJdv?yT0&Jzh;r=BmJMVt3Pvd zIcr&7|4`A*v=Yf8ZEYE>jYL_?YX)u@rycc%`kd5cUey-bv#g=ofSzWZw7v^{P8g@u zUn_mC)2mPWOqJ0X3VoB&_LqL`n-k_1X!<9w zOB1ov>zDrqol{13=gO}T?q0FPZ|O73Eg|djK`vI$guPs`vk)B}zfDs-gwPEvoBRgP9$t@ZQ z1w#+fQM+Wz`cISNI!zh1ZGC+bzbAeDb!$v6JC$|RzMp58aGqs^F*O|~s1~51O{X(b z=8F$H_bmca_s7~1*ULW&DyM(dMB9tZ@2s-LCsreBHw3d`%g^t(SMvvQ^ybw_g^zKu z7gO(*_I?6b?xSOi%06K$v03Zg8AaawmvtNEn|J9m;aN9b*yj;8g%VFy@ii*1os74e zS{VOkTsQY@^PB5RJ$7B_`a+TB(pH@EYZ-JfWh$#YFI~2_c)n+sYLn*y*8XdKfo)(} zJ@-9iv!f>ZcOu7hV?U(?2fu?~=DSOY9H%jF{8}hZKJ|Em2amKU8Eq zy;yAvz{2#c<##40R=PqsBi@s&@$u>ZMU)<^t*F}gwy{1y7R|?(V9IY*_qVs*@(Vt7 z@>hzW>QM6j29g(*Q5F6qpR^m3HDSo>0S!ldNeP)4UlF+3m9+-kj@*$o9xtA2r1gnx z-rV9Snq=jTL-Ii=Xuu`$Gp2h<@}ar0D#1%h?Zeu&gHrm0Oq zSYWNo;<2Jtqw&)3B)bVWPe1X}3Pn(m;uSkP67lP&uqoqdnN4Vg{*jbjcK2^d+ycyQ zC92Ql`wWHt5}gJYpa1fZv;BOV@gpB~w)KIWvj6nKD%Z`BmiF}~d37k-K?`!Za~C~1 zTUvn~HtA*9Z4E+4ESGgaa`jl2<+9WV4^e8;UY>w-)7T#qC|&4~mRu=~urMr;lX+*b zz&>IP0swj<#$8t%Vq@D9hr`AH6h%xw3zg5b?Mb=$nw9s|Gd12PeB!aOYs3n#vvxzo zo#oB{P2q5ai@xC@#bkEX39i$n)~e}8N2zTO+_IAM6e20;dk$JvPm}ky<^aiPM{r&H z?46*^mgK)MrY8o#wBl7?{UU9|%apt$Q|?L{n3kHx&_9t&O+4mFIj8J)s$Y!NDWbvW< zhib~UqRmgY5&$ak2$3x`DI1t@R|n&Fx^Oqrj){f z1&mIjf@rZc@^{ihNK{gIuL^U0`_Q+`Wi##tJ`hRZD2B<&Q%eFxwQ7gP6NU5x0%3^IuL4m`Clc@=NN@dYjkBO zetg`x1AHp^J*8%q6$1$+U|~o0=A1X*7KwN+-MteDtO;-_3rKuQltvQlT^waA=>F6I z2PrNOg@Y5IKd=87_XxXL&3Ge-A6(y)Z4W^xCRrk6W$5_sAt^kSbAAn^a9d4Rm3|L} zu=t*2FBs~H3K{}BIRL0d-6S4c3CGGBJ~3T?7l;4lW>qc?^)=oHNlId7%1R^0bRs4b z1hoN<^gO<*l-B*;)s7jbh}F)ua!67r@qyb*PTB2%fPEobQ5Mz|i0(aKpi?D4%s}cl z=zu{GT_PO;wvI`PNNoiuA}PoYsw=bYqm;!ROHfTJoUp(JJ%Y$cDS<2e0Rx0*V^TPH z6!f{0f;-56hrku^-EoRY#JhM!C}3#%;S}Hm925vCZU+0EI(buix&MOe+85zA>>}tR zSEkZ{k%gAl1nXn~HQH}V0lVs-hx8zIe1!$$j`?VPbx9^zU zXgd6a{4wMk)w|^tnsA6CwWq4|^KLyEP(MtpM<=Y-{sCMq!~^V!S}~t&^o|G{ay2mr zERi{Y@GH+BP(Xh02wU>=q%FAl$HVShM&><*pV?X^G0{J!G6fFNy?Lr#Uk|=HRie-g z))_?ahcZ`t1HrKD@Ga+fE7f=_%uViy&-s_C-o8F;?@6d`W%=%71+356oviaoNpORO z%EPDhBrMCf>Z^&wLPd+4M;0W0)-52hMUek^DLhaY5=t9y?^{N3%X+_QR!$X z3Z*5eDKp49rO@7DJe>_PKyUhSLPr~0a$i2PG@`OCpjlo1An(%&U%mWc=Jzx{x^B^1 z=Ookv4|xdgH7KxKEr!W^JfTQ|AP4?HM?#olAuZj#Llt3}s?!j4Xsd~M4Qnd?D z?3$#xY}ec)kc(6Tv5ro$M;C(8y*!V?6!%_v8}#pKED?>`q5xL5oE!X?!N)ulu7H^W zkXHifW+DXI4H{h{$<{{uf7AtM7vk9$v;JsCGLIDwW}x!=Wf%HPlW6;)k*L6zoZy>U zS|8qV%R9gWRThzRDtX9uo0Mi?zlW7=nX;I%@w6$GF}@)O@ZHH(U|de;tnkd3sWYh7D^6lUc2$4`K*|L!h`4GmEes_W&AaPrQP*41Z6Dr~8TmHP6JJ zMBTP&d$9Gx3!JCl@mtrY!;dyzB&WT89oY3r>EvxKq)}hum2)x~wOZ$L$`Cl*nd3ks zh1T4%Jaz#4jHu{ENXY;eVGF=t0b>O$!c2$047+NCli6Yc;LHjNFe#X)rplh}C$^zc zPmU>OE4x;M8+8(FQ9-2rl29h(*ae0GD0oiXjH-uxJ-j)DtmeD`hf5Kkc( zAr9%GqDVJ6yEXUlUVI|`t7O=@sp0ffz1ZnV{(|Je!)=!kGat;1m4Lqt`5{(_Qrf3ng-_LtadBb}GRd z4MAg)tfb#(^GW88a3`uc5+nOl9rmavoiT5C-Am2RYoC`@CoW+)bYb{0AV3?QlBJ;X zP%?!|+jbDG6-OxyBmkf?~(P0*p6uPZHhV;=WPVetaAmlsshit2z2jyTxZggcv=+lMtMvJ_Z)|5}7G7mGE zS7{KfNR*w-_6f7INJA-WUvab1a9g{dt^&>~KdLurt^9NUrm zeAs_x6rb;5Hb+YFY>Y|7T~UoLnV-4+gq*+y2Cxm?PeXY|3Re;!=ZK!vz4w!n40$)a zEw(>r7{J?YGwDXEv#eqc#l;utz8@ls0#O`N*(t!)4umpV7B~ky0fr+&>$dIj%D$98 z;eHrnjk*QJA%H5H?u(=Y|9jOXeEQzn(-1-{SgNCBWq?P1c1pV%k3%8Gq7n(aU* zWGN|v0|tB*70Xpl^F^}qVs2r86d}fz)fH!yoAG#zvwYF!k3|9$PJ%kbp5f5HnYX`E zGVYF}pmcS$wPAubrRVML-u6X4v$vy*YUd{gU4wp5u#y@1Oo2!pTd{{I^&pLaQ@~#d zOyBImu115_Z*>-D>ZdPih-0b%+rH&O_|xl{s%MGxs1&b#FcmNxL77MRtq)KWhC}A# zL1bmbR-DuMLz0Lo*A?mVK*`uWd~6I?8T+fZ+$m~r-NLG{ZGN6VC^C@eWcnD_G*B@6 zCRE-HNO(K}MQu1(!j3J`i<1a6?|G`Vzlh@sMh!Y4Gf_d|{^hT|0keeDK7SUH0=S?G z4+bmQHkk4Y8o*eV8ZeycJ$dZW^v$7>#dG+lJ_T=s_B8?|P88=;ecL=Rz8;smrdKWz z4h%>}*5B|~m%Hj`ZvWwjIb%a@)fLe;Hlj6H3$67p$F?|3AKtNOnss93uh}p|eX3q9 zR*lbz7n;P^_kIob;||XBal9XHnqwD4w^adphDW=;(B~3%%b)90b4K`SaJ5l*!K<*G zds5|o3GbXu_KMM?^sQliXW_m4)1m<=>Zycwend7wFb$tsPxs;1x3*?wc@?T7{-*%X(NV@a&# zhL!%#i1`}qO3}tJKnpH~yJ!`27U!?q|2eaE!#}v}*(B$5L2%xLyMUJ8ek-YQ#w3+| zVq;<6=g!Y5u!ietDl)6CHkmg6{VEL}2`B9{H5%lEUm$-5PkAf*A$lhP1q5w>cT8zCrK;eq=^W8=Fi z_`G~wotU5m1}%-Pg2ccjqnqB-!f55+F_y_A8$TxA_iB5B?7zP9K;oI6H-j^29B@B9 z^Y&O;n-IxwERC$5oUQ%ecL(B(IfA8BqXAGK4%WXw3US0{vX1`k`A`jP#HO%dzSt_t z)M+}&Fd3L`Q@Y8ngI?oC@imL?-aV9mMd-!hXtD;@Wb=Kw>!u!dbrD>WXMP6KuLGlH zW|p|}CsuxNJ4N@m6&-3blap>~Hv)FNvy_COnVXW{K6Ue|su(_v=2HZGMcZ3ujBXqq z6l@@_V9p3lM7N_0^fP@L=WJY;KlJBr)BU(1GwN$1+8M31Br)G1S{xhu^*6UrNPqiX zM4MSR>13DB7U-gI|alUhQ7Jt#&{AGl}=bWg`|V!EQ!JjA27({&Gd_ zNYvEY_3>p<&Bl0%j**t=)GbRR)e834>Ydql{4R_5_wk(`ic$(FHzEWM7l$;e^1k>u zXT}Gl-zN`6|1ICqNUq-VtgJsyd2-NGZOA+Da_zdHlh3VpXzdY(mfwPDt|l^NVhW>z}*=a~Y`=ra)>)dh>Mr|`MQrkWF8Wzf9qvqQ4Lt{&sMMW296vX5;(g& zWmKE0bvDk8jSWSUz4j5OYLu~utN!xWrIflmhvs~SGpSUVUsC03n}t`LMBwie%V4l7 z-yf8NClxG;Z|Vth$MPyiW|pR_mSTn-llDeuCs|!%*RQNx0u(rtogA|uUu^`^(7*bE zphg^HYt7~e{bu)E4Lb$sbChzKT?bjiCvo`QVz8Xf;9hrgTaxLvgCu@=;O9J8b(Dabb`ZQeeQ5rm zHbgcFH(*}HWr#9W6qzKe?ex!~kW0k5w02v4*0>cNc=@{j3%Rp4m7KM{0-OZv2{iF( zLXG%bk`)9nZ`+r@y>IAk2&T@gEY4IPHJ1JqS{e>#S{L(4vC4s%*KCcnBgoL%q~~dL z(smal;%SWAVSi&|*H9m-G(s0S2bYz((*n|L%qq<4%m%w}lw*G+*i4%vVODu|5TICf zwSwn?)(!Pr0xI^J^HUqD5r>;}C^C~65ENJ%OSQ(?LTTq8a@65*M*loZY?x)f59(|u zDEJ0qRDpc;LCo@;#ySVE36KJw2O=f7%sljKSAE2K!iKd4?ZjuIG|V~+8%EnI3$_9X z-R($OYm~MWY|C9EG$4oIfwmQt?PHlTHrl|)2^Vg~V39oDXgeDEf1pJR6HT!09v-}5 z92m%b%b%a;_4ZE)CykT)MJ8eb91d`*1P`vt=Fi#nf(;&arQpFXDU{|Y9%^l21^*{}$OmXh->m z{F~`%F~E#7WAI}l;Dx*QONIjA=bs-k?6Em(g?frk^?U_O8-xiWL@@DsiHD#6aQ$?NmoOHJ3Dq@!RM$NNCQ4m+oB zu4-Y8;8m#n%Z&YRW@p0dj-{r6nNd*^^0>9JJsQ)#58h&HUQxCDzPxTZVw3HY2mzpu z-8Ir`Tb1{id!fydk25^UeVicAu5u9KiD|i@;c_B0Jeg7xh>4XkRz633(41`fAnx2; zw-y0|)P@Xt8kP&fv$Dyt49;%A+gG9IDF7E^Kjjzi^G*r>v0~)I6_XuyWy2Gk(+~3u z!Ej$GT-E{tOZw1HIlxiyFn`om#kA6bbhMF%wv_SjEf1Kwt}gU1#!l~xC+*f}5?chw z<9Pi{MbQR-TK>e^+U{nB#7hrt4zMUu%zdfuYF>w>OQS-l4F?V5GFwTPE%Af{B8F_t zbJQMz83so|L2_Be71t;FZ#%Z*heQea3uBx|t<7aoy~Cz0aZ3NQX*qY`@lD_K#^B6p zgFSxTA+ab1JbFx1rAw>8uf3iBq;ipB7Tb3vq$FBHpg5;H)$?TVnc=HabaipSlx<` zyk4)VOuE*tL>SyIKM55Tg{WBRr$qG&1TGai+dr6pcn3S=^(^-v3Z6*MCx`qiPIQPS z7IQM0oc~rQ)J?>^57Ls>~NQbEUhSxgtQ<>Dx*qMsKebqq;QIHP^ z`a$i`K+K-lN|lgK{$3ssppS~IkR=@TC|PKMXAA*Xvkj$+>ER9W*q^S5m^p4V205)) z0ON4#&x|RDkhU`#x6z$zeb& zRHZ(>V(&<*bkD=VVbvkj!~E}@j;8({M*i3GK-@6F(JJ9`UvE1~0aAGG0M9_~9{@5V zCp5Rmyl8Or#aN>gFY*`v<_d1)bJ&vgtKMgcQi)6iS{p|~8{@|tzOER_wN<~WNjAEM zx5DS=*|rF%bEJnVp|P9*%(Nm}${{~3Nzp_z1$n9c+t%moeOvSJd(iI%b}~u6#(|is zy_jCi&gfj6@e`GI!>05Ugsct>4*@6g^C%U=Qw~aa97Kv?RTb(7o*j;G7cgmThdDrH zaYRTSXnv8Pph2*3aJU`eDHtqTnq<$7_WsXpNHCm##Yk1gY65tFX5~K?jd#^=L&fp6 zLSV2!eO5(AUONh4Dsd2dR98B4dH^D2Fkm1@*=mR(Q)xR9k69@(9&GNQNnGI%_UU}a zgp~otGX+O)j8noZK;lQFEpS8A6e~lFwZCyB(25h#7;VP#i6oQ$NAcrABZ~!j%Mng6_v({n< zXBt!2XE&82M*Lg^JKhbfz7d75_thDmx#qS<5C>3lFO>9IZsW8%Wgbu6#d#q{=oh{* zmcLVIAO{GW&~N4d;plBXNJEtk&+d#S6a7Metp!up|0t?E`dLaLTUecW2AurI!Sev{ zcl^{`!xnIbgX^OWGc-^36Ls@y)oFvzWI;B5N#Ix6zb};|U;in`r(o)K#GRmkN|jc? z-rJU@EYfb^8BxZ=T|m$$VL>KIu`5IgV{KG->@`+A*W>QYs^$)gV*q|IW9s`awbuHL zPg*vO7hEb|oU8#zuKcTN_lHY3x4EW4Zvi6Yg2oAxksFz2puI|uza1RzVq@+3Ea5`h zI(w54*N(FONju`8s#n#3qse;*1qAD zF{7OkOPk9tp97rj;@S;IFQAFOEg2NhoCl2_ArNuGpYtOjvm=s|n?p{n0H8bf<@+z+ zAy-$|zl6WWe%vXU@?IoQ9=RP|FQC<_w027$2o}=j(`x$%x0N$OZ*b;lE}+cTn1W2n z^n`7gjVY|SE?iQQaY5bXA)r9t=7v#dM|(zn;}VsN8ltmB32ho{&o4?Lex)bpW3C2@R+IzsnPTYA#`4ACtYP>kT~K z#kTsF+t}=`KEYM>=+z$$J9w!9VP8j2qWd^u%l+3Cg9C!+0BsQ)6tuRr{kysa40iMM#>a>xP;sbGZ|VFyIJ-8p*_^d98xd)Q zgUG26>AgWm;{F+|U7T!kpV7SP>HTj&pQ_Z!?M5tLpLmb3sg^(um&!EH7uV3&9nA;j zdf8Q#T~`3dwPeQV^Oz{hylx#dI)+54@G_^J=0GmCw)m3w&&uOi0kn%`GS^D0lF~_&x`Hl}l8Bd(HeKK_PQ0$d^cP_}hTu1Wt6Gj_?Lfw&{ z3;Sq3n)VY0<9Sd-6FOEvhrmoeD587$eS(1F&{GXUNN?0c!m8&Qr|af5Hod2-UwN-j zlw+4GeQL$yD`%#!QWQr;l%wY*16GO7|oHuqI#2^M5$I= zbm%nYpbJU1E4GNes7~P{A7B0LF6q|_O(3w&J-j|%{d&H*)IC0if81J2U~V{6^O^j+ zTWj>x-T7tgjuZ6=M#jbLvG*m}Gd)VoL$kR;EJY{1H1O*p%yh<Ku5znt`QQtL|p(hbvIQfh!; z--Nq2b(-B&RmPVTm&K&u>EguWcPpj8v03m))E$i$P#P<~eMNOUu%$al9_43`TiE%I zN1Tfxv?*Fv=!%2I8wBF4RAnP|5Spsd=clfK9KLG2 zA&78|W;bZS3gOe8u6VTVeL1Z)$qTN%-M8j}N} zChmb=3H3A)hLF+uAS)Y#aDn5jAwcx0850T*cei?S*bsC(P-IM~716}{E(`&I%7CQ| zs6^p#YYP)aJHj4Wz)g?=yIcn)7!+E!HlZ9o?Xxn9U7y@g)|3SpQ@B23>o*u(1(Qrk zLI51M^@kTSs*Zc8#|CMxAe^#nF!)l+N(UGFbGSUBE5?>FWGfWT&-K#;8VQ5EiHi1y zuov|rU&y70d-aew`MsO=nxCIPdt(W@>Y3BqcK z;WhLrrszZwJCzh?{yCQ`p{OOyAHJGg-@as{HAMk#RtS*&7a$0-b`2AmJzv@ef}o$O zEB2-J-aRhYR`t}Ub7Cbu2ZcMo-SBrS2dy&0Qm2of$)(r(dFnyH8*G#G6Rcr_9_Vya zRBM*a^y?k;%X=pEMaW%O{FW5Zmnh_i{98#l`jI5#<2)no?R-Z=L z&z4Xx1}m*SDT#8n@8T5ER}E6KcLu!Tm__*MW$rG{s|xY!lT_tv`@DkvOlZ?V7oCV(QTX=+<0lM64B^xP!`Q(uTd&0b zU@E{84Q~2U8BkRETUD*@p^@sL%W{W2MZp&(Gu^b*o%H1sWB3o^L>Np#jH2t%VK|5% zQpWds6hQ`gg~Eio87U~PtnMuWD7k^E!F?K+pSgddML@2AND8Fq$J^XvYS%Fdawuev z9PtxSUORt(l>Rjg8$8vE@%5d7`ofJUasa5*7Z& zUV`ifGmO(8&<7|vnCD5h5ndibJVn97)AO&E2!@75Lu{qa&t^rWDyKP1j3q{K#A+5iYvYnexzKs3@$ zBhx`U&Uwq4rh(O}S1zpv=K}v~2z9e6<@XK$iEbgN3c$**_*|MV5FgM!4h)!eGLjHD zCeXs)D!KZiCNS6e@>5xIpIx(n_l*Jo;JK%_Q*HsuX2{Tty!k0v)Lar12~()c+u19? zlyDBU%&5x(0@@Qs>G$2l2Na_cTQ+!di1L-5f3D#pk&b{@UD0IAJj;Xv7_`OEE{JSY zmy8T)J3@v~ae5SQqWK^cPN=w)0P=$1kh@X7mWlbcbOeg=8ywx-7CSGT+r!YQIPFh7 zo^e!Ce|PyYU}6#uuplwXwwS+Mh;x7+YC)NxpyIc}ac+3|XEF6e;<<7iOP`nV9V+Nv>jm2S{s2;BAeMy)|oS>JxW8Jx(|a!+5w5K zm2B_K*bT!HP5}seAsnDN24M1GcN=$AyIJKjf~+Chr}9Z7$wVLs(858WD7OQSAk;c2 zoGY1(=<|^jW`((0;*||Rm~cb8w!77|o|g5VOVlIf>)}~Uh9Mcf#i17UVsWEaBPf*n z46-)9xuFc;lWEDDC3TWO?Jq31@BOhEr;kK@iA?|~@1V8T+_%dcL1u%QU@Ne5@y)BO zu#JVO*l7-@d^l)*M!%*%6x-3%nN^dXw)p**;Vv)&^9ke%?|^w9Sm8BhS7eZiPK21q z4Lj)v80d3SzRmq;_yc4A)j+NtY|Q$|S&i?9*g*>p`I=iE^2rx`6xY9x{TR(X4Xu-O z>C`(oQKN--o~9|(Ei~>OoGDd_cE1FcIIx`*ko=Ba{+8P|U(!@m-HpsL59JROgTCKS z>%Y^TKH;N1lWkRQA9*u}kOiJ<_W{Adu28(&{Lt3TR$&{@2*h7$oT#V*e`F)DKMo6X z?Xkw5O@2y#z5uaH53%j{7vc`{|jripjXhPXf&`JxK z(NSy-rBYEd+TT!hOJDWZCNwtQyNX|q?D!h7fnDE%`HS`G2A4^kbN7_g&n*G$!S9y~ zfMH_n+H%6$-H272BJ=O&hdMf%FZP9(kL;~@c7ML)Oy29+B{t`6I^c|A20N*K8GQkP z>2-^O&ewZ8I?B@0lpAWqwE~)8X5#iFO=$2cTHq5T=FL!U{r$x1fem%uEP3mA@oUl7 zx%xK0J!Kg)S6y6&hGi?v1}%Z1a_~m^HMX&FU)G5*z9VS+wEUg>rhzt9Ft=CZ&MyEE zGS#@Vx**i)v|+P3?FJZe5))zw`U;6*k@t~bfK5NLOs!iDT(5Fn=kHA@@T;gY(YQbA zYi2b8c>G|b{%1E>_eCtYZmuL0iRCpemuB`*{LR!1{neU+U2snn!5~s@O1xGdG2-M? zeZ0uqdC;M4!(p7p|$zqwaGF3;Lf;fRqcCRPr@sHu_~ zO1*jP9NoC>rg;$>eYmL2C@y*!kxqg?P=c@(B>@|&xfft@^>0+ZJFMNoJUzpC()%|A zR#!EY>2o>>9k#Zxl$?OY>bv)im8=gqGJ}tB&X7 zosw`mEu(TB;%zcPug4eE z*OTjn8muvs&bpuM*|i~KAm#j#e|lRwbE*6GD_62ZRYK&x&r7_+&(SzXR2h zvJ(M7W=!-cdo3@v(Sa=huN}?g@G-j->_{|&YqPRgw2t}e1JPBrXwr~}3-By|9#cF^ ze3qa6`8Xf~dV6z%^zJqCEs1oxp{2f*!+tuS3&Vj)dfT~#Z;a`IM@=gxo$w%NSy_I! z2MV=j2>mp09DvTG+(Xc)X!3nOlR=tIA!vjq?K2gtt3Wu9P9&XlKy-c3yKsw}l}J8% zeFI{^BH!UMy%u*Rag;D^%^Y#rYX%Y|BpS;IP4=iLf)v5$o~rWEU#EJmw-xIic~sxf zutLF{8lMro-ksHWm(KMm1GlZA)ZmT%QZ)fmqSTt%rBI0SU#?f!Hyg3keyHhK`tfPh_G%KR+ zasZ3OA@g4@RBvY|x7X~5rIiwS?CL^EL8n-9E%t|bh?^U+)fReE&!=|ods^-CYQxHT z5+3kl0IX-aig>f!&jbx~qGp9}{8*RAhWYvHfb0aEex)fS(maI1AG-i{>yu7N;4CxI zhs5c!Dwy17wnB%Y#%%bWg1NC9p?=}#<7&k2-t)zWsMFwwg6~|tT|TIh#*unK6Ag#F zVrT4q-)_QyfJdD#GMAC4pvaWP!8amgSU^XZ+MQdzn^VCMSru2Pcv3_Zt6b)sIzk(Q z(Hf<2QZ*!98tP4F;VmRJw}p)XVH0@QHkULc@{m114>UVEH9y@B138Glv#l7QD8xZv za0S>W!dW6c5~mP_N{akxo&!226bx+Bw$r2PcFA_5EFfrYSvs5`6@{qAgE$f*6o(6X zK>xXE0cN?Qc}i`NL@3MwBHK)m0v%rzh+=#Yngjy9!I$wk6HVP_f(5)b8t5+->>Og3n3ALgyQ^^8H#WsJCT5g$!brX+fGMe9P^)_mVdnzz4E^PWhXW) zhx9w#Odh-J0B?`0FvCX7c+K->!^1%mlgS~Q=^h8EM3X7K`)^;dcLn+Sb+H1NlSlI3 zsz35)AJK~4Rm#t>L=fkcLKbF>_U!~|Umh>tol7NwP2ltEPx>h@=BtuY0fr-E%A_;T z{d*Mtu#8prP_Fo8TWm(gAc;CHi1B-hjQk8b@g2g7L$SQ9 z=6T-5*wYgOIg2s27BE>Eh%5`Hkf&Mld4TL+KF_=FM&$|AU2b5*Lj+nElL^fTi)O6|$S8%#KVTr3!56h{_6w}((LT4?`D||B%w`r=DT~p z72L=XvyNzC;NvFeFgsX>rd6}mH37R4RGg!KrUEV}B%23T^#|E(>b69Pc3|f>gnmbd z(=3%bTeJSNAAs3sEQpW*P#n`qk@(1{O3hz2fx~OxT1sSCP+^lypOn>@zty<$F2wKKFD2 z2!_*b2$fG#km)klx(~8TZV!56AEX#MX7DI3ec4J{DdbQ$aBr#iQLI=vMWr~p0zIRP zhYX1|8<}}DpY!dOjRli-o;ao0s#f6XJjpXyYUhWz4RZrmPKR$?-}vsjoOYH@SmY zdd*F5OKVD85kBuZq3e#CSxBim?e^@Q68W#y=W-RxZMJ!vc6-dLGJ-4j36`e>(3a-+ zQ~2#zzQs2fim=q~g-UOQgrcmiVX(xZbM~GW4r)f)xaC92&gJ3GqR#TRPWE2(=?nLG zOBvftK>4Q_ipXPZq*5+y#4Yc6UhNA&Y)oIJVy)_asyn{6eFDVD*%z1g@!CBN_gkEqzOD zc2-rUWoXD5Os}ZZC)t+yzJFgKDn3K-QqYh*Da{=xXV}+U<0oD#$)!}M*s_Yn2Jm+# z=P|B*sZ19$WFixe_ctyXKCh~s`nLjkw%$R|X4pBA%8*q+0YGvjy;{i~YLMGScGafk zkN)`a<15b@O>?7q&+JnXvF=p|QK0x+syvg=stmmk9!!hk)G-ljcO=Pj&wb*x(qXL} zai$7G2mCb4!rEu~%|H)R-s3QY*=2;;T~7K7!XnQqv?JaR=?aGSg~%jAScGaM9USR& z9_5yp599?pTj@qx07D}hCOiInI(=_c`;D4@Stk4*c%J7(qmmfb?*!E;?LTU!QIC_j z=*MsuEm_&;2yl`UKFC@qCjQ)Rt)Sq-!2Q(#07{hYQP#3Q{{%@)Fb5(8Y7bGgo$A`_ zbJ^9kh%If6yMktk!5>*)tPqj7O+3pPmP%K7AA=Zm88Xi~jRIjGWXcmJx9gQSlYu~` zcX{Z5gC1_*4(?ohg09HOk&*zxSwf$WHMAQh=T$2HP=sk+bG`tncfbT#A~8~YGQ*!g#OA*r0yfdtdce(8|@BQ$$knSQM8gZZc5Lfm7ueFAN z!}u2!5zDzc%&uIJ3lg%aGmLg$?ugc?e^p-g+J*vtap>f;K#}WH*B|*~Cmw+^9EKD& z@Xl;+h-F^)X6^r14Io;E^*4sLxvr0eHgPulBIYkN z9Z&fV@3=ikYAr6S_p7a~^#mg{0F0aawVn{ZJi9R+v2;D+mp|)s{itu*Go)WAh~HDu z?+EPl5nGj&9ik4-%DX)M(y+30yDlqj>6d5^10=C+{PM(=N)UP>*%+kQV zbYmX7&T?HXs9UYf3Ys5Y0ZVM}{IlJ~2eZs1w<6MQ=6IBOSD+95t3W`*bl8Amwjt>9 zd8zs8JQxB~bUVZEMctbI+SoSNpomL-_O8{hIBE$c#eaM=-vZ84iTKdav^-E1jY!xd z>(6|`%*5xQpGJd#XgKbp!!~`pZbGOYCX@<7#eLYa$9C2mebx_~=(>OvcU&I{7H%{g zd!gK?pDS(;D$(?+T8t1bX1Y={Yo2&xSh-+AK23hsRFTRsA$ zxqq-yW=f@$m`Ol8+D|jx@xKojrvtHTL9}Vgt68&0!s>Q9jV9jwGP{{uwEnD4l2JD&?_w+F-MGY$IT6pP zSl_$ZnzdrT`EoOS$kt{S60@fo@*ijhccRVB+a-KWbk{1m)%V*D9p+X7(fu&=wz+;* z-4IB|FnYwgQ4mtA(m2-3i(|J{n^gpsF%PtG8Un+Y7gqZh8;mY@uD68$naI4rUG3jC znejd?)1LMy!S#nD;p?}d-O9JV1)m>^SLRxih*Deo`DJDNkfnCc^(XPYQVZ?74~SU* zNtEl`w2$7igUS>x{wN_8{QCb|fWpd#?wnIg4tb>Sg-32a`mcQBj%Uyri0k_VMYF@g z2S6p6G57JC=%k)b>p_aqt}hg5e)e{#!RG<3p&#FeYwCWsMKmVr`^?s^%*;lt4{C(} z`cbu*$)s$3$LlB)g0pDzkE}4U;CGcHY%(q{Kk4`LmO=qk0wLd)5M$JzZH@7R~iE@ z#SQ}XL>#D55K%bHuf;s8&z|@l{PvBsEh?8jpb@h*m(GFoFYIC5%C_Z)jvPr>{dsDG$X47v5R z4~X?NB7QAQl_&>F>Z{9ye#hFuHkE2RMS8@kmhkt^u77j_2fgjdfWYpxKih1jh>S0? z3SB;;oxoMvVq7QrN5edf0k_WWlB1&nw*l~I!i$EH@P#kz)A9wLms0~GOiDp8HwK)% zWa2)rMR*q`1Re17KDpIsr%ENZ!x(HH>))RKOtwB~1IiY$M7UvceS)Iecr~WI-j9(2 z(lR@3DBT1FI?()NUm&&0$zb=(76A^tEY9yG2M^xmhupmaK{IJ6PUIrs$t7moHOK^N z)p(u%Xyw@TUU>p0mz!}I$UkRm*OzGJ5_#YddW!r0Cxo)~OH0pnG#K}eew6u?htfsi z_oNu+x@bxzfwTxH!ootw2&oNVxk*qNDH!6x#{`g`JQ|e;c#twggr+P)_BRt9hKB>j zX9NJE&uSs)^qS5F`x&}L6tF4w%AALOo^ z#5K83nLh;jpjY1JgU|L&_CJF-`Sh494m*CU*%5Ft1fxJ#e17cnmcVUprR}#$b|3yc zAW_xSKhYb)#iskckd6^{AG+Oh)ddB)RX%f(|K<4X7HJ0hcLAHKS|f|-M}m#cLA`$m zzfvlW9WvkY_X`eZCqmn}ZFtJA85(bxv$MXqEIZ}+XD&DFFnNw|33*R`wHO`{K8#$7 z28V24$jb?TC+(-+#$W>DpyoE)uZ8N8!%9%dMAhlxtu^ zyK+zJa!UCEIXb{|Ht3-Uk@v|XVZ!%f4Xh>vqg#;Op_gtkPr8$-{PPIC@!M3x{j2E- z{%G~=mnFQ|!IPFJ+0#|a^X8 z=*mIb6Vc9XQd{p#mCT-~sSTd{WoL=rS$NvGq&W&l>NfgZx!7q|CGJY58Ye-|L`s1X zkbNYDX4Tvdh`Go0^`xY38ImYK!YPA`0;nJe9{)*K%HeQl9N7jXv)KN(T_h}urE_n7 z#y9XXEM0}(KK@rTL3Q7MqOv9-5`wp~nlO5lL^{@+eabcU{KLx7eA2%SFVhBv*+C50 zR};IMBNjSf?)UB@m8hclcL0^qAgg&RNeM_Kwi}ZD{$gzmX{;7vmpa!UV1IRPjB(AN z-wS8&tc{mr0Zd?IMUd8KU%T{j^G$}~-!D$iIujls5Px3V4iZuSSG~KOBaVB{Oi>`j zxdhgyRJwG&to-vD<%!}IJY1$l?zvA>G4>GS-v&`umY|gXsBJv8J9|qD@5?`und;rb zi#0Y)+A=2YrI`bNnl8wFXo*phjfBP}#u+3=k@U7aH_>{Feo=bF{UiK4+IY9IjzFcb zSxG^2^s#MamxZw%tkUUsvmL=*cHK%4pw9?(?mQfIQ&{ABH%9fK7y^bNZ4M-;`E{Uz z$n1Mp+<-QjE=pw}Kt@XuE9E;SQ>Er~!VAuUUZ-8fsoQTlD}VUzpec9qPlRl1VxnPg zUfd5wkkM1hGXm;&90Kj>&8}cXArK+<53HnNpGg)A>Pa434MP4ORp%bgbpOZyO{?fG z=ev*?R;)Xbxtq%QIEUi94njyVhhs?$yX>=l-mlm5`FuQgUdG+rZx5v(X^`(`j-Eos@;AXP>E$;$+JH4Hf2O494t!z4V7WiD-*4#AikCBAW({N5r! zhy;m7!Thrvs?}Sm%PpCLu%$_!%y-OACh}g7}=AbhA~P=)AHI#Yp}~# zsb${>q|Qu?B>mB;PvAr6+~L0!6@M1@KC!fGSbCkRqR8n~ub@Uo?xJVE;Gb9u${=6NqYvPi(x+EfG~hKsAy|yc?e?*v&w+)v6FbR z0IJm=N3R(^eE`dVcv)!UqVv)}s($aZ2|B`kM1`b=V(klMOf9`Z3=g#Ja`4*Za;shH zv@9_=%1qkO*2h}1*%W0FzR=Bz9zFo}0&hKosS z%6i_8Z>LZ|1L$dN2}HcTe`{yWDQ3*#gSDJ%^+33fh5t@sMOteGKWb%O zatqdh=sk$<@tZ4un^a#v67{RNJ8GlZ5wbBAw6VN8G^MlEViH!x&T&aeZEt&QxLMn6 zOyZ6=2<9)QXm{8NH@ym4iO)lx|Lqi#JGfMHM9_=K4??#XJ*{p}shl6e2^I-kKbJa^ z%9<}vB{q90y?oc*B$N}DA2lIud>S5h3o@)frQ+FGA8|cm??fo0!O$cnsd?d#fe`Ok zO@*snoo~omYi&pY!-fZIQZES2ASx_}tru4lhfNQ+j9iPkR64&p6D|;)w@iT*!cc$q zgN)h+`xiL_6J+A%;_^^RwrW$&`pQ%dC)Ij%WK>40rSn!bTl$H9cQCWfb7e6SJQ>u} z8XcMuY2~t#H8N|pMzL*jn83de%Js&>9e&PEEasy}XSfS%%O!~(qxJIFD<6CErpMMr zpgnwRK~raWz4_Q}=B23<>RBwzUL6`5#JFuR0kpt`wI9N<)z$Lo1>dHPp{prPBJ@_e z|8u&$*uHFE$W$@dN)Uqh5QoVxu9_$M*PdxQZas?uphc!*w1^NBTTv%ug2I6}X3o>T z!Q6OK>#%H3S5+=7%V%Bq8`gh5dob0yn8;wpy%OH-A>8IcA4iDyg|z0j$TBsRKF z6)%Cp-O+g=LG*3b{KLp_N_MrN{?@`~_wSjGVcva#=sM+h*M2Ebeehou&f6}~-8f=- z<678WMWf2BweiW)trfSit)(&1S|X4E`f@kl4teAF`9-L zgP9#YUK+DFkLGby2GKlE;0u5b-)|OOf1>EO^(jVR!p2qSC*(4k4R$j+Z{}rZu;{iK z74+z>iMeZkJeX^hs<(IzlQ&XTbO=J)63D(rX72<3RvgQ0^Z@5Y%FLOe;L{abSY$bkWEk5jSTDOl`DK%d2(l|Spp7;hd z(mhI>yjkfPJt=Gq_FcMeka2{d2}$&tq1i^97tW!9rj2()^IVu~Auf`f1rG)#b*4M$Dvnw544v(p9vs`~l4=y?OFh0t;zW8E)!OP+rf`10&o&mW z3P&TR=WV(R49^EK=5bmFp%MN7X_GlJAKHggmw-E}gJoxVNY3%I$VM={coiu^1A#i9 zm;|tJ?)$`XXX2bJDJQR0=Q0tBz%tf9OIWb$0tcZKGH)-LDmFwiQ33IlD!P?-Iy~Z1 z*67K5m7K1Qdym1x>wA}&+R}khvS?_*pqd4=hq2L7E4~FSw^LsBJ!rGnAk||>Zf2@O zktkbNq<;6g62E@i5{6GnJPd3A^5oHBAa))fPki32o704~J0`@YV(pBuy-p)|S~JAo zS!chhQsvRE2D@+>e(ZweHooNr39H)AAfGe?@_(8FI0LWG16a1 z&QtpRz$?3(Uh{Aw&h@XbowaXABg^m|{q;wBPC;y2Iyq3wsfse3a=^cOdXw~tDPFO> zgxE-+azF`*FP7x2{s1Sfx9#1yuIltEA?B;%ZZw$BR z4(P!Yr0sNOcY5msYT@o;$SheCXGnf~lq=xo0_kuitZB6&UDagILEA7is#ovB$ih`D zpTjX;=j8&CJbzvI8uOZFg-Dv<0in(HvwxNnZ&PpM3EbJ>&iMfy72 z&UsNw2lyU0i$GEQaa8C#X5>dh9V}RW=DJuyZlW`(isUU=r`}l*s{_3WN&(c?V<^x1 zdLjzF2GZr!%9`wnmIJXen%0jL(|EX|qDW_F&&|)-55>L_?3Pj;qCl9k_!obRzO@@` z*OK4bp4wj8Z5$#@f|$nX$K5-(3$7+D>t`8fEsZIH?E+rNOpG~1?H24s*bYo$w_|^;i%P zq9z^p>#7(AU{%D#Y)z#xCGm2g=?rA)Wd4W%5R7l`&kpe0s*dKf&9RtIesO0&^WaAg zv~K@xIt>CE7@ts{IFHy{H-+)l&q}F|m?&pwSEJVtjz+Hcw5dkr$s#g9AUMdQAZl`F zdTAlcRkF>>@|cN>+p88gyvzy7J7=CSm1m`8#1Q19_CopKQ_PgyVp)k`xs|SGi8_3q z`W5$eeaVix-iw?;%pKVoz!Oj_uB!5SE~93ed7F2{gQY@Wsec{2d$%bSXZ@>aZ`IqL zAD}xcal*p8yWfdh_nIzAxWqain`Zal`-g7HavfwPx<>NJp9b|FSZhQnRJQ>4 z32;T3Tg%QMGjU&2pY0nPo9}E8#@3Q-UTi-+fPz|St59>j{A2`m*6Ml^;mDp-w<+Sl z)M{3fAI@*6J3Z-ScNWzmN!soiYEeFx!Kj=-M2Y@SwFZ#976A(tlO(6f!>$VlX?)fGE6w-b11%+J{m_* zG{b@(4}{unily|&iycn*!);!-A|n5}UQH!P?JQ0JyO#`CJilpuriC-U+F|q%IKlIG zAB6TI$O?G(tfhP#Va)HJr@d?$QhbgY^RD5BUkNZKY8}7_x%@I6ulq9c%#}jru4|iYJ11rVXamjx}apzw8 zf>zwU!UCuS0)x@LI`s_A+j?WNU=t&HymdDH$k@=IP3*PO+|3QT=N7GLwR)@TL3X0* ztxfixmvrkQz4)ztX75wUU}kw2nDHo9Ufc{mf9*&^;*+B}f18v4mr|{QG{d|<(5zcS zjJbq3ZP8%Jj=mB0R>k*jTY>iWnVy!C!~*_wB~js(yK46Cb7AOzdq_tJ&)m4q!TplEbO7F@OMp{SJ1~77@Q>gr z47olWDIz#BG!%ymq?*aOjO^A&Lu3liA&;73E$brfq+?StD4hWfJq^xEo*Vayk)5sof}Cg+|}MbAqi+R4W*V&5GLG;59z#^I83tSTi>4q z-?(WI4ZD04NC*^On--Fp>;H72=ExuC30EQxgoBaN*H0C~#vdlZpU8bVlSj3^-AWPP zE7a>}Dc$YF$@UMjKma&ZCfPybV9owLQS*2_Jv_avWv~Fo1X;59+-m>&t#WD_mfpL*>7FxdIbh1?bdH>s zH4EFOXp}{VUY{O*6sg^!p{@Z)N8}+5OcvJf0$wp$iY^u&5g8U4Dg6WYLarv#Iy06c z`>AsNd+}QptaVZD9k{d%j}@78F4-G-5LFCZ0VUqvAWEQwM{)sO%%8R`!}5c@T8;Hy z#2%{NqlbFkfBA=7@v>ex$iyikpc#NHf&e~Tak$4Z6k4uANRbD7-Vb=|4u?Ex>k><+ zc*HX^G5ELnYL(5Ig$Ib;cK_uR-(U=>WLr_e1V=-w(zwHs;x`0Dg^>fMAhtmUGdrlM zNCP)pZ%YIMn3NzhJ!%;+@{0$q$&5SaN~pH3Zrq+kY@!#OO3lRJN)Q>iLlUt?sSxD7 zB8n!?1OMq99$#_>A}_?|>6_W*=TM8lCw#bAiRA~(uZK)!`=LNha)TyZg6fa6Aj-m4 zc7Y&+INTrMp#k7mMHC>eV!?({_NLejeX>4!spD~V-H_@sqLc``Xr~6MU4%aF@Up0=lY~zpN4?TtUEM*` ze9^BVlZ^&`^mL-*bc9UK=g9>vq&j3*oOk&z1Dy;OtE4b`p`jWSSa_~jsNND0{I@t` zB9l^A2`$0sfK|Hq_*7_sma!IBY#c=mFA7zfz>v*UD@tM^MAP|=&^9W z@13HH$>kjzz+ejsCaxtEE;W{IE|ls-3jm~97_-hDTOaRhd+g!ZM*-I@gaXr2pPnRR zG}7t~*&Dz2nFxZx6jllHPSonr8n!BLjPbmxzjd& zeTrcIW@P00#*Z|HXa3`d6KxTvXJ$7>o@4;GY?cp_z-#2pi!Zk~9<_JtuJQ$$LyObx zo!n4!+ROo3r@&4fmFSwvB4x|>hE{S^?{5tTZFG&TscvNlZA=Zm))_U9SL|VxqyjA1 z%KtatJ$MFrOW$)>-}?Ix1CP|^!X?ebtBz(FFttima~Lmhc8Qpum)-a4&c5~P(6h&W zGb{Zob6Yv*y3x(&qO=I!QU?Y{2&HJ%g7d=SrHJ{lwOi@f{yjT$t? z9H+Op4JK-$6XoyY-6+D){oOeMMz{pi#aq7uiIASNPFmY-lg=T3{I^`-GGZKjEVI4; zO^esP+^cRZY5j9!4ohpe<5y|M=TwsiCV2W-b35%Dgw3fMl_}hZH%t5jI1Q+HQ@SQR z&AKlCi^o5_5UrNH_@Y9CPUsiRWrYCCOs(P!*mV%7brwxLMt^_c+YK5L_%VNgGm)YS zVF76Q1O=z>2U?t?7yo)3!_P;n8oh1w$Up6q_kFuJ?O)XJFhtUV*8D^c126;)*46Y7 z^w~p@xHu9_kCO(PwE@5bf56o82tF8$0z(?mT_5gAE7IC3swR%7UG-MU{+ARc#O}gq zh-=Bc8#hp$-ku3eXLF%!fuIrq1?*xedU0vWEkksM@C1Y7C-ed7^m_u@Qh&s8mt5e#~)xd0Y!y* zO*!#ozlzJq@xF`r)Bf%(%AX{gCQl~9Kv^R2cwgr{=YeLox>zg%B4bur$>EI-v@}FI z=W?pDG8e8YQn_`zMy?$a$TmFi!{3pWy*F_Pt`0aLkNhs!LBsO~eY*=xBG#DpC)k1I zM|GZDnmYJYr(>AJr)|5AzOCrxePHLS5OOozeEEqLk9OD%o@OL$o83UkOGL8403~T z-ynKy^Zn%5YC}-eB-`X7>rkvW@@~=Mme*gSR|xi%0(cW&VGKQe3BQ>b1^i>@LqeRx zhB$<<)Kh`uFii{;sayn6Pfjvblel-|FEsSy9^VWn*a#d{-D8r(3s=--Fj`_C?n;~y z&-iBG-}Zyx?414TCH}Ff&lTUb8g;e4EQT#3vnW7dAUq%@0*m=pZ>1FY>r{8aTu^SFt9GY>)(;(NiG%gsji50jTPrGdfIAVW-uS-ZAX@7Fc=^ z8gjB2iCB!a6w$$OluxW>)7pXesh?INZ;NJ%m`+{QLq4a>K9F)NQVK~*h;#lke+S{fcfZHwyx zcYZj^+&~7N*M9klo)uOMDS<0Ni-RB@!1IBDK}H%gVF@S8LMGy4e_nNoy34T zD4tXV%Z!CViy%N2JhA&ngRi5>=EQ)ZDxQYN!^OAt`c0|G$cpzIK|#ghAmU&_g2RC$ zm8uEpx?z`RG(UfG*m(W7pz7lT-*k`0TLY21>18w%((hlNR;Qd}R$S<^RGz+YMiZLR z3f8xrXp_L>>zn_>9til?%}wLP>D=aVr<87cc3{G0eFpF!*hsb>O}@H?dg5?J`bj9cNyIm&xc>8b7dPO*CSv<7tC*<;}@EMWKiJfql) zQ+AcoV2$P<-~Df~|MRf*J5;NpTC4Pv{SH3AL3cE8N;@e2JX2cBctT&2dtda?NJ%XZ zltF4iwa%y9Nlg`Sj%ox+waw!I+QrwSAm4p#+yCfx?>x>?Gq-jRS7#{pC=9<3DjDu zVeTkFTz=ld>72Wsm$JW;#C?nQ6Vxe?#V|$RK&lPQ4sZ!ucrAwjPF#+g{exTYR7IuH zbEVOP&5Z6>YaG!xIHH*7B)Ms>_7Y*ir0$<_BROnL!GD z(_mahZzCMW4|>g?U7!mEol~#>wTjb+pS@d4+%{z4g;B%8C7_fH>Yd6QZL(Tw%gFfm zk;<@vfWC`U#n}@(Ofkq}2Om4>QQeBVyZYsC4$STi=bVC!7a%eKN;mvY>>uog=?JRY z0V-|zenf9Ofa(^9PVc+A1TxA;xS=TA)G%pR2BgM?f9$?b9ysqZK&FE+`9|FhL)BG3 zpSVj)BeJOWL8`+xGt3P^!TWw)NhDPfA^jPV@!7#Lf!vb3?*Z(x`~FXzxMXoz+!^p% zJ)^nn%j%xx`d4vMEoihvJ-xn8i^Je!E1m(IAPBu|x)l!i3eNzCc`?(}336{YIm4Tm ziB+(BbA>mmvHOr8b$T9mxCPUJCRvsw$%$d^At>MWU$&cKx$aMlY!Eh&=SXjdf-HjD z;J^q(I!Og?PlWa~r!W-#8^UbCLr{QALGgX0EHG50f(*MUBGOyihcV>P2e~nCYl6S|N5k%hHm3t|dXX<}YJjz-qoVG;p9Sp#=+C8DqcrY?xT7j5Vz+T| z_XVV|u&)jlL`VOEeGp#N(N`lQ^>pidJi_tQ%>b&2b;F~p*Bz{^aduB!tie0uY$ln( z!9AzjRE_F=Z_)a4#;JZ;MGqcg4p)N+h=2Rw8bUIsjd<>6BY>0J^hp=R$op+%YAe1BMyLj;nLMV4_dA|oNT zkT}RAMTy15jk&e81Yk`|gaMP{oRp31$DrwXU&ldkZ^}&0c72r#^=t6OA$cBPzX=J; zrclW}kq|8&7-Qk5vEJ74peFtdMoe0|=UF0kz}0qQ&$tIp4E__~W}gaGWT+=VK+xyV zSO!H=lX~)4W#I*#Gf$S1X6P4Cc-qn^hvP>>LkQL=Kx(NCuBMJO*vzWv`LtfyIE@Rx zg8)hM|Kwy%cg0?R8i};>o>hr;kjQ+3c1;g^YkHM`M1SRbBZTAG`=;p>x^S|hYHwS_i{|UZs#D5Rz`(PQq5a|& zo55zEf~2c>6!1f>Mc*EDOSaWg7P}r)C(PR8(d(0|1mQ~0GanaL$o-^{{O!9#l-u_B zOC9Y34m(kecWd2I?yyPB!fb~psk(Y^Pa82FAe!n7Pn}{Ic%};k**b$s6F;VwtLOvm z)hb3K4!MHL$`E(;is~Of29^wUz+RP2oNb5^EzS-$hHu{4H^}w}PC`i=Z|jom8^kJ? zK@}P9aP-%)OA*xVf28Bj@|V47Aui6Cj=KBwTT2|x zvDK-;Xx^!@y3y_!0LTf_aKkIEep@uu3plXc77=3r1SdKRgfEzgh^VMd{$@(dH6^ZL z_jK;OE-Smd{GP%~9ej{cH9OEz0s2Gq-&prQXNqk0`AXE^3fZhSSt~2>JgL|_G_?0g z5m7nP(#=_dZ)CV0H72sQ1Fr>6{_V1pC9h)Y!&1w#kAhyTB-#Kd%WZ@ejWlu`n^fElpRUfS&5@zg0J~P11jET&q4YC!`4{ zfsahJE#NKjQBi$eqmhY8%<}IA)vdN@-hARTw+^TZT>`)=`bnyf3m)`Ie>tLo7(hcTf4e5mG|;VjAM6ChBfI-~Ra@z_|_25FMQ-A|EEXT8+bl_WM_2|nM)FVV@!p+J~f^&D* z_2~PPGBjvT5Pu|v+&0<6(WqlokMeoTF-zs5w5Ao`7?FVcD%*Jbfp2xMokTWUtj8kN z7*W&KK$ED+)4e`e9QBk&yRc2>MTb|7LL$4kA#a+ZmFEp0KE69T)3UD)J$%|fU7gsL ztER`?05GfjOIJ=^Ydg8OoB)~n*X`TlmGzbJsvOQ-dU?69yPUt~rDC`Fo8Ur9xZyT` zM{{~QcYL-cdU28W-%Xivp$%*8`xVB4+0b8uiQ6w9Q~J4M=Y71%(LHu{8Gyv)Ww?6J zcN$@S@(3~NVogwvoQZ#zt4T-qT6pOXQ9oCEdK2MxSQtut1i}{(S zeAVHmu$wzJcgKFar|8IJrs1Xtz~Q$G;9kyZ>+Uqwxb2GfR&q(nr5169c#a!yV)hO- zg^OmLW9D~)9fmJB_BVvw#-%Wa%HepBf0wf6K}VUKI_k<3hE)iMyXuQ z29cU(eQWP!-KWBg{>U)&Ga21GWZb2}s@L=XmBG@IM)3_4%*sDZDZ?1tEW%;@R&YDeFh~FmQ^gj9YRV!tE!CcuYmve>Mr+- zQ{Yo`nMW{@Y$j9>1sSs&!Po1O3r#OJsI zFyVUG$>`o+x}F34|CM~vtPSvh57oa_p~@h??`zqHh zvrqqM2Pr2TxKkOYm|$x5J~S$AiWP$c;|+)=C&fnFTh62rmGLwPBF$omP?8ibnmGTP zMD0_;jI)31tJ614GkXS37R z!x%w###=ep!)IR>8^$d3`jMgUI?dz2NCwwHf%t@}Y#dw~b`XqnaiFyQLy#I&TJulX z@130PL69qy4$AoRlgQ-H04Nb#qY0HBg#+Bn_S-O1jJg`RMiY#8rf|6I^=g2I1M=gi zc9=Lc0|J`a`|*0{C%xP@|yFWVOL_>-+3%fYMH#AIr;^HP5Br`t@tEBV8xv$6(Bi zhu0kKuK=TjD`cfv-ENQ!M5!M;$CsflP7M6@vB1m<1Ap;Qw?CSFz^@meLRzkXF}`4q11j zUvQ5k+ca*27xTy~3i59utlGj~v8cR5{j&1s*OVx(8l9Dhb>$;_$`m4DrW%dQ z%K&gP)}@W`DRNFcS6>4T8nKG-PrC_{&xLQV?2=iWpo(QAr;eO?#u%HIvb87?kINLF zD6mv|ffg6n;$78lb~0P8V!3*b&DkEVWDQ4tnIYI6w0t4id@B!6OW64K574+5rl}`t zs&~hki!ZINrgtpMOml^|rscpm4lJh<9`C#>h&?%k8aJF`F0<9WFPztKy}3 znVW|D3?ed185AlZ{)C>!`H?Di=eU969aYI!&nJ$Wz91?~3g&L!9{9nNb&c2CjynX+ z$gnhpZI6XRP=wao@aOE!IYOVlie#k>U6NZ@7s=n;xF!USdk|a@u$yJ#u`q0$=^d)Q z-iHQ-g}I&<-*N(p&np%l^;bxkt$NEl^Q?Ag_=32YdWEkNQX&WgU&u{$ka$7`ustfc zVki}R`9?sg`2z$@Nt!+LES}@!IiC*mJ2xATixuB?L-%N*t3BTfM=i8`QA`J5VWoi1 z-4gnDB2&KBl|HTM)=oQToh~VDN<07A;qHD?n=V`q>3G}jz4(U_nhi!Najmk6%Wm3w zyl&wc&HXePYU;^K+8qD2n(iSQj2YK)?;MWVs?2h3i+|V~X>Mj(V*^+z-KlZlA_pK1 zcuT(7C8a_J!#37CGflF{&H*6&vL5T>zjM;V+m_IamckP@AE+K9_3w+3xZ4- zC(b>q<#e9@5c<5WJq3h1)9+TddE~eJ{N8)xf9l&atu^2nY08Hm-|hQk&8}-5Kj-*^ zcv_ax>BJ;SX}EcFhe(KXBL|CNPO`TPv-avetyxkb6u~NT_O$2;aQ?8fVur2}N=IEz6N?27~lDAQMV}brnXFUspKFPj9et~&}l=H@6 zil{OtKgl1XR4l{&$ED z`zK(C+pr8|hK076UWEgP!XuKN}bI3 zGJgG%nwp0u4%F% z!d3dy`oaz8{C)DO+5iAiNyYfq7t+?8Kqr||s~E^oe7K19Xlz`>CXIDfmO8rPWsvv0 zksfvjdtCWFDcN!m7%VmxqKIUxPc1Rup2LV)?2TC8+=*-sIpbt^vfj3hEHRYHuj17 z!Tx4ARVF~DNd#cjg=4ErrRl1-mKwrROB_%jVxF8m&8XyrYW-*#03V6fjdliO^Ys)! zUOSS0R2363fqPMJG?$1~@$eWuASruau+h@tyv}H@Y)cPi|6H1%=W^MlK}OMQEH|FV z$kDEH zF~V`DGV);c`fMmbvb6mGqj;OwSBJ^;=--B)Qs(u~nW#*|p4p_=kE%xh=-cNxqEeXG zN-WrS_$>0*wQ83^R^$=x+B~pvcA;bDmI*PzQ4K?>I-Z_jqxvSl1QY?b-kSd8mR?|d zXCG~TwIjQuqBp9{$3&+=$iW2wfp1K8y1SrB#4C?kixJK9H-Fja$SEflE`dCrf5CJ} zU>rpH7nTCnrN*qqrE-HPbEX|IxCVGFYB+tcbDcg_6|1 z8j~Y2dLSL2lDqjvA*GT=-({^fyjSR#Rz|#ofWLTc|4=ROmDK%CcA09v}r*YwfPUYm{hlBBl*`_*PiVw zcjZnxb%(L(VE_R)H74p7u`iT#bO;y>_T+fYn5r#1uvFzl>Q&sx2oKGke^9L=8Xps) z_=eFLLsfk{OtsP)sjUvkJKsCF>~!NO5gOoevW+)ZQk>C6wd=!5?Wv=r$0cdGKUGLU z)E+C@1s1j{D&zM(~SALGIZjqv$1I7Vu_E- z#>X-i)-hpxc{#MKnVro}yep{dom<=}qn-X75lALCG%d~a^i`{9b4gYCq3J4DA3?mD znj)h@@}`|ZSubbkPD;v~i{6Ky$!pBCsC^Cn3(9lqaz?w~2(v3MFNYY`)POC)x~Hgg zYd&T(I7Vc}E%!Ea^a{jVZw+o0o2>5Jn(K~ZtK4Se-OX$nY z*L=zH*F58xs8{sb)%0b&W7LoLtUXd_pi8E4o2Q)^p4TSQzp4lF%+A)QHYF`)Q( z(88^8$u-%r?+`vJPihxnLYOzMh{Yoa`+hyQx`-pw(2}YXK2>7;-t1Z(Tc_{z(FAR5cnMNFAj6e8ef0cEWz`fro%H0I4?C$tOf* zP*-5D-NxF}-&fvVMmHYTJ+o zhgN=?YHgZq_&;lA2kFmDNqLfk;Ardmjbht#9?2v;)tP2724c!7+8LKS)2B0U_SZL$$ ztqy)3zX}YD^e<)fEOPN)3}^^q{4)^g>6S98@i+1j8Rmrl)DK4EIVk|}iVX9k1s*?3 z#LFa3F3v7>g1N7GAqQKcekHI$h`9|BmxxebVv%472o?E42-4iRO0u^#I=8iu9vTwN z0AAs=%ZHm5=sH`IppYQqW-W*atp5`;>0AJ^xI+$Y5kHOe&i1BcmxEh<4adQgG(FV& zly#$u{qV{@U*BB+xk7q~(iS~t+T^}?*#3m~OhnGYYDzZ1;zGn_rFmqErS3sM?^enH zaSQ_)81&CA-c(jI6SEC*I~K@xkc@Z)nEN~s2g&j^#J zOpd|srM0OnNN1{+$5fS)_F1|D2%)lvWr69K0s+=zX*e}jhS7O$WRPXA&8@3??Oz6j zL&mrzu+=T*dPWITUa?>0olQbrI=j;%*|jNxm^XDkYbE@vFKJ=-8BP;Iyl@2E+hY2>{_l35K)9J#-f^sDzblKy z`AXVb&72!Te%LMDhE$h1pm>#r=h7*xNAUo%oHn_#zC|7bf!X&lHv;CNSB&RSYb`@9 zzK^38JU69ce(r2qZ`@5i3;pyNHFNQusr&A9OrP=}QLr-v%S#f|$-LNBu@_Dz<*Qc#ePQR&Y2I+srI#_?2yvYAih z9wGn!9B{!NNe91FkANld2qK1X=s&9<{42U$T!jsZxJ&JSvL`?wui$b*#62dqUU>8! z({IP8PFFsz#E`65PZ_PF)}rKO{x_mw@q}UZS8(PI+t?>Wg)I7zk!)(xgu{DgvP;Uv z!N0|9^Dw$BEJh4I6sft#5@Z8#`T~l)t%i88bBVfthSu%&LP-fas8sJCc5_as{m1Gm zMqEPTODY1M!ywZ_oMi2ht#X)I8EIgL4Wh{>Lc}t9^eS1hFOsg&_R!;IjAotMh)y7M z)=^;%QwvK!hs!LZ*D$E1i$&U%xi*I%wwy-Z&P;YohxxaT_T|IW5lOL_;BN7-^gEQ* z#{cI9z&vnb7Gd&hj@^~Z?7NugCH=+q@$`1-_e_|?yOdl-TaAa*Oi&c+#tuZo4{8Mm zHqa%XQvwJ*r_yTLM)&*Yb{bH6!3{(c)QyN;#!27rcw|?E@$i^Co_iWsr9zhQ4{V_Q z^9h@RZ3vV2jP|3XR$w>wV5qiN6G%5PMP&U+-E%(67;%JOUhD0*psuW3+m)XQqIHF! zyogG+j+<+Ez;wu@vqA!k5`gEAh0;*B5bG=+2}F;rweAEdc;xNrazZL;edqz3F$oT- zpwfb5*aiIMQcYV6k$gk5QFPHU-qdm=-iE6>O_dYnK&Q$RE-T9T2_#HsY zl%N?%MZT3KD1pG_)qtD_!NX1sWH(RSiSvLa49j^_lY0WvYieqTB=KcL35ZN;97Pdn z_OjWumuXs6RYmtHDZ<`*eurv1q=9Pgw5?)c{c)r_2$&LwH=fp>n$&49SCxygLV${@ zX7SAMJ1`JOMcmc}d~rJvfItnhwjf(;1RFNJ!X*+n(O~_Gu#lEKml6P)18yn zcP?OcqNO9mMW-A5>3UX<-97nV8D|eQe06O$H0HXHd3|ySHw+3pLNa|6bV3;+E-D^# zBb#7py~g`uZqIF-H2XYR4=#cZP^*YLd93I;TaJgZ5)Ue{DC~+U$ubo56dL* z36Zn9I;zpXKaH)NQr+xLRE^nK6-Xz7K5PY%E%;QaA{IUB_Mc?mv1a4Dpj}8D2u zR~dQiR2rhSRoJ3*@XZfaFt}U z?w%iMj*VOSk5^`gLbrjkzR=1c)%##A1!^wBqk@H-0D1GIOJLrcYJn`?E4-1H zp4&O~{+r_=lcQWG`xjd}Zol^8-5wR(U5#quZ?!1|chOnK{jVRqV!U$X9Z$1$fE~JL zTco9F3iH1IVMR=yvdy_RN&UwmtomzpO0MO-nosUd>fYYB;k)jMi>Wzvd{meKGy~2+ z;_!JofW0ld;#FD|wzi^zriM9HmLCQEg_OdTd2oczAFZjYuld>_n92>Qyer$6RB&-0 z$R`d)G;&l4QZ|)~Lt&$f{-#q4%YXZ^+tM=%`)(PiG_Z&Y7%+e9&`wW=8>+yp1_6e1mrk=dChMD63k?rG)p&7u_+;$p zm9hb*WT{+NvgR*Q=t;ULz-_On+4>)yyU}qT0dRDg$hl*OBPxMeAqu2X7 zayR?-p&|W?ea&`@9gd+UH){VT8tJIke;rfa7gla@;N`w%hE#dN$)n^_x{gr+Un)$X zOojY)!r-sP5{Y&lV};Ty12f(ohDSC@O)Aq6{c}yjd$QTYGN1V<7Y4KigCZwG6mqo( zt)}$k_Lv~@B+6~gy{iDC;=X-u05x*s8UNOmTb+JIxl}h|d5b*~GSZ3B^gGi#0`H%d z@%IMnH@)C$wrH+?P+g%*O^p8yco3CyHRfZ22OQ#&^KA)tp54_TJ* ze6(A5#K3%St_<0NsG~woocz>IR8HQ91T@hL65NW|x7buBMk$$!fPkka97Ul>K}N7g z3%g^f7K>1F%4v(9Hyb6t==K*^MZ zqZ|dju9~`g8i!J0+joOnPL1{?3Pt8e*#uqVRGd%K70wh&P!c&vQ8?&&M zzr|50tj^0*u#qT*msB4dH|kFjpl#2#c*RI5&K*!TTSOQ3`MV7MjV-X1DePa+k6D{o z3ysOi{y7BxhFEhn%945mVjX_&|~cXG`c>#2As#~rG5UuUP#-#{)qp7v(%}?$9T%Z;#x`8A|raDt(-5(9ZoEi&TI8zaO8CW?`A=N3mvl%W7rv- zeqHGL3Lzf0ZUmKpL&jAO=KPPUKdWM93Sy1Eu$$JV5M~ZC7GP)o71KADh9|+{5(q@S zwJ9t<62uo(%*?<@N&ywYzYrqS)DAEYvNgf9Ts7f>f~N9|&=w>8CCjt2vn{d;edeU}yFzyuZrPx-_xBTc@_>{u##N|!bQq&7=a@6E3 zh^TD6qCyhCb~&_`QN!k=`@Xt{=~!sDP2T1qWnLCDgZH;WKl`Nlm*Mf&c2CS?f42XJ zt-8v2oHegsaHdq{a0_sQPCfK?{5uTVKqo3?g@owZTJ`2&wGX1e;cZy|G>txL@g;QR z2v@zm;mcRn8F20kalvZ?z3;Q((z&PdI~5x`{9eRk?mzkEPS)=oiR2^D z08Oa(kjn5MQJwy`E7R8$$MW)PfZlZaOjH7hu>);BE~62Gg^t`PQxN0)^3>|Nm1?rh z=U7aVX|lDC677QKo8_{W(uq17X_mMas0qmglV`-?&Lb$b zG*F9hLfMggy%L<1wCxWi%r*$U6u=^A5%0M%*QOKXSzmW7xENETSmXq>lA;F^4i-a{ z3eRChC{)d;uKxE#`EuBRoh2HDe$|rglkc|AGFE@W14lwqk>YVw`x}+aBxa!`jRxmv zYhYLt!QC&iR1{@eq7-H;URx-h5g4BL)WC}EmWC8S3lV8g_G3CyDUg2%xJy}oTZ;oI z$tB}K|mBGSihlHu6_z0ndPUjE=iK2G? z7GTg+rcXJl?w1S;8>~iW6hyE51RWk*?{_wBbYCCgn`t#r#DA<4%j~L_v`h1J|9nP z2L2s+AFR8(Q~xri|7&gm2y2AcdmYNdzx}R^-=xWajD=uQxx4PZD0FN&zhg*ef7Xu}DuhHziGo zT%sJ3;ot`QcGEz*M8}0cu*meO>;%_MA-oMsj8gR095KuucLz;1tuq^xvde``akAOl zwz%_2mo4{vJnXvX$CUo27Xad#u6Yg^ZE49ebp=@U0~zk{X1t{^%WNCmYmQEbd46sN z?(=Kgh;~Ii1WaebbRW<9?Ua5GA;Htz>Lfw~^Bj~FY}R~oI}m`r5w!H_3}RHAJ!Wx0 zeG?M9Cs9|4VtpTW&CM*kI`h79XLIsXTx?zx7;E1$+yLxN03!YI7r!`9*QE`^a`PNq zPQ|X^(d(2FQ^|aBTYS0*9mogndnj z;^DlQpT!Rix9`IKa3MqIn9@o^p&0|yXMgu zdY~K060|DjQOU}netx<%<1dODN9#$RB8kkDhv*;HvqjlX<>igm{kJ0zBITh7#bUKj z)8(j0+uM~1MtdLO;|F>B5fm+A=8XQ15kKc~_Y+)i^Efqaj8wYfCr&bwQk6!7BB8(_ zjZ`yL`YY~F`J;)?+x2X*#4`@wxr&=*<@DZJ9lh?*KUa>ml!AQXI%6f&zSLrmA=L7^{`&dyYPhN0jsZy6ZurWa!T4LWccQ><=Bv*cII z{I7&fzljCCm-mI5kt8g6cmiVkYJvF8Gajuu671bgxxB`$9<*@gdBbX8nEKi zTwml(ZABXVW(Pr_4ATzIoz#EcRQ+iU+S@0o{iND&J{F5Oi)36R3bZn!AVhttgWpABWuz?s=Hq$XhQsL=zD!(rcN`kbn7P@8UY~rPE=6 zw_to1=tk$I(-4~ki_x7RyeJq1e-MEGtASBrttmdYd%!l2%E;(hoDmw=8Gr66A%occ zTu=S{hW>?!bzjMYL9y?KKto#PD*>c=ExxaGacgxh0qL>tqUOUdDT*^Uo$Y8ytNk1v zN7?D;v)WTSfJ4?b_P9L8T2&8}5PlZvmBcf&MN;2KqLZAjHY7|+>y!lNsh)G}u2}q* z&{)*p?;9Sv?nUyM8PQh@e)`ziJG%V}52I%56298*yZX*U<*L(8=APxfK#QCSmpp8% zwND4*4=ONC+Cl;Spe#Dur6Cxo4cb5hQ!%Qq3ElX$GRB8G|E7_G`>Ai}h{5T#+2x{U zR61Vx=CyYc2v~n~eZlFeQeukH4%UO=r?H$(xd@S-hP-vw=s`@H-CI1!_%L1 zhaBEv~>YmI#RS6ZY%53yYmM3oW>X%37fPxIPn@(Ox!U*hCEcNrRx`$(@&dQA3LOikY0y%(*u^`(M|0=`X^^1qRB-d!qH|8C2swE`KP?U@-l| zPjyTkRn(J6^L`oBZ-`99udW&!>ogh$X#Tk=U|^?_uzWMgb%A#uXV z?uh5iKuv#ws1LgDQi0d<()B?0D0dDgbsTbQ8-+s)jW|`o2@@t6JU`RVAN_YL+s|Of zjkzD@r2+fX?)_T&g#inAMF=4Y6a|A$n7t5{u$8y~rFc*r*yPCm>s{H%TJa@eDyt_q zp;Py9z{_k1Nqhd&0+%~y))6&K9?f5Ax?-+TD05Nt>lVf+-Rsi+)Qw^CiO>7LUzzbT zxJv#wTv2|-5j_g-Mfz4~i%n7pK=lC7bGh)8uj;nd73sh4?#n}{*bhO8)vVoCdxQ)| zzj0tula=4|C&RR-{{s78T!>kXqoy;@7SOZ87cZ^1zgekl5UsncF9<_t*DpOTI0xbW z69_|P8`Z3|qr(NQE=xbjmBv})1u7A@tNU-}$8KRJ5I=BPY_PU=#f9Of5e&w6)k6;D{h)>^yp~u(kBHxB4|=zzhA>gh@@rJBFh734b|b+O?!){p}z}asLVkSnkFu z#U{ujZ)f+E;lZ9`4$s?eLp%hABfa2!`JjU`BZjH?Jd{mzZhGR`&0u2~GL7^qmaR6g zPyn3*y!5)R;SrmMm?!wNaWMnxcnD}?Lg|$*RPj}$3#zNSet;g&M^IpjvHD~U!fjoI zXxCeqGp(iN-E&H@7*N*8?!tSDhhKS2XF+0O;F_PfcyYqP<^+~JttABPliHu3{}O|_ ze=iY^^zFwBYITV9^KgD+X|xS)Cgp{b^qGCFrJI3Q%}cYU<1#Vxkt;Jvk3jLEOX ze&2e(fPlYv!AS!IA+=>-6JB$tj9d(;V!}djk#^t#X2EE&hS1b(&uEfABzOXyvjeQ) ze2odhf}lF%rvkxFsv@H@Fd7^yL1F$H(7e1!V+=HT(wJV|OU?yHU5-&WIC<25u?Hi9 z{R7h{&e0SHK?+tf>k%GYxgW5DB_$2wKTKAb;=!P4uFDeBw^p>6naSN_3|>Q_8^b3F zlDU$wu@%8B5Os2MFbwQ6OQ(ZTO+ST(1gfII z;+-Pk(?Db(nlaBH05A%8ibK($%H8jv6x_5H1lf@HlW!$aX3wIK+tiR0U~4l}2kz4- z6(lgNA`wXB8pO|BHVTP&@14i?c!XE;J4m6J4O=5oauA?QLgZvjageAG^AtSjJd?qm zQNxx3ypfrdK+knIGk!W#B6FE#gTcLwEm|4`w1 zp|M5wxUFBBZoz}?GRBR zpL+7&WTzhAu~4pc5#^)hK0{RmmYaWTPis-UijDKEYYL+&1S37@%{Z>{W;d@FV?z(N z0?GeuabR?3(_JrFO>>v{-7xLHw*z6XM5m&_{g|3*LE;TJ%m zLSSmwUj+EfTxY9}2?{!YEqRH52)?PEb>QH|Jgd<%2mioJBLh=N0bj3bRu$D7b^!w+M9?b=;HI*2cF1Efi4|JNV$%`Il3`fwv+hu z(jOE*@WDcXe8b(2!`Qw|z5cmd&6aH4%moTwo!GfnMz6A>0{A1q#@7DJIP*R>ACe5b zsdp+lboiGT{Mt>WAGNPrJ4gpfO09jsE$J38KM*nRZ}MwyVWxFDb9g7dC1D;|=Nfe@ z2I4WnSDkKx2F1>a5<27EUA6`D&yORw0|LN}F^rT_k4pN5C z;oW4O$$ob*kI^OMKl(AEyNCLg@29*rK+3k#1h6>&%B^oSk5}e7{T(4r0-bjKu#b#TRRnn~y2R9nh=hS245q&i4-a*SZ)m!x*;T@Cw_7S|3 zqcE1gGdm`~G&UX#E<{V3*?!_h{e3$F<-3(7qiNv_=yjGv)EKeC|8LRYSHdAOB>MWt zpabQ6a$0Bbo5JWZ{qCWEU+uK+Bsz@C(DX^($B$%nt641!05bZC#}#)qpVUlTgzWAw zJWre~KW=(S*_rIMK2XqOJC}Ilap(<$`jf@}olQ2DZziIvt2(bFsCv#ka3~JQI0*4h z>JNw=fL{J&t%}0B?s*jCWPyFv#Opm%?5@2pPW)BrguGR5ah-xN7Vf#lf?;+Bg0lqu zF)%D73cC%t8AAa$Q!0&dq%Z&0E%JaW6y)`2R-4~r?NQ8N%g0{`^kR{sHuT48wAF;_`+AS zh0y`TJ^pg}LA-3JHZ-tpV3MqF&~e4e$r0=y{k1NR^qoX@*v2AgG!7yo@3I{H8r-wd zM*Ur)oSOTiNdT)+N>8rdy8}-Ic+;nve`3uZnRO(RcVZy2#x*fApAUWFL+QYiPSHEp zoB%BT<~J;f1KnHRC0J%bpZ%rje|DRh=CR;5>-0YlH9@yG>Rxz2H9utQW=4FJ)qYW= zM~5Mzs@c6p=#N2En<91)F>?GOrJeoE+DsZ?l62KkG)d4gi-H40{)9OuUfT{1G*n@U)c!Rejg1gzqr?N{qb@xtu{WbdobPuMn6hQ1whv)R=@>-ju+Jse} zt*P_TWKJj<@SN^gF?`IP>E@L9Ivdy4cp5wN_vhy>DhGll^Nm{sa7lJ{0z%)_+Is;a z5Fe|qJ{2yU0_|5NlDeFgEQ7$0LgTQ-`DFlc8QMFzGEg>g{(F>4-`Y==l^)4Epms(N zH|i3{J3Vr;0m!AF5S_aSk`BsOZ~6)rsc#mmcs}uI%%+aM%dK5apI?Rk`q|4JS`zg8 zDu^5B?igk9{_Vf1Y#jRCxqEs3XH#oY(N>WWy0{BJ5u_u4Ek@sPb9TO3J`gc8GVM{h z3L~ zX~0o3*;@wC7?w}o{Wmkz)I@SP9Xz*f-240PhPi3UBp9FCHtjhL_%( zs#_T7>HgpsdaHVs*Y68_l_sk!beLcy&7fhHEBxFlM}@!E(FuOPIDDoh$oT^a_+n3F zje~e%kh8P%;MzpQcmY7w<$eaeFMq`T$nNEbJ~b}@mTy0v_1Rsel?Tf}?DN47-SFTr zwc3>T|K|k|izBA&TS4Jr5%a3Eb4{k6K|j}Ky37Ne+MRu~wdb_>ZqmKgPkZ~hmpNdt zmjjO;F46z09k$bOMjQwdp`RLy_)Sey`km9Amt341g3rZ__Fu{dqt)VMPl+?1r_8(c zhR;_{b6I=hyKd6(YcI$qHcqd%b1a6lk)z(S?I9{W2z7CEsOi$$x832t0z(&ERn8>lVaW!C>%6q94Xiyc_Kd zv=&krxCJZ#wvO<<;3aFz>@k^}#np4ezlO7lW-^}-?%!#jmS)f1VG-ESuTn3W18B)q zf{A2+y_=o2SG>AT#4IQqm$As;KC-v~`1$}%IgzB3#Ms`r2V;JZJx4FJbk(Le| zAs)K1@SoFLzp3aG1NZ)2ZCUl*pSFuaX(VlY99&bTB;_>FF0tDiesv$9#N$u*<9JlM=zDqE5&KYjjg2OJUo{KR@P!Nh{F?dS=NG-W2;*;u5ac|7A z0FL3x56JhC0}16lJPzN|&j3JcEW56=c0xS$F$VE5zr&+`7Ma}n0?Fv5OJ~==vsE_w zD(gkX!tgtW+BCosH}8n4%rRQ|0RX5E#U^FF);&E2CK7{MM7cU8ElVydfis644hXdzqM*n<{8cuZjrqG{-{lB&Fl7HHzJ&F z{=A(J{^xRP?|9&gf;t<6qiJexej$c@bxff%WP3qKXL6k!QQNNqF^j@8`fh%R1`GAy z!A&nskldUf=nw7&v9ujc@u#@QGYf$?YqDLPlaQwv4eCXL&CI=3V~K)sXG=dOmc{Zg zpTFYR%87Z}Q>HWdbF7H%8zBU;vIGR<{LIbG%)!-{6ElF;LGP%ksl6x8(&#iS&u*Ce zFA#VooKnx>{X$0CADAp|m1I>8hCXet-vG_2)WAUiajEPX_~`eu?$V7q-s6uWQ}&<; zWpLw$%j?E_{*}JQ6`3T5ZhC?i({kBG(j?JjhVG!S_Xe&1c!YfM8&ryeNlC%Y_7p~e z(m4=*0kvP0WH<$G28oj+lSxNRPhSlBbv+QH#U zndDg|)8E5mWF*!`MhXFI{sDMK{|h{Zd51>kP5GSDF)Mj}-P44og(R54nozbEdw=#9Bn);sUnS}Hi6LI+P}#q)b|jA{Wb zB{TDstgvojd@tCM8)YU>7I%6Qix*s< z?wfL6EJ%UE^p0JYwqVeZ8FO>w(4ebOsP+9ks&Vj9SaN!cflg&Xs_b80egFs(j`2wZ z8t)dTo0XN(DSzrcfUEA(e{h*6mEAQgsyQs0Yus84uz%$^oO7*M_r^gu&nfHh^ppqS(Y}zQ(^O`648+hb;@%s;(~iMK!cff1-c#Bi{&SqR&hL~$KRna+-r-8Idfhzv(_3LHxr&(k|_fYbt)!a?8| zD`qV7!{;>u(7r(2E*@TNM?_J7ZCKHkNnFI9d<$s?%aF63mjUBZ=@C3}_b;ZrqPp z4V291gx(2V9Q!CuaP02nJ&ahnRKIKjICu*~XfV@F1*Ig%-9bORqMo07_wP1Et+%E7 zkD~=UkrfXPw3_WptGC?ZW9eff3}a_Lj?RuL{EELtIEi4&Da9B3y3IcI*($&Utm3r< zIbqZ7fjM;vxCcJw^#LcsmWItHx@;QnokC~w<&Db#XCdAX_u{Ku?pXQ7#(&L{IJmzz zy(PR-aAE&rKtCE>^tfdHmInNb)h@*0`(&N~vUjIh|`DA#=hVbk18*(Ua* z`a67PL}0myh|Hsp=x%5IywqwlO*SYNb+|Y2IF@gk^{?;Sg1)F0Ow+wF-5z2l)ZODb zK5nf_uu|0vb~9fb_~;7Bt@R+vb$8#{@|BP!pO+wyN@qMvfD~Foo8ot$Z;3yjrx!vr zw~;Z!d$44cCiVRQt0M;-?ZqLV~wvqC#M8Hrr z@A#&kkZozuO+Z8@C^HbB=k@JM%JoBjSOo%OY| z7TY2ZRpK~lx_2N{RdJ9u)O{?#rDkNd}D$U{$47k=Ch3<-R}G8bxo9rhMN622MC5|46TjNx{matKr$= z^?Ki8mblmBbzxD_OLiZBKkx3x$7jv^5g!jdmv7n@8HG%K1(%YOg0G#Gg-1n2VyOt3 zjbvT(qk1sSXDIx>qv?j}cdiFk@}0VlW!rl6dF0gf%lOLrH+)m^Q2Wh8b z+Hb1U=>w)RrgG;|$YhAcRduKgGL|0W9jW(3Q@tQ)qjIAwCtQ@+1JVR$ayD+kn&v6G zTz{hS2aC7ytup}3KHSu`xZE@*Srj!ai6h4PoeIfD9Dn=6NP|-j(qTQ(UkSB$CVm!d zd>1mt-5)HjM$AX^XO`oONZIy{KgPfjCu-NgD~HWbPCfT%L+gOM;Ry){mrbBwhxhnO zhAw44jR3zV+HEfkU%U6TfAPn*h7VJ{4laK{X-mqqBxM)qh{?jKh*6WJo`~Se!Aj5R z1?;z!f;M0N$+|ZudXq+q&<*+mY3HkF%+ycJHwttGiy=@CgU|Wvi_2qo>zsY;iux8r zMmwAWFcw9w2PSWaoKu3RqbvLQ8(+j>+Dz7%?q_@UgS3^Qv5nrb;~4&{bnb{MN`&`1 zfMDtgw}-B8)DdchEmOh%cki0dt_=^@Nt>wotu7X`Jv{7wY}`u!ub0l)tc0;@ z5b^zwob`H87cWln7!01hQ^|KHdcScf*$m8%uA}-FoLlPpJz6`mPlr|T1v(`al3ymP zt9D_P&c%9iam_}jdbNrdoFdW-iuj+eG4D>-Ctb-8TI{F`6&|PCv)2W>5*|97Z#PZK z=GO_Mhk;`{xUTnAWm;PQ`cQF*hs*jq4-0nC$mq|}_m-q$r>ir{r%&&mB6}2QbQ&E| zaQANQ2w2yh&*VC6*QESo6-Rbwi$E-za zQW7Irh_ccqrCu1UVL{Tr2sseAlGo&?m0?1N}fDd#9UYDhH*Ffqbc* zJ{hPXBTFM^y$=6A(-t}=D&e1YDz-05mAV#T`1G~C=Fftlr{mJfCONCzQY~15epyU< zesu}+&O%w>=lXk+@w=6osYG(+=g-@Go)$D30%%#2MbQ|uzjB=PqvquHBHX#dYH^O< zKBU$m-MVk&O9s=|Z&fybQ~5AFw#da`ikyy>kupB|tu@pya&y+LOv=I}S)$VA@3(vQ z?=YtLWo#^6TF=grFeC!Mx`qF`!uQy*gnIr@Km2XKIkA(M8vl17zIJu=w#L=|#F?9Q zHSJwnpoV!{ervx|_P(`uHa+sNk3OZ5Y2QYEwbHSxglyFsKQk1{mT=Zjxh(U%+jJ_W zbBwmm_O%9v5A78~@6FG@vs4+LvZ=o%9PR!xle+XTbC-+w?~dg$LDM4e6R5(nIuptI z!-oKjT<@QAw)$rTPA2;TMCIjv=G*diojTROy{q4-ZKU?4`?1SMj`2HNXeU0miukUF zz?+J22DeHIf0J`Jdd{k3;J~O%ZgOgK!}@0pm#~qIuh&h`(w|)*SGs708t9!FHzudg zzzmc0F@XkU!^FJZXd(=!aKmJtLDKj4FH`s{UZrbTuIBYdr^&*q@6)HD6Q@){MOos( z)ulOsu6s*@$S4i}^xoJ;7P@}@!`_^rYLylKU2%_Oysf=VI zyjQ|gfvsQl+eQrce~8r&#FVCM%fk9f-*<3;(}mQnhBegG{AU+twi(~^Ge!%b5a4&5 z?0JhL^g;s2Yt*u2z7qV)tS^XosRuvB;Jpqzw$cfXh-CdTLraG2wRl~8OU3&RrBA~H z0jzyp9f3~T0KlFOxZ&Ca%yX)siO0*b2{HdHf>jZA6y>%y(;?~YT<*P5!T12d z8esC{LA%v=V&TskOQpBfEaqklh^W?DRI8;8{7`P%^@N46o^wQVa`!s1?65OOi>UxD z>^_53-)#Esn0dMN!#oad>=>h+1GwkBEUcONVGQ?5+}@-FGfTm7i-6nI+okr22WgbmJd~tHS1jz#pwiUvc%pf^-_yltMXY6>b}OD|piz`7M8G_? zUrw{unqc15qNb{SBJ<~PihrY>4S@Sep|bVV$sMc-hync&^YdpzzQ zi-W}+l$;u{qgP_URELzn1PX;Bk;55aPDOxZ5mp9^g_uGj5jQW|l?*h9KW|mB zpkq65XJn}|rUn^7#Rr%{&UR-90|Ns0c+YWz7uH=i-t8U?J`3Jt@eT7Vmmm)Y@#=F$ z`Y-&WdUnwCczpcs*4o-TH=15Y2!~Q$(+@;m8w{-Uy@~G;JoPzV6fpQCO~_ZS5j;r~ zY>YLm_*3!u?Yvul)nVbR#uC>L)2%vzIQz_rym zSG;|+DR5$Bzqp%uzH zV%tNGe^@Z-motLQFc?JB1zHI8*M}N3EBx1dEax3JGz|@6uc|uJHs??8C*;Ti;6>W&j3XTNIy4RTD`hF#>plXhz=C= za1%zB5vHkGx4vQ}oqhGHK-_}jCnV!7O6jGXc+l)v>HCyt#0T4UHM&pi!ppYHd8yrb z`&L{t@^gi&uQ{!^_Y}zEaFlCADb*D4S`{d3W3h7I1&mnX6#L9AhtyO(b<};bIfa}I zTAtjm5@2{GhURlAssFqSZ8`{UZt|k%B*uO%mW)=DxD#c{2JSMwmn`rrT&O zM{Si5kHL?WSDkuBxLU|`zsm}I*<`Zuz-7f_e{GiyShYcc@ zWW{$qD==bcuSY=mNsSloq_7_K{@V9bpK9E>?he;aJM}h&N8USm4{eswNBc;bT8&zX$v`>()L$~N`h8AReGY65 zrmor2IE3KHcZS*?8b^}Hzp0p~oXd~GnX0AB;4n(ssB^(n?9Z|31x@?>t)!wLcbJP# zu?c=xIX<#dszdp&=>hgRQ*>0#VE4q>GLq9x6xUOf5<<6lG+ zb&NAj<>2=P%|BP`r(3%2_5|>Cx5LHJ#uiYjgZE$N@w#Q#$z<3+o0B_Lz3nXv%|Rcc zxs9cTzLFFTmV4kao`JH`gc1IL5aEVsOcb6|TMnuus9W^FjTNxoI`z*-F)SmXC*llOzFWA=pVf1C(tl1%+w7JgI~%crvWX zQb>L!Pm_V1+s1hI8%XGSk(t?!xc>;@PCV+U#=)iU#)z1#1PGFnY=)_EXuWe5MOTwL zASLzBt_OCn zK+U~uwv7Uh5y+t!r=9^ZUv)FqNjvC5vRQ`W0rbItg*8DW2v_&gA2M)KDm7P&h&Q{Ed)VAX+KmZt-E=RZUhv=7a;NQuHa+ZGnt>C`tyu+#Rbdu;R z;iwgsO5E}skMbR?rCKsA3s)P%BhuLfo==1!XqR!B?&Ws!1-H^uZ_doL)z$YWwS7kC z11U6Ko0=@(8L|6RKxI(=hajaIvO}uOp;!uT?K!VD$j*u>Ta(I=C4Ioho!)$nbOEp3 z#mCsnS(q~PXhh&N^@Qo2NzPPZAvEK6gWf1bOX&PC+*6_W+(7_;7dTs*m3Qlb4qldg zhDD1tmSK4Sg(+d;;t;Dkcm5<0slDus1VvtG%rsqWm(N_L1?uy%iN{gO30 zTk<7sKu-+JlOeN9pBg{5)zM4Br~JXKI%sLBI_=kjZ^Z0eipXQ4ZO(i9H1}l@GJFT^ zyDTuZ;UMo#t`Q-iUbiZ2?$3sGgLQ_<^7+aU!>=_e1$zq$z#~wwGkOB8^9MJ+VY%@YHy}^5QbSl%>eBJr3_4Tbu z-C^P%t?1%M%9gNb(#4@$--J7(-AUu*w}xDyN$A?=^GOZM0}r-d(owVhUaJLKZ>#dv zGfYn=sKddXe}B!&ht|r7*?8aD^%dX_4c-_kYn|!3n=u}9h*`B-++XQ6N6MgAMNAyb zotS9LF^*^_to|9X6zJQ1geEGj0zM<*ohtuA{;0=>Is%M&XOC!q9m!NHd}% zrt3sSVIW?Vr>{hb0g8F2K6m7P&#fAV^@@`4W%0&0-wkaL72}ts_>orq!f%HkeH_hw zY2vV>4PBD$e0BYlWGX^3?&wRtcriiub_N)g?UPfPI~s3^#uLHQqBdlrTVYku30W7GfX#)-#ej6kQlie78`e#ub8a;C}Z?v3lz?1MQsr6Dz4Epgx@ z7hPKW>9WF@SrtA_<8Do33p^*G37wbYp*2;!&m%*hxwfCOlm4XO!fu@in_8UW)@L4o zq{;d`O)Z-1p6Rp~WLdXoUlj`(YP`P>Wj`hEx3~|eMW0VefRB?<;owA0>MIZLQ0Tv)`xU3)-Cb zQB))wl^3Horn)NkYgTy6omyq55caK!%ZqAp5DSdz3RU?dZI&E_K zyi0ubi09;1v8eIR6WxwP);+(i-vy{0N{>$KSsWpw)JqjgSYHXKF8sz@;p(T5Kyabo zh#p+(4pA`*t>CKw0(6B|qu04Ht3Y26ck`_Uk0NHOr>Li4E-`hg%ff6+dZ&E<3~*;$ zHkFk^{xc(fPVY1_ZE5aSJBz~DY9^D(dDXkccyB*+)9ULZtf~<0oo_kzMXtxTGZnCT zpd-F+x~A`M7|4kbit=#h^4TeeJ`7*P1o{Gd0O(${f}299x$;umfNzEQRYCQW)%~ws zk(U<2?BmY6#nU0poY_KB1_XhWQdP?*=`?Y(P@XID|K|ljaZH=KKh~iI!W~{Kb~sir%o?SB{4JJ_#bIXyr~VD zMZ9RT)CPqe39F6Y2vz++bu4Bsm6n6G(%)6Bk9#H6|K<&4?ow_|iI+Ar?!Q%^=D0=Udm*8|GFG zGP@GN?x(JAW+%FW4PGj9(bCG=R^GC#rMiBDh>yM-|Do&F$Mpp{r$gq3G%khz5O2I6 z+pvjO`4HLeUjmQc2?fS8>a%K1e`kW(TC}9sMGybBRLhcalvz}yja60M zN8N%rA0?NEq9wZ#X|tN9z&IrjfyzHrr^?`PYT!Jzuvn5el}(0xc_EJlvZ6#40ao6$ z-whsMNsE$`LmK|B!=1Hs|m1KYv;> z?maP)Ch5!BDAOMliorjpcEOUyTIz@#6-&O0O~QgVI(maAYa9zQQ!YqmQwk()1`U|) zMfjgyY=cf$lL2WJx^H|J(QoseR}>G(s8{?aHmy0t^>)at2Sb4IN5gc`@J z&dlo(4u;RK-FD6ZKt*nXnK$&G)Z5)Xe|=NQ=V&<-z}g60lTESILQa=%xhL&h1!vOB zo-Md#2x*SNzkC++{n$;rB9K$RTXXdGzK`&Np!Na?O$JVhL`1?6=??Z`#@n01OfEz> z!jXF3bJfQnEPBeq%aXAHZi-kX%U8VBy<fR=D&)M#y!>PBl$&XBlyH=uiZD;$G)}}{;i(Zgs{*z zzf+|8Vfk|+mmF7?YgFIIEH`_-`nn`MJvCQI@YelDlaWnwEFX&L!|6=^>x}&m2LgYRlb-Cq@D2F~byWY%(Bck~@I~F(-IxgMU6L z=apU2b)$qEaTGnOrMhZ>(~K7%2o#}{D=FN62WJkz<)lnmN)$f=;g1+WHpA}eXem5V z(eyqH&~>GdKVPK(MLR`u=5aj7QTKLe!>)nE{sERJ!~*+FF*dycpPa+ ztkUyiQiU9O3(&lv*p!rjL|8y3+>a6t?Z|6Skl|kdUPYYlgLVSZJJ%XB921pH)lasT z0_-v*6ep!5mFKwyn@m--$gtlkLsi^?L><|wc~&j)*-^Fl%*S$0E@iCd?f1)v?c&sJ z%bA;zm=w6K9`10*cEu?HOpQi4WqYeKVf%kP`5o7LdSY-;2GYA2Zw_xxkjHt}{jlg4 zNN@QvIsS~`cJxS-Dg|fCFhBShE`!bE#hMXEk3nx4V05e^ZeQ9KYl-JPK zgCE8al4UMHY+1J_Yobv5+}+%Cv>$2-P+)T>g92OmQ=)TZife zAGXp2cX8AK?N+(=xZUUj7?3Uelwes6r3Y(Eyi8k5V6E!}nOI1JHqy7Zn^_G$eFS(lc*}{zXw*!_qR?_Jyr- z+g?3VJ|6`~QQTyivN7*s zP5}*sA_(EV>puRvM#Nerr}fwT+VFJ4%D_kIY{-3=8~(RDc4>e_M)-cf5g(2L=N2SJ zomORj2I&gS5IDBd1n46lTsRdzI=E^p;e}s4u92B0;KBaw2SOCs$^kZ=fY}Euon>;?6>fVT>niFT_2BtfiFe8pM#~QhXMIj&jU@DAF~X5=WNG)AEpLo$^x{D zSw(&Wzik0cU1P)-fkN-V+oe?f$I*@Vnyue1M$g@@Y~U$}FK0>DgPHIAguS-f zFI|DgCotI6y`gL={EuTx1bz__^|436Z&pKQT+ zab{Ck_Jo4pjk4oo_Y94~!mAw?B7P;U-N#$TnFBtCC~MWKS5<|{zHxWOmxHx_ zuuuHovy^c|ZJz+}N`fa?ZS|)gKZkTg=f=n63Lm{zzs)uYT^t_=cUH@qkO{yf>;^(x zQ&)v{>(tbTS8k7F7hX8-aM~};?pTQSQ=9ob)8AQJ?it+(m<%5h6XbsFahUcYt5>X8A|j0GQb3pQx-2I~rWF zdv^cnIEl^Q;ZzqkJzmESe0?|CWI-sI$n5M~Al|?d%|;C`;2)2CU1*%?H+asn=Ci{@ zE^A>8WmVww5~EP~L%=jM^G+NM_6HSqU|wErN7sqwR;6tE7IsZr@9xi7M-#tmS@t0p#niKSVxwy*nW}tx#7*v{4!h>a`}d2yLH{|;kQdo8jxIW zP5lFhz0%Y@1+o-6jZ;_BRHs#(IC8~GaYg5TbW+Z`y#!3)E)t$gt*G0|ai}*u@^WGj&$Z%KjO8U;QipZWQP^)+ljn0XVr(&gz)hanla3 zHon>B^6K~lwo0m@^&gIgUy4m3Tf~3cPrp2JF?@Z*1F}!|JDAC~KRc%bMCrt@of>Wa zgp1@H9jl+O7u6cI;s$H||BzwU3)MS0UVawT-mZ==LR`u#=Gy3`wWaltKxLz~(Y*~T zS<G< z1zY0J)$lqcOKs-m3|Zaha~Zo$)V_o6d4#Is6xj->-*malJgd3a-FTw|;xpGKz4PH+ zc*uJeJeeUF2xLvOtr?0G1u6rq6g&7hb*YX7W)&5JGe4|XK)T<-gPM(YC>RK9PR={o z$5X9F4Y@wx!IR1DOHj=HDtGjPsJ48#dzVW|^l($cI4FwRp2s-%-cSe0du11`=lDRs z@@{%YbpX&N5mGV9_qe#glxN;2&^}~fCLJQe0aAPgT;~a?2lO_50rMY;>ZPj5pCp3y zz5~omdw^i(h|tlNd*QVC01-}0rjiknzbuUUwUzXL6(ikeM-wSuK>Dl^e)6960HPW)SbsOjSI zqTHgE1Z!{}Z9nTVPL1;>5aOE^j$Q-{Btkhz_hq&h%Nr<3QD!_HJnx{HhMx%W43E*j zGVBGZ(PGrk0yJMZ1N- zo(uyqS#?8@-@$~EBP*hmaId9xC<)E1eDtJ~@cmO(R5(gv0|M?|HsqIY(H z_q|_bU7+~0nza?g(4hnhD69(YYLc~xvi2z-^R@=*S@C>Z1jPN z@7(1P*9GdxkL~2GyjCK;4<`TtA%B-Waoc%-%2WuRQ|K0V-AW(t_b33HJKxNnr=Fj0gH$`_;chepVa~qKzQ5nMf1O(1+u4n~^)2|k z7kc>cZ6)u(a<5#f_1^!O1+fV8WD6AgY#}n5g4%|p6=vVG-^1?t5?IEa!muE1Z7Wz# zUnlOQ?Wy5=aC5l=H2DTVIF3C}u$C`Z$Ekm@UoWVXPimqVP~Uc0?|57(pML@04?0lc zVu;<8-i<@bKW14Xm`E5rM9k||S-xpJKWw}lV>~~5^Ylj#Q9qaKA368!YaM{e2?5u< zZt7XxT!BkqyKHG-&Lgy^D$b5KCfFv?IoX1EAzHE!%9iU8Z^m_awH7Av5$gYa`L ze85&_>es`A=j)r_wsR*c?qA`dQz)igoeLD(LpRyVbrmi0C}#HP*}udimH36)?kM&z zgBa}kwd+9#1tmPFCUCQ?^#3gVqhKm_{Hcqw;IzZ$EN!6LgExP!e6IY+v+REi!|}q9 zo{J-7r;DWn28MNCn!jjG=?bg4f`N4Q?Hw0Q;APKmQO~H~Md`seU?m~?cdP?$hOjdK zdmX{oB6?l%Dq`O*c!=NG2>>n#w*qY|uv45)&{=a`IJ;`CSl#d~qflrPF(_VKJE{tqlke5c9(U(?Q6G)zCN`O081s8x7<-O}#3WlVUm7*Igl)6r!Tfj{L`8J&ugtDjo zMRL<2vf)BRu38jscRmUSbWEJIwMFvc6q>F!juf@igbdMvZw21ZZyL}?rGjbO0d*w) z4q_WRg)XpcpxU`t=%Zq%I!SQC7cR2Gso+ttjvm~CWU;-Ge8Kr!XB7%ZI$5x_HC=l| zAOfr-nH>+iQ^{7BIQ09%+%GAWW_ud$^VBGmmK+SW@&H@e3S00G`lYzz!RE|lLU4c% z5ueF6bJaBggq+tyUAm-%-?WSr#UJ#P-q3Ukq#z%1!!3$biMjwUIA*RX^T4v38smSe z5&bTorxwb5$}W^=#mN(q1rNLwVE0tR3{fhKObmm#$r& z-ORDv_8zfC5cPcG<+nHVKSrD03ydKg_Q!x8|z1FJa$3>>mJA>tt>Jq z5S)4(7_SQbOn@Ksu(lA5(7|{bBEKMsQFkCUej*+^Po;)RZrc5ETIsKw+f^sAE+O27 zTj}Xw>}jTc`TE6+CCiOY#>;st4%uzDKKAy`(@IqjoYAAY?K4E4t7EutTX%y~=I#~X zL(>hgN=8`yyS0IpeUmVY4`Mv*Bicj`?|&O24PmU9mRM9OZRbe+C*k4yEB|wdT&R*iu9Xrd?_8Lw#_M|<`nBw1g!7k&whWweH)|a(w4_cgIY(_)rFEy?> zXH^YWhWl)@#EIx*0p)Z}LlwjDH?My!(Bfi031jLz4;6b=Idg8gYOH)8DP4X=eEW)@ zLH+bln(ZbSnO|A*``?7DZ0`Nqd6A_{=oDWfGNkNbA8z52 zO}NNE%dg3xs9oB&D_Gxn5Uf;XT&*1}A7CV9PzCcXwD75gvZkfE_w}nYnROwOvZ|PR zB{cMP?6kQGSuqCo<&{QW-OKO^wouuCaf*A(f7~$i8j232oqA(4Gd>RGeQB0SvP}{9gj35u1T#KkUIo3uMsq*6`_?QL4~7Z9*3ReH<=xM!`gb11 zK8gY4if?FL`)0NWyDY6})hw{9wD^_&+8h5nW6SHJmC`vKVWm_uvHiV z29&LqlDwr+koN4+8(jVQ;}Ubqz!KOH{S~+gZk)|TG6J!$RT`_4-Xh)Uz2nUApOz`T zx-iLqCDs1HesBA7vh{df*J}ID*9DdFet=-u%FmVha-${PGkxxk*bx8J*6NCm1kR_u zdbZA$5!%wjciTq4HP61#u(d7ruN$=d`A?mbIPAv=IwU;|;%0}kXLJ*4%D4uVSJ~h& z`YEYhvdGrk6)H|aeG4kxL+{z}z-3X;XFQ{0yqFy+7Do;`IEORNigG5XNP3s|jAi6f z-eQ&UvYv14LO<(|pPt#%u2Z+RS=OXnX9O{>YcJ~Fb2@y-R(7I8$)(~=O-*h>ScOKr z$e4f5v7|Ao`voD!{YYQlV6U@_?2MaXO@z?G&FFfNkycJ;&&0yITA?VyIbyg?B6a^< zFH|9!98?p^uy2!=OK)LImbJAEM_)M0 zrkOPydHk6=ICGC{`!vZGp30!P1rh#|47)rDIbzwWQZxA4%O!NWOJCvN_xT=MvKohI zi(3}i4gHS~K6j}*u+jZmdDEyfA9>A7Mw7BtN>fw7&dC!m&ff>~k25A_d6NM1|L5Xg zj4sQi&RRG+8rv9V9-DLn`tzx%;O=avh3K zA25g<`?kHL?(cl23zsXT=k&ildVfMz#l)fl)*-)uy}VBIw~PCwe_@)_<3c%s2NTC;er9@W+73~G<0<3KG_UP9+h+JT zZP>m>-b%z%({?w|#)yLCi+D$wRO^3Ix>w!Q{?K#GQ)F~E)!}Kk_VN75CY;V4#^YZ5 z4OS>hmZRn|d*2<*^H?H=E}%!8ienC_nKJtmiRL=avFXvVy2Bm_nKGm{25L@#C1S6WkZzanGOx>X`-ZWf#b&=mP3Dg*XOeQHBC{@Za~M zGB4sG6ALodyp(z;Y+DS4{D1lFe_v>{+qSD1G5-GPNUN{Dm)(JIA8l$lALEMMiDmO?sm9@jLd)XSmY}?l$>`we$q(*I>1gg#Uon4NZO%> zWg|@FZai-P3><|(QmEy=(@F^yMH=cA2XJh%Bbt`<&SMj?$tlA7CkPb(FDA z^D}{?;6PS~L3t^7zm@^l+qlOfpcA8;!btMkhOA(mWeIsYsAOI09#s@JM4M;! zNMeh{BeBvg>7g(-@b-;)9R)9UmiD&97A&8SFwxdxz04{sovPV1HnW~0PH9^1_rp&j zNq`g)yfqmOk?xe;Qv}e5nON>QyDnEphUYV9pA(}Sw2UPjS+E37(`mJ_f}UX^D|(gD(ZTZ~CdWtr*C$(c--Ifs?;JjR4& z#N2k5(CjNlgrLR7)0-lGY>k|EhycOq=|mT!P~Zyf?;@+p8*&YL%DW0fjPJL(Z<8Lk z?mJc7nSaEuId=0E$BjK4a{K35zua!C>AOA8Egq}oO$gg`?<;2vEYc35NmypR>y2v@ zqckH8>#-F0Pj;lM7eZqtgTj~`M#PpJsZF8?+GbS|FFd|LDwbO?Dov)TAeSUzI;9|VB~=1 zet*1niW%U1S+{v#83{Mu+quUxR?&~?w` zGetolvES)*3vC_kE-1C3tsl$U4jr3S1{ues@eY^*A(crH?NrsN0p<{RfelRi(t1{u z8xZV9$I?X*Y+9Ly^%PCLQb?gpUZg3)sCzc6e&NTeSrt4498dIlLO?r7Yv)7xlk4S7 zk_qlRy)3d$6e+iHwbhB1M1O}k^Yvg85L~7ZvC4$^{P>s0aCha@Q*4tnShy6pdA|8J zWT9JQ?0yEVqJzt@L(7rm%X9bO`TbXvKGjFiub`Uw59MuA*a|?SaJGiI(i$`=04>UdcCc?fB=?3|M5mMP4#C@yPmUekn9Mq+j7sj{g5t(} zX8{5!UH0Kw`Mz^aBqB?Zg*dq%m>^AKZQL;+E`x=Ge?r$^Oytu+`2D!PIzmnWdc_ zO4=-ZzCr)7M~tPNa?JHBIynxqE&Q7o9{WYc7DfB;vdOD*~jNOmmN z$fuxT%tkdf^kugROBZ89(6NGl2X?Z8yA(<<)x0uToP(+KwNZI67}B0L zrg@SD+pp6fmQ~0-_w7+SE3y89XyS>Um4zBA3bKNVHURz`OA%a4;7v9#IRsjxp-tmt z(YeHWT^R^mqodVe(UV9EIHhgJnV9Fspo7I18lwc+39(yrx*0Tr25E*QnxEwPN( z!m)^Li575srI`nl1Iw0?!@jE$-7L?H@>HkJ$xcSu+lYy{ zD#<`5ND$wYhfqY?dM3cdVc~cfl8HrbMFO;G7y!{?GC?ioez z0AVb>Q<-~TvNUP@w`a`ZjlEIW(sWpP@YQXPk9LPR8ZG=hNpv`r-KXbU(OYk6SLj7O zeu=ZW2^45{c{w?k^}d#z=d0{92%ZvDYrwt27RDVp^?-&_I<<_c`zx{pvc4LsB1q@A*ol z@#H1p;_@pEPPsg<_;wT`K*h(gr0`+J1mmhCNo;(5?x*8{stEVcML}DLmr6KeHFAF4 z;M`JiaC>kS7#UyD^9gpig(q5`F;lXkp?+VExbUHozWxrM^CdiX#x9R4mxXWT5t9xP!(*TzyQY`zNbac0 zhQ&%-wN{%Ww7H%?y`Q?gT^tfG{`DE08g0!kx>J@gd~NF6>_VAOs!{lyn`1_(tn%uw z)t`0CAAEv+`EO6e0fk7dMz+`eP=o8!1>KD0h0{oUdG<`*G{B(T-70e1nckbZ>>3gF z#wBt1?u5k`eR1S;8z>4vsCSwpF|J(wZROJus&k1Gxa~0|j+F*HK>$KytR&+c_fMmm zN=9b)OfOiM8?P=Usw}l^6`#|8=tQUw+6ErVjWeFH+)s9S%Xu!50S>q7SCT0;_8Dx| z0B0Ji#5j04QRw?x*}?9O;>+B%-%fbdBmr#5a0S)%$^Rz6XQ$}qe{^@m4YxEmzvk!W z<>nZL1_d1^QcDWC_c9ONsXr{u`2=1N;>RoB29JWZAP_F0uc-?ccer}#uFTXeWJZj7 zM9k`~4h*i=mQ*iHzv$QRE0gOl>{)N_b9}V@^Jjs_286i|x<49b9To#*i=SwkND>4+3XfH|MuUtP~C?#G{FOLO;@TC9UsUUpwc> zmnPJXg>PYa{|dVDr$aN{@RfU^_DRjZUowdxJ7HMrD*#Pvz zZn+i&Bkm9TnL{6k1(=v}DfRZ=N3QB@0q4w=l7VXfiD5gVqYBi?3 z%ar2`|Gzrys^nK@2G6-7VCI+btH+{Q{Qu~@j>X}}?W5m^_dnMg{vOEc>r`V2r(Dak z+h>IVPT!oXmapD(y5>F#x<>Rm-z!$`@wus~9beQKNjyf*;0w6yYhoPHu%&iNnM!Y*dg{X2Li+l}r!_ zz*fFH*v2pH^4hGMS;rvfwmhS=DI*aT=qWRY>vVwQyB9E3#9aZ|{a^vblu0OCg> zNNvU6pf#$Iit^Jd-JgOz3mO!woJz#R+Q2O0ky$-Mls$J@kT-#*TL*pLucyPKdKGfr z9T{T!mJ|Yb7PB%h(nX&K7F?Z2?H~ICk61&F#j(`imMJweTXLA$mVi^L_Px;{wO>P9 zHeiEQkuvO^6+s=KWz%uZd?_Wt8)L4AP@hN>(170J>kzv48>K(yVPP^kABES%W$P%jlY7RZ)PbY|MS^A+(l-&_`4R_85g*QCA5NCI0DA?{i?7$K~e7_Uq(CmDh1m0eLq&GZrnkjb=a{|*K8^&D=WYF|~UTl%{p zm_GQn()qZsYFW42!C2CNVeVVD_)WbiR8)KIt^WPC^Ug8UGhMO2W9qA^C94yw-+f>6 z5;A}*kU!Beyz4M#pIj;l@Vk=bK#~%GJCC9N)mJ7d=B6J#cHj7z;)e$|3@9}LBwZ*K zpnw4S2Prws9TGCyoCpDks2{+6{zJepvFkq=n}TJ#uv-;iO%L{?3Jl+XRXD&$6S@J) zB*ec(ykxK&Vnu|<4w_O(piUw)K?{sM)1$lmT@pDzY$u8oE+^rl5GE#IyRYNP$EjfY z%E!EwOTM5$wN!~*a9F8d9iQy-fJmkv(5g2Is)XuG#&V#?@j)GY3-)sRfH~1c?%!V# z!HDP$AEjWTgg+N69TTy#RpIzCZySQ(<^_RnfR>Sp40Q5pu#Q}AhZ(_D=@ze#QFhd@ zkK-^L5m~{w`geRhL1dq@C3i5y@IoMEkXc(*yQ6DV51322cz zfSl5OvDjbUFCs$W6XRZ{>+YK1+yC4PuDRu7J*`O0?X2T-kflZ4`MA7dV8-)W_x zJXRl#YrU-+>oTmJKYui2sQ@r}Cbhq@}Ry9906q_jS>mU>$3pAm&6b|(5bD2s!- zbfv$SKCaSDaKDW1(|&#KOxONoJJ~7wrQV1`g!g-Q6^D2YAHJWH`_-SiG3Z`j&)#f1 zWdja9P$S0dB#nL0Rp+kj^e#JD92SkmVx^*Vw*;dIZ(q)wNhm~oi6(FBpukB=Z0x&4 zdM*L2Ncg2IlM`F%bg-~mzIev(&Gwk1UxfPF#9 zo6vAjrq%The|*#L7teat;4knj)mXTcDJs?v?bCiflVt@ME>=hs%dt?@{}y2W(x}CN z+-7EnhI5PoK$%}dv+W}O#W^<7h}JpMf&Z$biVx@$VQcvi?Qs3~Dj;n3R7 zL{)r({Dt!$+47X#B0{Ai$b^ux9t>G_pJ+jvf)&Ze{MdKs5eq9c0c8&WS7ZY?k$7rn zBBd~06%y%|f`*0H2X%7HJnyaZNKd@q@fc@rFFxZOHmMXotbGI51d*ai2n7w(#+JYO`%*e^C%Bq5g zyi#cPwQ6cV7;mIbOKv3k*B5xXI7ytZX)!|+mlD_QKZ;}hv~|OYHb=g za~(BI6!8yf#2GJN&OVqd$B0hRJy}?FERIO3w|}%(n`?uC>5LinPmstcMb%DJurDX` zAvqm$ksOU+r4x6M2|XnD!p<5}3o;A#02+R!K{)2-fAfL}N>^kNdMIET8B5xhc;=~x zn|OKjZkoT+KxH0!7qoWklNr8s;wvL;S)Asaby$&l<4jbzUT4^53qs5;XIjHwBcU{ zWbR5TF7T%Xlkg)IaUS#$Aw0N&fv;8@KPZ*IDsfvn%>tuqngOb+{}wX!p{?6 z>+5r{(2N6^k%sz%k$$T``ebw2SGTRxiC0dQnbJVLOB~bVjh%iS(i7zHuL5x*H#hN| z+-&P(rJ+rZFhT@a7Tcr2gMejnX zb53ra;q~eNC7N*@Y@aJ-%#Ke_i&t)z)cxtS_7DnN0p+1@g7z%XQ2qTWV zwSyCl565K}>sKy_9%$}xS>y#rjEwn)FLOX>%`ia1O+f0Xr4;3daR?fiqdI|Z;UL)Sn*6Zb=~xjnwV9d-Rjo7$X{U2$bZ@+sS2Ns7;Xu= zJ@;o|Ikq}*YA5(Evu8%_!e-Vzr|T^))15*1r8;1EG{4kLT-4nhRI0C3J0pszo1Q7J zTbTf3$6PC%znnIzlNU6~)V3{$VB-5f4<0_i}-8@{%f6miRyfjv` z#f2(Hul@nylDyT-RWQ08XwwhAtOP2rhg5ymt;l7qm15(WuPeNHCzr?{0m0knCO~On zosSk3d$n+R!czYH(lry)iZ3^GzDv)25}m6HeD$q;LSLnS*OwcIXK#TPw-TAu3R0t>9We}QyB;aY)9=bYezu{l~eez+HbKD48fL0_i9bZ zw&rB-(lXSGmESLYQ(ML0y2j7upzy1K;ZviDt_lKPHZ|V8JUcJf(1|ftI=lELFY}ND zEW5kkPT>Bo5rY?+>b_F#O+=sY^1RI2d%a*Hq8% z$k8?4!>$M==<0OxW2g?rUP_jj0$6hDPy4a`GJwI-1|8;{+QpGL$7c?u;PxdOa5ofq zDHVD>D@z_X%;0I4US}2h-v=g&1}B?D72%xxzkAU>9>ArdIplmpK! z7|_^k)=B0B!wkDKq?n4TV3o}UYwrVN71>P4#_+1LE4RN-=RPY_2JQN1XHFKaX--cE z;#+R3hUdZKqJ{(u+EbZ>IIC_7_^C|AhFWDj9WbmgEn=6Yg9X3q;@*W5Uk>w3|MJ1^ z^=f@6fGMq>+Tm>x7AEd0ADI7BZ>Jpgr=zBHDx7RzJJ-(8VG;)fR`|r- zt@N#uE%Vd8Ba-SBav<0arVihz_ zE_a1p_xGzEXo3*s5g&*w&7z=@Arv6C+g_rNY1w1f{lLE2Gbr?*MyYv3GVO z2T#YBE04#^>te!d%db_NpG6upG4s~4% zVtD^#ltwTZYp-g!)0bOq z@`VO09&Wl@?xU2RAKJe`in8y6RNUo?{a2OT8ZuxpL|g%$8D;mnPZShvZ+62%u`ujtDSypl%Zxm3&OQ{pHo8Gx9 z;1;yYXJ|cCCx*fm1@FKB&+_RtUr26iO_Ecggob0;ne2)+$*0KvkB+@P5=*)N^B3Kr zKk*!cJR)j2mw0K9&}$#KwE2K96A=8$GORr~V#s4;f(o?pnzZoN|!Z+L-R6A{Y>y=dh$QdZwJ$vg;g!}~ra?U=u$=l&p+uWb`A?VAy z`5%O;q+i#xpFO?|it|Ka*LdS{zloA8`}rB57q+vzBUnDw=pR}+_-w3$7AWbcM2*e7 z;J3?=`k%!N1sym}c8iNnBe0RNZvHV})WXgZ^i%e^)3!eCXv#osyI~L4%|a8b)m8I1 zAOnx~b~Uz;*d&FNqJ0}1Of1HR3lkI&mme3Q)}GSQ+g9m+kvDh5UUX&@tjd7^~kbm@DewumCgJ z$);95J=54<)U=59BJ}e%x|4!4*sqp3s~az(ot^HyrBy< z&TPzny}f1f<+1qv?bfDEHdr+>p?*IyxjW-OH-A}oU)b)G4$vCYr}PIu;B-?={=vn`WLr}=fhWM%tMW@Dc z+zR_0z3+nbq`7@E_Av_d_^@E|WhWoZesEA9m%S4EMUP+ z!4zn)E4FS!kwfHIAak9k9jv4F95@JhP8L~?1Sz8VbSyU=+;pHgedfP=YgK{r`P2?F zfwmK{U7MP0tmykt%&P2{Wm{Ni6F-Hu!E62(+HPZFp_7j{aJPdcr?a5H#3(nrk@dg? z%skwb?q&fvEA&Is?6=v9R#rv2&bLXBMa6c=il9W&RwMpdFN23wEl+=+oR279b%^+D z8M&}) zOWHjn0ubLum&IZ%%w%0rH*hzCRvZAI8%fXn_6&G!q~Jpk$-IzPx#fLRk54=tOhJ+GWgHpP-ambF!v z)A)^H{uG?QR8&+p>k!da7pa2bwp+S-p?`i)_63V0e`NzrHz#R(wA&reIjgu5apR91LZvRWDLfd68^aN#sQ%(&S`)BN@7 zTBmIiuOmZmaPfPC)7O=Wyp@;K7J4pQDbAPYqxEZY{+Kwtj9PiOvZM!0}Bn=Z+ zjg61g8R#2n4{NutPWeXuYMkin<3E?2EdfWuD}pJ5N}y)W67*&N9c^tlN4!tVKfXuJ zb=`-_$=jJ15vmY6Jp5XxljQM*+CFg%75Zs1eeq3BkWjd_?93OH9C7XJEPrre`RhuF zR$atu*q8_pjJJHG+&kU&D~=1=X}ZHB9istxj9;O3Q^SMvlUtn`qR$iCzs69d?z^1( z%-J3?*4VpjDUAGOyt=*JV2WGX-mmCTA5oV#+cn|y_*(7Ez`9n9o-bb){$Y}~^fhuk zDNk8Nwv0%nj#)cV%H|A!xYv5Q=4;)2WY~|rzSV){Am-erM4Vn5s|%YlNL#!6BsNLU z^5Hcd6rOL0Tl-b$96rBjBpK2F+Ft18z@?wl-x0H!xoiM_P5X!G)Pd`gn`c#gwaQt0 z8oUZ^+?~&z1GQq<5^rRe`2J?F>`^~HJ?HtXUe}Hl$L*=uLqkveobyx~-QWG@^}b@Z z&D1Ntb7xC$ua}dcmH*kgnY$c;kw?3LNtUr>s_ti!GN{KcolTS|yPTbFv;QZsoQ?!s z(<|5gB!V3MLw8)N7KxmkXSXuuXY(!3+nNcgFNc1X!#-G(`EJYHjZAU>5&dtrlZz#F zRu^DF?-+@JFbumpJ9~!lWUOcOuG3e@;QG~(3l`M@wP1qp5jj_71fEP1kUqWXT+M@H zDZVwK;swrFyHVtZcNY?liTgwUeqP=Mc|xuqzn@8DJoPwd+tn|4`25b-PnS5tMX$bm z*v-jj3;uytC&h+3Y+k;KTfsK3wehD43)M5i*Iip~9AWG(x&}{WUJ*}W7UM_e3cw(d z0Zs@#rWfv9ug=RGFJz0qjt%>tV;y1g7SdV`nf!cfo}0-#42^sGfCpR-k9-n!Vya^_ zD?5>WIg@>_oVz`{?UzBFp61x_aL-{VS+|=Kry}>HC-V2Yy48iU(nVS2@R4GdNb$h% zL_`Zxi>=vO;q2S^<3A62*ytv$x~0y5)=u!iGDK%~IIJNNWWJ@EO=g!rPb&W58F0Bl z=sr-s9MLPu?J}6T+mMvTkZhN=j=dKIMs-;nAZ{%?ytifgK+u?;G-p1SXd|@JJ?5 z3GD4h;V~RZ!hHc-;@q!p^3-g{ts4c;@$dZ=5HrdU>ECl%6e z{cZd<60Idcv<1EBb;ss*gJVAlj+ZY=M`kG^)j;GM4_WD|wZ%R>14E~zD#q)3vJ_L$ z54lZeGiZXbnYaS&HlQcc4sgtnhzAzi2Iq(JmOE4q<)?r=5@W&#C|E>%5ad`1s&m+* zlUEZk)ipTz_p$Nh)rSdlgAr5l5*5SBfZ@w^dHdc}QCfZlMKY?77#c2H)=mDGnOoxs zuH9f>RG}Qx#t0uCpZlCxS~;^Sa9D`|RjryD15&uP@N?-LN^Tt{frJFpDTF%of5C(h zeli^*A)@!<)d8X8$13nB0BIf|m0k-ew}1au8ZhhGZ%yV=jj%flSF!yNAp^-hjyXlkf}XQ3%8d0Jf|!CBEB#YJGr@ zF)*1;SGh1Ia)QNVIdhC%3N+Vi7dd3S6dV~8T)DWAEnXTLT*-SQ+`7nv0Z0n;!7`Rg zHg_9Z4-hJ#VQOv){$cNj7$j0f6}uFvhF#K$-3#{a)*+55YIfBQ-xb!*a>^5#AWI8N z#&{NV_M<97iyFM5(lOZgNRtknw$n~^B<@5U#hLTA#Cu2F#O%pi=7hitf+F2v-Ge$A zuH#)l8`N$-NGVFN>AXdy$`bC%ooJ%8z6KAlhFZU&EMCoF_=1J0p>7-Cua2QVZvL^} z{}?0-!F1L9s+FxLLq_t#f6Z%EuW;lc_kzk9<+6-eNLo%t+i}TLNqo*YB&;&>T7*}l z4J*{V!ZFGA9uhG2x(qU@yHQPRF6i8;@_Nd4cDj4zYxV2c-6F#@IU@Y_nw*3{71nts zDOq5l^8jvKEN32*J4+_;~tiu%1d@cF7rd740qUWPaU2Y7$Np8 zpNiRrj;juOwXZ=dsMMTj?Zk~YNx``a%F?~E&J4eJy#?%2kxU0^z}gOzdq=r{AztRT zE-{(-)?eWk`yk5VjdCbg)9yyn7A3V{gWzhIl&SSdffmDJlfYg+96#fpfy z(0J$S=>d~F#s0Yh_<#FB50gE^3zZLsiZ0h|LSTQ~75c6&M$QjbpH<<9OGKWte@n}^ z&#%<)s#}S#TWWk=dC2&G;&Pv%t9pY*=Z#rg9&4G7!Q*<4bRSTINzYvOg4^EtDl25q zVEu=AGm9z)+nDg5+s^La&@eV>zps#;!C3SRo9dYVu3Xc)yl^)BpeQJGZ*5-2+FagS z-`3vdj+>vh;%*JKc5YzZ%6CP28S9zIA(MesE;@ylkQ@p_*OWZf)HJ<%Nxe!QdJj&3 za#pHR6geVl|4|>$Muy?+fG{JPgj53Pn?KYGZD8aBV0dY?22c9{@?=2p4auf6z|8_ouJH12(K$)QJ!|8g>e59e8%1qeV`k^y_gM!cI zdmXSZ_buGXj>R4YE(h`@xew2@CM(KS-z!K*%CMumsY$=Vd~-vvS_(y6l>WeGcbWzA zHsT%}fx*UrgGkFGd?IFjk)>N91^5+#)-lWEH@cz5GUMV{PYWOSXlB5P`QT-l%!>+?E>I)j+j45w zfgxPAe84_y=&DY5b_eE&jM!b>U^6IH_(FIR2JvVCGn06fZc&BA$bXCJD-51I)bLPxQ4Bpo&`K%_>E>#B((yP zN!$P^1#v_QP3d|O4OF)1s7K{8Q4g3Gxgc$dyp@W_=6A&U#>-*#riLJjLqftSi`}Pv zq}1Q@<3h&_)x3a=4vU8kPQKh)UNs`BSxof|dadj*ysdqea1@tYBhguBjv^7wEc5oxf6(0Jt%DNH!oW%v{c# zz|O!G&B&ne%mn%GqOv&{2&hxY?&fZB%uqsu`VVHTGDkuobMCs)W`C0v30PdgGd4UO z^h=5PQVk1(6sz1PQ?J_%#y0vTZA)kxODj zNxx3ecUw68!NB6p7`uqc%+;8|l@FP=can@|njIn*H@F-t^dSj zutaG?6nCiMVP9YmPLYfDh8!cHv8pf-$d@w$>t!$);O=4&CLj`$jJPgkp#wZ2Ad0zL z2Ul`le_nPar;fxdP?Xx;+0WnI%te~h%wG?v-rY;LIQNj1vftT1_z#)j{v`0U$X+5g17$@NmI0<+N-ig>EJ4K2YT%JDU{9aoN-XEqE zLmjhkE!Hxe`cylXmKQePyZTEHNZf~8Lmc;Ml`FoaZY(>aW@l%I9DmGuoz~{fn)R)T z6yFunmw)Ch)wX$`ODe z*=RA9&aXHz2I*j0J7Zim%HAl~NJ4TqK5g(0)cOU6dR@96LqFz!In>R67KhFIxXj(u z6Xp4~CAe82Up zWS7bA+j+%S=#^@YVHUj608)kQa{5w$mhs{z=kOv%Wkq#@be3=MVvOCsw(GAPdt9pz z*S)@|)n8jSctz5Bb$Qxc1Lsr3oVCs?^m^i6)tBe16`z^TyA(cFQ)Rrmp^h=%=<`+F z@5s6JMx#qt%P?YAYn7e1IPdb;Qug`a+XK%ULzA>L7HCgSCVdqfhFxEYmZEuXx|#$z zN300=yZU6`bZwafmXuSR%fh+8+kF>WBoAqC2sCQ?VX7~EM)8w!19?-rwX=}PV z2P*$}$1=O_&vIVh#4G^xU)h^WhXyJo*B!r=whz_@O>tx2k2lXxCkCrHk9+8KLXQ;I z<);~zT23eM4UT=BT$ppK@t5oZ3Uew6_@#_8yzhtRg%)(Hf$3jOF?-8!oEIm?aU`X$ z)iA!!Z*lxdMo}4GyFRQ`S-2%w<^1Q9p(C@s)?btK%wUHl*DJDtbXG0cBfHD>+~duu z=$G8CUqKr#EV{jn1AX4H?;6rx@F%CpkE%9aDl#KjoYFEQG~EAa5?_5^$kv0jyP6dt zD>F@zb9|bgM7$_mZEDNbGp<(_A946_E%W&K7TKcM=O1*c4D?F-#?AjrQOb% z+42yeP>1bHJvj9Yo!9F7_628lZ6O97vmys+4+ST99^9^sLb<}$WNAq$m^dC&nB{$=8y?>>1Ls~SRpkiQ8`#vU9g zSvNl=^+7sBP$S9h{{W;6!}c~&+l!qF;$Q_;vcsNdNJxAe`QZ_-z<)$YXT@8iBD|00 zuzh@}raNeW1!#$azSGN;D$cud0-u->Z1qyX7Q#ualMmvgqfCDrDT-O(l_d;0P&%Nd z4J>!yCUWqOfaj$2tWotOh^q?@Nt^9ydzKNm2B#)V6_Z0I2h{%kk@XH-BXv(Py`V}>!{eE|LDLmMbnx7Qu94VOro2A2&$`uy zgmoGNvXM>9OmDiyD7LiBXyP%?No?|{B9jv1fB5J>fN^M^lX=oWMo5-USNvv469NgG z0c%e5lR1hVPVHRf8*4h7xR*KBIFk>a?25{&BW_bu9BK*WZ23N$Z zqV}cA$V%Q2eXB6jC1QEIZ|&53pq>ma&r>_eD))7coEg@NSlFbMv!jGR=j5_9+6k6a z+aJeVOvVLPx)id@wwTR?c~|8HcL7#hPUf%4wD^hF_g(0D_kGnhIe;(5kv!<7m#+au ziAk6_#t7_P5g-f_4kw@htq`zQ@d#k9Vq&0_WKc{eN6V%p|FHuHM-*hGMEU>&H3JNW z2k1zDq6uC-ISO>JnNSqd??2Ge{$LDlU%&`}g2};d=whXa;P<&dD}{+^k+TBJNhyeE z-?TrfYA_Ng%Menj>TceM$Sc=*@KF$-rnxcp}u8<<7p`n z{>J`*-|O43?B{>hC#?Ow-dv%rK$pT~J?;c`u_q1WmQqw7Xr?GOSmW|PG0Og4O#RmR zsi&fOYq9=&omAnW)Bc%>7ACFj$TLXwrCg9eQzj{Fc80uQ#M<)!i`N~?jS$rg9=%iV`OcG>VtT|Y;Ln+&k((qfaVKv8yO z?Vy(7jUg#a6Z@drT|%;j>7^Z%dzrn~&9Q(0>pqJNSZA&Ztjez)OETR@I=&Y7*eiYS z{}z!2e&wj!(SAfyffWva;mNO`p6C130=x{hL)&x1ci&9z2pkiXRe?eL%4}Jv-9CPJ zT^=|!YKpq5yMc$f-djv={W9yusFEogwUYsM+cGLqEjD^Quw#&7WpA(fYoWKfZpL@1 z^6%fhvZ4XLxDae$Y#lU9 zh0tsht3;ckoaPX7DDKr=nW6*Bp@vkL(;V(7(+{9h6vftHE8#p>t=I3YSavzx^i;^lyXve;&&r zKRj<#DLhYP)Aza29<=M^3*yJ?(WUI2Uk*>|SM&K%&r2VEYq6S&lD4rP&AZ>`SFu0o zAx#I|263Q;`uN;f4rt(dQO}U6teLmW4|e%%jaMjws+OGO{)7{oRDt6p9%g(elkfa8 z-3DqfGNmfMPT+M6VWn%Y38r!yMTz^_x zY90RZh;S=j4}7BD;5!-4-y5uPrGGsu# zuA_O|%nFaC!i`;0)2Mm-&A+NDQY_JMH+h0;ti0u0p$f%##zy9P84APImgYW)X3O%f zmQzC+S5jPVmPWBh zXZTO|0oW~z|FFD|aTLOg<7-pN^wefo;CJH-kLO9C5<&b16c%847PCE5*AgLp1XAje z43J_cJOA3A5P!kE1%Xhol7E)c2Nr*>=CCSQ;zx;iS=j{eSXQ~Iifz(-9hd%aeKBLH zX!qhzqklXO&GSz+2$NlaNA;c2nnTUB?}-!l*2dyiz{h=G$l$MEKouAx3qeca5fl{0 z?Wwq{-n&4W3`24O3`~YVfo0lo4NU@ffdV{6U-g^{BoQF4&is){1Qj-n+e#E1Eac8W z0B5VmX(7*O#x$faE)o0`)B6Zq>fI==c*r0LFA$1^h9MC^XdcwS4YGzrD zlV#N_bE|62%Z!?o5`|}#)<+Et4)zBdLC5dl|NHaP7HP-9 z^;%!+W&3rl_KjUyn+=v2Ws+xw9sT8x23;6CD_4!y8p;^G)h-hSrDAt|gCi3O%d4k6 zRJ?+{7bPx7KU6I1?@+Vx4QGZH5t!q z<7KXKHl4I84EIkeDVh6I|9fZ6l6Za9w|aJ$(@OaApaV&bBa_G;jvT279=~DVCGHnHE!7(x+T1@yUtL%sCgnd4yTvSVH%Ncz6ucPg zxz^Ls6Wl)@02u7A_D5$^8(!^~G45xU9xirESEXPhBxnWwy0S1pZ!b6S9qk%46i??G z&Ix_WUSvG~wb@3L=Ud`$|d^&(JkNQF9l8DQGF$& z=DdiMx@()zwy};8GQSr7xc!VHvpE!?`XRTx{f$ZSSJc!j(gek2o`RXg(+3U!<#3s` z!-ZSpv%i2&Vw|zwyV?a-&AV4>9h!{Jcnr@3Ry!P+YYdsrShe{7?o$VH=6dRW*EXtY z`x&P-zxG>POuIal_bGgJdMPV9V`1zQrdxBWtJ|~7uFL@Ul5qR#K<$jqm-hdb+dp1h zSt#%*DCPcV++D#7s;Id-ekEimuIGqj$j`>!A(>~AZ$%b6yT{i^y{ne-jFNB5^O}Ga zdRb?4+ki6WS?3V`D>kKvIk&3MNoo~O)w^$hD^=;%?Q=sY*YJ;+{n{tm#+WzX9&jf5 zA>5e^nhh`Qw^VYC0{yBDY1hnmN0$!uGjCQYOB%j;*b_AQPr=&oPKM|xZTn?gQSZd0 z(>e1KqZjoZm69%Ay^!;yR201Ff|~=R+u*9cp~Aj4;-1GA7|AZXsuvy_6A+5*%)bTZ zxFV17r_$$-Xpkb?MivlnOESI~Tb3>u7o2!2GFsTXE#JA)~fXAn_%dlmCBLNAGahNo3e@A!&>IhNg!tudsxr9gYd{R=%&gHXSCH9)l zO`5)~!rP?>+tMhw0zqTTlVc`_HI)+OvCGML@kh=do zggx7J2ZZ`+?P6!IOJXR{Y);BWxvFm<5u3+N-nw|Q)UV*C901J-`NEIh`+*Ide)yXe zN%_ZJPHg`V`kO>;ot7ASG8zwizumG{3-#HP1R_lUuSL}k|Au3Z!fs#0Jm$AE=?~;B zapb*8GUn2z$2so9{Egt? zqV91>%w+>Puv1g|Sk%5Z&*JJ~kF2_rfS1papXdp&X@w7EmIcS7vzc78Uqns2b{hYx zq6J`1?nC~mU;JGNK)~yHyVq0N^WEtn3Go~JC=C2{@DcYFGkhvjOgKsqJ*l%EBLyN8R_x7$RxmEG#z^%$Cx#-gN*USDjvl+|W z^=2V>@8w{bIm!mXFOf7lQQ{ z4qzyaKuhlLitaCyvJ6;|@vL&yOn}^7P8)1$qP|xKmbwW_pGG$1-DZd-N+<#TT=Yw} zcWordpbdU0?zYW8@QV}Xs1gIUqEE^{%~|GmKLZQB%OnR}rJ*rHNaWr+W>a6j_ZTNN zhp}JYxY9RJ`+P=6uX#iGk8zB(i}Wok&E6TURV<4*wkMPJ z?7sD6zullqo^xthI~mO5sT5ULoBHgI6Sjtd{wk?h%k~itRz(YUq3l_JM*;g)$zj=1 zuvCDiVqo+QT3K8BQ3jCj%15M=%;JDm9l0&S;7&F`Q>(CuGkv%D7oXB!r|mFqvyM}* z%XN{rIuF|Two++rKeYn?Ouv%#EU-qVrdbj&Bx?f5Ky}zoa{o+U@5thoD1YLL`SJXi zeml5}^W=GKra?U2{FQ}oD#RsG7Lu9(HX0x<9e)ArI*k*MDkgybDtf_SJlm;$a_@w7 zT+w$S=_HH7VmoI?Tzq;e=jw2@15`U1O^s80b`0;zsZidaz;rfqqLn+`t|})|y)-!@ zuu0~Owv{W4>|U-ln))werT&U-PgB$}U0zv5NcocH`uirw7x!|mH07pQzm2?<r{@Eak4CCuR9QV=R{ zubG_f>By+2klzD+(b)6R%W6`)9ech#7GBL2=zgiJ_jqR)eWUnMOvKa$Ir4EIpTVjK zFqEf$?^mXfAR8znoH{uU-Rmr9?8*_q{U-GvZ8pjF+-(mw{n+(v+ z)T8Yu(Wmmo=@9FSgmg}G@s8c652e!Lj{13Sd0BLN-w7BB?wgT(I(l2SO29;Ek7a%- z#NB{+l6;#jZ+8#|my^je0J6&`zM)h!`@8xCq5?~IQv5JwI1u9#T)S`$=rEs13@HZB^6h&Y(DcW$#Q)r9gcTBVJ| zCW78Gn(85nwvLAb9X1@?RFYqpA3><&jEgTmok*AAQ1Er1?Xq{qZHCeJ5U|kl0J8^` zGIZ(8GRJ4ukmdljcurk3M;sG#qfFVJ?*=cjz?d3rLrE%FvQ7($$1>*+0KWig_%mx4 zb=trOg`x&fRI{TXy7x>SXnTR5JdF!(2yoYGizqt2I1=IVx;+3+K{%cR$_fzJmnEZ> zGYlW(5Qv3^p7^VW^P?c&nI-KIIscdToaMT@e*qaRCUE7?uS(4?DXM72{b8y}IegiO zi+^Y%CHqUq+SrWOm5+~31^6%gFdlsrkpQ7yp8@P)7kZon!_g|CWPdd4@o8UM0tvre zv&*`H3053rn#mg zm3EU5?Cl@)(mtgRlre=WMHXZhJ`o}*GBQ-Sn+y3Ii!Q$sV>imP7%7v8np8oeYe4xq z8W0uBzQ&ZBq66@d_X`FvB06FMWp$CKupS<=+zZ@e;F|1W7I!xJbqP;dUY_vTl@3rz zMY#qn%n)GI03%ys8?R^Y#2!}mq6Q_QndU?rO-RHbv~Z9XzH4^x!OI6FpcC?z^OpeE z5p31m38l$kZ58Mil%AsOA5{DZ@QinGUwFRm7HKy%cGmsY7RdPf-xT2v8~|iYo$fr{ z-MxAX;8i!$>d9McteGnXMKy=XR&8U2+au*6*}3yBpkU zpL0=rK~`v=cwm63a~y6vp=9yC%2`{TbXo4Us7khYyu}fq(*-j|fs>2*al4afDK7G# zz)rMu2XDU3ozI_{i4OUx7Cf62IbT*Oa(_xpyG62mVB3n%ESEoc4+oJr@B(~&7LigG z78c;gJXsYxvqWE>uG>V_X`OBu9?puKFJ#>E44HYPX6v-ZE9A|Tg^cfO`ch~`z?Y`D z(I?UyL=5Uj=2OD))+*)3D@JQwgGS<_-D~f2dzZfF^TgqTcZ}4nU@mr6^Ti8E{UHCf z-Rm9e{iB6E;=O)e|7BlBnM0W4%Gj7b)uK!~#l`1)6q&_@bHA^Z6Y-3wKVgi`)EUM&O#@ zO!a!3RO2hfYwh#4_ljtPw*qbjpD4Du*1pR!$e#J3CD|pt^2XAipYDp5bhEF6{uOVk z6(Wzu?4wva1h4H}?{HfC&&hB0V;cSSY_K=UX|l`x-?H%>x)}|tHvA@_NVo(p6K!_h2zX6?ueKE z#4dl5YD;%?v@ggATEXCwckDTDGgGNk+0&n~)^f#YerZ^zck#y(GoR{s&J%jh@tV;* z*H%LAVJBb-Hf8A7=$}gpNc-u|sBD)ierE~b^}I6IO8+v2_Q=uNthSfqtKn%!xZ&@Y zFWXmW8oU4m@&oEg1`bV+Fse&oj};X?Pe=B9Rj1Vi1dIRpk#?N8=IGfjm0z@@_rPj+ z@u-^S3)_y`L8p*~3#7y<`=!V;I%m2Y!;2Jx43y6nKvKPee70Oj{~|d{uKoGWUF#-< z=S0UACsQM-?gVofw&2ZHN8#K9YV;7tda}-s)bt)f&%$}53_%r4Gy$j$itLi0 zT2d1eF!*DW+ORQ=*&CI+s6UC{%jv}xxZ%JC%^5k zBQ%+My5G*D$l%qEnyNR|Z#t#x5b8c|-~ldnS||*zZXcn8BWQvfy(y#StrCm?#oW*II~kOr3AiO80^pLN5s)wl{3q_c5*jrJ zAcSA7f=wn0C_M1>%UE`xvd zvSvXx;?XQKR0L+@grW5Bp89&bRlUhzR|W@!GmX{;JVMs4tnnE-y!kcXkg3Ae*qNEe zwDEh{coqvZzX-seb|+J~8N){76mWYY7(YRV$tykL>L>UVr<32Y_?IQkSTaGNljS&Q@YZ&v+l?0O-}0fk`JJ5<5~vE!T-M-P6gpaIgx#hU z7M9i8Vc3^6n+gkkXSx#lRWKglAh5PebMvu#$`k|mh zn;jc&rQ%?CJeW1JBB+^_TT3^a^2)oEUnrK)M(f0}Y2x&3cY;B&T*?cJ`MAU3HOsR? z5qrdd59DJ5>AV0!B5_9WX=@JGpr)J_o9~wHULYgS>$rF}ww6Itw2y2FIALvF4^bdV zS^~)yCrn;d2KeE_AjYULgqnvp$st+QSSQYv`zeA34swi;cWe6y_ zNT~ezA(;~np6wko&UZ%WW?_x5Hk%51aH>>vQ7+A6*2@=wB#V!cX9{<70v034ixi_W@{^* zZcrI-HZ2Gjf7-o!y+NmD6XGpXpVK{;`QdoVzDlhZht;xp;L`&Tb;Dp19NZ@^1fMdd z8&WZu$lBRBz3N##o#a~+u=Hc0v(x1u=;RMAG0#Y!?v5Uf(pG;bcy_>AEdf^F9$v1> z%5J41ftnaYI)`b)O9;PH&2gxBD%|qE%~iOo*6Azsr?R7W+|OZ|Pj}$H;_|!g^mDi` zB5!I8cKeSMJ#!RzDm-)9bma2y>Mh3x=sdR>+38axlUwC`uhC2pPZBrTiK-r8aVHJ# zn;rBeKDML(va_#K7=Wb%D{&jXeF zbUbwXJhhQn7A5;iSAg0}o=ZPro!u%a|Bu!7=D`i&9C11e{p12YkzyW^@&s)AMd$OP zGD)TrJLKD}M}wYnEwatN@?Gzy!>vV^Zzrop7CDzF+gpqKPV6YN+kEpu3Ru}Pex%DM z%?Mo&Z{D5>(V0~S-w_T$1xvcQ$=Q*lQ+CT4+RFq`7B@CGbEH6MjVHZP~9jX&nv9c@t>z((Wgdw#~ z(ocVStT1eDoPD2T*$|74$qvN;T8T`7+Bb)$Q}h@S2YoZl(g(qIxz% zCW6ZF@=fGPVOmO3&}4-9IG1A8rvb<~UtKYodf)F?m`2&)s>;z}FH?Y)Gaex{I>IoJ z-g;Qm@!|2t>o4uoIK+St`a1uZD=S^KDrjX$T~AFpqukSby!96C$voA1>Q%{UFvB(f zV!dyoVBX)Y?t4Vvi=ihnH7QbCCxCE#`@C{l3@`$UNX7Ffy3#8*(FRnpl+<02L?|qD}S|sbw>aA0*GMwGOU-saY&sThj~K2>Uw}ybAd9TqC z!z$m&h5!AxF^&up)r-Sq^r}>i z%9Mv9q9_y$JD|Y^^ylSbBOpjjQ3|#wg)`yk;f;g*Oy+=iB9$5!Z-zFpnld0DSrg@) z6u=M#jWp&EXCXuU@uFIC8JQxOfvX z-}}Mf9dewuW=FS3d@Du1+ih{WvdM7nV}8H;p{7RQPb}^kA822u7a#8G?Ci`~Py@Kc z3kHIjwzf8KXB`!9D2bwQpJWItbu=37q)6z%;5lM|ucpfOVsAi{04EO@POiVN|IKkm zobp5E-AV@xs+RytZWV~smI~C?=TmCt##S0c7#4qXRYMRbc-CVx!$>Vn z0V!t@4-nzf0>ph_XE)cA+>ST9L7|_vI&$=T;9NmR@WM>S$~TW(y4J|-yC8%P@Pxl$ zd*AZz#Cqlc>08i|l%jcHG8=6qS`0ACOx@2F2LB>?uD;!s+gSCjkMX=eM|}8rWmau1 zLNu0>tLcc=H9Y#9(V?T`*pMH0B9ewHRrtjH^t;BbG^~vJ#xxM_7sO6JdL%f=34J@f^z+#ch)#iK z!hBr2MeTQ(M&F~sNzGT$*LEG3lxt7BsRSHOpFWLl{i2zh?&LQPPLJVvJG+PLZ_$#b z7j=}Oy4oI<{@}aSD}bb@I|U6a_rmP%xG{Q}>tl6`6U|f4benvw;}nJFYHxQ`I1HTX z)o5kv>e6;AKEIvD4JvPPb!mlB-Fli z!{OG$rHao#6(w^A>jW!n(fP%ql_j2F(6J)K^AMu^K{pulJZgNlqdwBR|0d)s*Pm0? zJvyWZwXS8(WXjDEbE2*_FxlatW3-9I#`^5Pc|LNa-E`oO`^bZUkn3ybKDUMk#BDu1 zfBJIV*$7qfbv=m(IREROiuq9b99MJot%GOqn4YcS%5- z#8U-lY@PgPFQj(U4IZYyJgsSZ#PCSW=d`qff1Q$l*EQ}m__NT~`dIpMUP^c4=xCa2 zP_ZFCh&J%L(-`xlXY^ z1L7xTXVsuhvTUt#-cxM>nY>_&W>Gg8TjEvar(`y=Fi@;9DNBn%4T`CIhaIb=P4n93t>i~8&>gD)8b?uCIR@};^Na5FUvMsH6G9&pja67{mC^KZ zw9x?uy9_$TJMow9W^|5!`oMp01#NA=>;8>XFYS8NPMe)z)IG|s*sh5|NcYEI z`sL`1XE)bwHh)u5kwo>-s67kaNTxT9X+&s~bZV7Ix%Ot1C-M;3XEv4K)AA4x3FGAP zMT`y{T;XTgMvSkIFW}#w_Nf1=-2?$C$Q`{T*dHQ-)xyVyvB3Dx41z&%{+dW+pa@7k z$R${DweQ`0TKj50aIq=Rw5-j8O6mGS+}hVqy@A&%AJIH|nS;Et8u5glEf_JJ-^Ax< zg^NKAtEee(S`Z*L`grO7){NB=kaKPg`4brz7x&sHBgGKB7h`4Z!0j9_MkLmOB*6d> z#Oz)h46y`?L59YY(gC`rQ+lqM1UxK}jH2AZlgVIX1A!tlLE?{Mg^^6W0A6G)IN1^c z1$aUhNcsG|w}2uENDacnGVv?Ycs%UAQdrm@89?I`s;GqGCn%7J-v9pM4!y1M_`t2u zP#`i3L)?9z?iI~)-2fcK|CtHVkWl;_069SZh7Qd%PE5tE{EA!m1c{J=cK*Y+ynx7% zk+}7rwpHRK-}Jx*5Em>o3Yvof!pFijU^V+Ab1BYIpBV+dfE|e}#2z>b9jpm1N_aSV zL5V_HQ2M)X0(U$>Q&jnhb6Q!+t(l(FF*XSUY=^K0VALU~qTnDeXZgUMZt{c!k#I8) zi(nX2_X0(!u@w?-IhLSJGUg!dAU7HXWRoWe7o5SVCY~M7VS#JlDZZO9oD6Ws@f)lN z5SdOK#_u3^j%sOF{_ou@?uVp(;*`Cs9N+1(t@_>Nm^WI4<4g2>8=ppsPu%CM@HW@L z>6Jj*jyn`T6V3A*dUTgjSZl`L~O%*Pzk=`2IK%R%^!v z)m)uQBv9?bjS<&p_;?KBLcvY@F6Mq2PT0=I&lK6q>bMfeSeezesh`i1eGLPDGVr*> zY_>U*0Bl0(oOoqLrI*RYGadx&p%=IPX_z-Ya(gplFrBynTQnvK8Gix+$8N(*LL-3R z?E)PL2c0#5K5&fg_^e1Q=RW+HrcVm^^^SRyCsMHA3zLr?&Q` zH()t`{YOXd+K66?X2xkv77dTs<{03`Yn46*}ch9}(RPH0i7yQ7KslJtG$$L+h1pD3a z@+pm_=#+2QnMgh@!k-#^A@!d@s5t^`$SQN$R`(GI6x=Scl8})2QZ36Gda7vK^E&lX zWm63USu4oI25=%e8|^<;eSV_1+id8PP8t8-DO#jRTQ$BuwBki@GYm_CP+^!NnvzYW zMxN{hYJYx0GY$)ta|oKD?i-_lxnefHwriWbV;=1|AGSkqw$pBk3PdfOVg6+H1O z91Ahmaygk8+)1xmty7vVUB_jhsVBp*1*a`&(RD(+oMm`kwkmVa^{2JMWWIJP#5wWC ze0pfa&Nv$ie#@S_7n&GEIX>m(l?V2-+4Vy#_Su3+5o7L>jke@5bo`KXkJI&u+Z(EUcz#seWv5s#$V2nNQVgsJ=V@#Sde>hUHkSFtu8z>oLnukUb8tjr( zNVsj;)bBV9YEMox5e*jB*-$hBX;#23l?E9yG9(tID_uH2!N`W9%&6}@?PgJM71c2S zwhzlDvt$tndY`g$06wY*7GWQy{H^I{0E~>0|&WhDid!& z`_RJljLx<(whG+Uzva+>(vr2oS^)Qg;)<^P* z@@za`e0r4au5mY=rzEOzGA020u?HaL*Mn-+rZz9O(9@PioNY0?Y8$n6w z>b=AHGx_5J!68=_dB9+OHlCnuZbr9avEy4w;R`%{Kd+2zJPGVu;4Iqc*~rgB2EuDi zBB(j=aS@@E>m&u_L=u(%NSol`!SfX!B*8E-ucfq-3QD6OF=;QVUMqS2}N9ZQJeGyP;`ss*h|`$AcMW5X z0k}1ZnBd2tXhMl|Rr?L6GKIhk&5+gFVjZJ7nnrEa{(jI97i()&ib}wU%3D{jW&vlk#0B%L0WMEB!2hLV zK}Y0Gxq!*he;=hB{`O9&TBWP!c`ZSfr=)zfJ-@A<7l4LG+z9rb`q_GgGc~kUAHF;< zTKQd9cR#nOdg{^Enw41J^@)_4wUz0Qf(Qfp24oo6uH}~4Z%NGYztulzwD@uNLQuvs z*k7#u`8DKK-1EF6Qp!We(|~5?z1&t9*x$Pzy)OD>H1{k3tnY1^t)3InG|p21VCyF>gYFQkKl z#_Ror^8hb0UgB6t(W`m0HrHC*`0G{4(arEKeT@Q<@T#?U{B9%O{C^$0rMc&Nh5Bzo zRvP+0-7NhQmD}Vrk>gfM1CsOi@0i@E_5k|5+6%L}nojrf#c72GJrg-uwWiSB`ayH0 zo*{!Z>;E~W8u}GJ|JXQw{nnwRKF~s11LCZTjMYYqe3Sk%qbl_}-UA_6mR+BF;v(^n zQlX;$^~(t4euKklQ!no&oMq}CS@$~Oc&=%mMCirRBVEs$cPR&6r9u6IiV)<@!+oft!h%E zS^u8LetEqOne}EG{ME{PWap@Ud6AoYMW@pL$hj>>3j@R9f(LJB(iT^XXKo5c(%o); zU(kZM%C|DQCLE9Ed!PLv(1m>-YrL+a(vqD1MCpZeyJ=_XKuK2H(gj6!IcK2uzVW8H zqnEo%E5x=vdcp&%?v9RnN8Y3+k8+P=ST2AI3_Dx16a~4X89W^A$rBHh_4-fdJFU+x zwjIWTY@akWwR2ZtdhpNUjFpAaIAz1~nzR7{(@$I?eYvw#G~oJg(5Z-X1>%|Ll$nR~ zyM;QMX%`QPMQv?2ox1E!6OK0uX@GEXhB86FaGQur${Q-Uudh#2W12f&^EIcZ=$#pD z=D$AEIze|h^LuFRqSK`=jsDQ>#fH(dS+(K);o-DR^)3?z$G-o3_ah<#;qp|o;!%!U zdVuqqQN%k3{_A0Xg-s!^1QdLeF%S0>PZF%$f-$&W-)bEU{*Pr@B2G*}siPFMFDz1}AKL)VPT)6m*A5`Vr!r|e9JFX;C-w&;E44=GuD0zBw4;3($!+cVYK z4Lz5KL9N5VIXgx+TOSoG!+ER>rhBgVrxH<_&0y};7b-)hQ+_~E32&s{#sH%@8N~sD zT$asGKvh6uCM>N~C%C7C{&1*yUcC z)!S4?V_Vuxzk6YJ6oj$#|_`QRpH!LN7jWGwPIw66y{gZ*LuX54;#t zln)A`y_}t$x?b@ir}L*U*sd0=Db>t8PFaSalL~NLENLti7P}T^U%*Yin6v=oQeuI)9k86a8US^LyGJaZpQrqlpjJ zH&F{L2tW_QfQ&0s9W0~BOC~>2OWhasf4``#VE$d zgN)yw(7&ytjHR)(^*_-yC#^f1zyRrT$gidq>yVM@k%8XD`SsTPQ3uF}gg+AShyXae zj{>R6Y&1Zuk z93sa|xQ!nJC^75Pp z_O6py2pWTdm?s08gmv6uO?Jy8yz5;@S?+=?w!$$MlmZ*7Pz|ma0iQ=HQWz1TZ;xpp z{ike@N7V;pRHl<62b&HQigdqSbWEnm-KPUIp9!9FuU4z67=yq@QkfALR+~~bp2DC{ zwCY#*n{76gcmL0;GK0A7FVXQy+OgXS@1=mC=oz%Y0>LrH5IWtYtLa&w zOFqV;)C;yIzm}c1NeI00idN7u>3B}VM`B^9IXtbqyIsL;qHYUZcs2D(GqG6Klc#5p z#DT%XAj1vX^D&T%&e_5TR-moqe)#$6N)f~D;I|eW8~Nm{4D|xI_+6Mif@X29Y(VHt z^6qP2R_RC+vk`&O<;hfLKhJ<<&3x!Je1;Ft)ssN>iDGe)xwi?xNp z^FS_I;-Q1R8vt{-7{<(jqmp)Aa{AOY=(6MX#c;z-a*;$0(Pq!!q2FbiFVaP0B7drt z^PA;wUE#&|gGMVWd926m_O8yX;^^pIkcekHk20+}|EmA@8S?<#jJC+a-wC&o>5ok? z#su&@f>DsWF_@OOH+<9r;KshMDXNsO>d3In5ylsni7WXR4=n`v`b3;K!>y-z8c2Ho zen!_ZfRiz<`|BdL6$ZFB0oLg#Tmssn?zZ1$q_MvIM4jl>!{;CC9D3ZAz1073=fA7r z_f@}e0m}1;k(YVDMe_#`Ut>NFL4VX+$7L7=gcP55`K2$wsB-jJeBld=RLz-^*&A8% z{1U$GFRn9wle|_Lb(A=XLq{mRHHBhMMvxI+#Wo1bP&&sg8xuOA%)9?u*+Ky>u*QAE z5#H?DLWtL5?j^!0nY*5B0#E>L`dz!b+;Sy5{1g<>^P;@8I95-kOV7%%ITIUHm|tU2 zE{+-`K@2=%Rezsx3q_7On$2YsjHMt@vmC5j1i0o~f*{yGqhAB=oBb2f49?(x*Ig9d z7MU0n^ye}tZ4&Ne?{eFK%nk+9o^#CmU~FO;kAgoiQ-}u?m?2pNi-CM6gfIyM%JtN{ z6i66U7J;|)(JAiRkSf3BvkiJ;fX*hiifD0sJ9;+LY&IQzkwxA}9njY-khFAR7M-F} z?qtfV&VHuy`6~8PE^csHj(PT72WPZGWN1mc<$Hckg*@8XN*3PofIu=K=9+LUsjN!E zG0h0X*{Pm4)F&84KZ2uTm<)_`(t@DEM4^p|;2UXzvU|v(+<|RDUC<`ESjB@Yc9~d=K>OXE&9^e9O zXhCE|hhuPHSz1KQXXPSVLBMF)^7+TeC>xz^THiLlkAdKr=IELXP|UTYPM)8KIOn7l zp1uqukr4iKz=B7D$N`JE?R_X`DxFiYQ${9120l&3+6z^oUh|*N(N5;b$KLue0l{k& z9E)I^OV|FGK;xU$p^2HgLkS%HFixd>tQ9n#NK{P#A{V+j5esw~07c=3pBP3=fGs1Q z51=2}pV=R9ib!A$zyk0n1n$OW=K(-rza3aJF(AYw0?24nzCy_mXS3kZ%HHLS^=_xD z%^~8+)sKIBCQ0M;aWKaB?FK1dtfVD~IgraOsNioKPEPGy9CkCOZ?FWc52Q+xIogY4 zY#ptvf~-ja9p68ua42%cP%&Xc)Zf**0P%-xvNs8&6fEO=1D3ux0Z6t41>(1rg@@41 zA^Oue33gr&(-{^PKaVI+U_qd8>fJ0^vH}up<^h5uyYfC8oyb`Xl}7^CUA#FJ9c#Xc zKvGq7&T(X6C=E7$tk5J?n}pz^0_g!FYOC&gZN}3L57vcf;NnS=5t(mdA0v&=kHsUcR+tuCm#SI z%F2B4pB_7&Kfm7Gv^wOWX@Gy3meXe_-4BSu0^Q@4(fOlo?z=ef+mB&+F#={KEf)B1 z2C6eaG3HsXQ1q`RuS{Idoc;4oJT5v@BYyPvP_Vwx(oyrrp~lBsuOfhM)qo(u#&~5t zTaJnt*h@yo8&-t77rq-U7lW|;-#q!Eo7H8d!=p*Y8q<9v?mUH_V1U8>Q?s%wZg+a? z%FkLU?aHbu_X4Bf>2i(Mw%-EXdsnWg4OHJ+$upX*__X!JZSU{nSLUx@e_%}JVh_Bq+%fS4Xn@49lxAt_YD4( zq+_)9IAgWG>0!om+|A02C!Yi&k@oR!!5g;wK(GJOL~-}Bqc|=GClD=!L9?EI8FHEH-WJ9Z~oM--b#f} ziEo*ehI*pl`M#y$%BF$pfZ<<1-<*P;-j~_F#5@$^h%1`)3l8ux5J4a0)(L?{K#D}E zvNEY~Ae{-bso|xh0*?XeRi&}Bmp@Uc&Tnygt z@vL;-;F#PKw?i>;C)zKI)BJ>0egJ7~PSqip%FX>79uByl%$vH42R%CAp7e&TnX!&Uq9+y4A| zsFs^nx%m3|)u-VO_RNz{O8wK9%I#gQ7t?$}a7*caU1Jr$tdjSE<}Nm2Wm7?^2lfka z!GFvGFv?c=0R|)2ZN$2;6sXQ9{yzSdy^}#Nr<}KIEDLq6xa=?0;Jja~udgkhp<0cu zj*RU1ajPETlU z)UIHovL1)%%I@>oOaQsLRg*E0Y~pR}GI{X0wev*o>-{|OJ&92Bc==8oUhcTbq!M5Q zaR^9!1fLB@fc1`+oSQZzLFK2UB?|si(wIu0M!@jSw;>c=3_k`BW{k7Sc&j}634p_b zn3#-MM`$SY6tR*W2{Z@~~_=^v>N2TJ`8dKkcux9T6C(QcAC^6h$)&S)DQ zynC#Mcr)ocbw~)j=n;7`DD{er)a8Qa{(-sVxAnvI?ut;#T`+ve5k~86CF78ZkZk23 zPD+$|DdYxDa90oRyX(_Gx+4aZ)J`o~o#@X!0iz(@ED|y7cVsECh74$)gM(MN?d@3_ zTN)(vFfmW-JP7cRnX;Odp5FqanaGfV>5(pe_57C^&9$t;kl(vJ&z}>4Dwp?Dqoq4r zLk0x4yt!Y-9^e}7j;02KkWQ}-x+f4O(Sp~b=k zvUJh+00|wBuOi#Yk~fBVnSm2u6&YM)Sbu`x0H7k5~Cs`1qZLH&@)Z}!vfo&>B*3vI+Js)MvKKpV$b!o_37Wg z+j`f<>obKbEl$0RcHc?^=+AXY5afuE@Ree7(9(#FSPUx@L%L6WzX=`zP!sTY(EDGv zg-75(FLw2%(vjFo2i~{U~Ai8Lt9Zf)M;)M;Jg6 zg80M}&J4mL3{GWHIhL?YFMQ|*`~@$npK-ROE(XK;U`z+^!?2Q5>ToK!_F<53nnlJa z8v>3D;oF4K_1{9{Ajc?_s0n=*o{Wy*!!Oba|6~>=!`=#jYldQwN=3EWu(oT`)w*M4 zfb_GuSiAv4;;~HKHzDp3 zHM%R(W@#WEF7;>DS+BhX2XT%|TQxjcZUM=LYbGZ|P%%i>FZ!W30Up;F0uc!eAZ5VM z8{1u@(9r)zKu}QS4Hkwu%4PR->%O2(lF{auOM+i1(`=!jN^>5#g+5<=F2A=6i>$VM=jV;UQ4O$NH zblCuncdVLw$bO&D43AMAJQ1E4eEn6df0st=+p~?#b7$!EDqlU0kAqd*)6%izJuJs> zG>sn1`^h#r5Tr0>`?soyG;zBC1poF(hMKGLpR!XD6Ny{UW@HuwX}&QY&VslRP>@!^ z7FSN)W^$8uag-KOMZyiEd#cy=nzrGQ-fG{<4BFL5?5^a)rIf^d?xnQzV^?6MjOcHd zl}DbL7L1=nBUB+-9n`_sC<43h`{v7!8G}c%-~9B5`=Y-ny3*nDZ*JOuYIXBPFY5S{ zCd=H|wDGDMZ52rz+_wIc@yzBwNua_Y;J|jqB_Puk)Z%8Hn8%Xr=^^ISTJwncW~oC6n`_t&G|0sc9D7;lT`NjG^K98 zs%HA*&(bg7q@}S3dK`A&PHh9Uk*lodnZ^^fe0b3s=p-W}uaNEIPpK2xZ zgQ1I(hP!MvmanJEUZiu`?P=IXyHB)jc6+z7rBEl46eJ3cKxk1x|Bef3w&4`q45i1| zkivnw9b5;rNYxiMxOj;8h%lJCiy2Jo)i;x3nxctWNjrBx_xZ;u3&X{Pc}>q=|M||A zqnQ9O{X_eBrP~JAU-k7}F*7A4?R=1r1u9MEex0%ajy$-K0y>5IW7&NJNO6xP-5n^t zjaP!x_5C-i5Q#U*CW&cVO^*|pDRy^Ls1#U~4Kf~(^ngOL^t1vpnI?EZP$b}RwXR&* z#JsE?+!O2Tq{P3~8f!Plff&1n=$#Dv<0Iw=0L~T%5|6a3`#3PDsSvI6 z)N>%2XPH9{f1qI?yF){ZBaxz!Ab^Gdfw)Xcfa*P}C7gZ(#aBJ7{bF-He10ZuY&xg* z=eey^P?uWKo3CVK0BChNsXV!*c$o|qYF)7k4ER)jy<1^dTFpT5h8K-oiq;n2OoMm!b{J`IeG#8CK>ZkMoMKif8)wssI;Xf<~P0XuhR zhz$M{jiO6KOzVa5f(0(P*W`kO1&(Nq;3s4;$cKT0#lkulY})X06OGZCd$2_E_D^vV z#gF#G@R$X~xi@Y*L=go2VI%0oTcf8-FJw?+aPS=g!0+4;9W4G#vc$$2qQg2Juehym ziWFfj_(fj;J=apUHveP#$Kr&N+Xiwc!I#S zjn*;syvgby!c|Nv7^vPV-4INlXdAxvWGJlf*s<<6iqWDHN~RTMWjB`=NLuzdr_q?_ z#iu*Z*vLj#^j=S^4qx%!`q^5$y1#Z|s&?bSlCOGDT=O%ev?%!Y-TVvE$&ob#?XOYqzTuw*EE#B`RhVcH^kHS)$I|mBsm$wY*HXN&TAT;=$z( z0KW?Bbu@k}#fv93R+r^`b{saML0sf3D^a>s!tTu1sPK$_l_0OnjHUbW$?n_UyV6Qt)sm7%0ZR6nKnvu=fH*(7VWUjxgNp)J!e0;ONkmv2%UQ}W;YnRc%x8}Yho=|I#r@4 zr|%xq5au-_xHR~27tP%{f2YL9(|H#xU)-e>_n&HA|FALG}HG0(<+OMFZ;Gw0)dO8%NK>PTxKLf6|4Pp_Y6GyL0lyg_nxtbCy-5{Y&G`A!-sFX@6vg{@D$6?;*H%^m zsBKWB*MV^y5L?Z>q%5(kC$x41V+!8Co8CNN+V3i01ht;r^&3R_Y;2+HRFw2lZJ&vP zh3A~e$H^fVR>}Hyb5*I7`8&3`OY!kC!obcBxo=?nA#^9T#h=N(p)H{TwlNs@L>;+i zEC38G^5a*_5Q&K%tKiHj5=&_qc@_@gm3N)~Y3F${o- z8Rj!V#~oL`hsYYTq>0ihk9}+6-cqFvB@_L|7%7g{xnRpbZ%PNFY|iK3kIq`l-aY>L zxOhFO(D6@^1P&|nEcVfwy^YpC#3=@Q?u19StRM~z)q{R91SqPBt=y~5YbNq}up&jN zOTe}l$EdbSq< z^NUjik|os3YHg$H&>t<$Q4q0%@)roXD$tcK_@(ICb&`#>Y~o^k0oY;2D16IheQfK? z$cVevh+u3cd^V_NbL3^%)Fes$tsrjJK`DIrz41m%k5al}mvs2tx$un#?hHx4n{!W zOr?=AG*6bf6dim78x;h+PC`n?1P}fXlnfHALL`A|Q2r*0$2Y(%a4H%|2nI}OKt<4i zO9Bk4f4k&lqEwl5bNk;r6iFn~7{q!mA(1HY7*&`gKLLu8M2V?r!~pM9om7H^UCGpR zN!iB!t;zJwpHnYGrwj)-{KLQP^(6;^oywLHk|u+Q$UwsBQL4aM2Ra+0&=7E*gI&uGbZLYl4GlyME|Ro;2NR`+ z8;x)A$kfM+NA2!9)kTPLIOynWklocW^O75T{*3zHVT z3C?#9dZl@YiK4F+w7!Al?jFHDTk4#?Yd+&=$diNsFW+=X=QH;Q=>IaY2MxFd?#8D& z`5@-xx9>woWy9+)*Z#UVGnyGZRh?W>#0j3L?s4pY^Kicx==zy%nHasMzaRq&a}ypr ziDYo6Nk*sqbDiVt93<3QVsxG%XqKRzlve41hU5f?h#$bIB}0aMHac^O_L=gsk#~Ya z{BWX8Z+~oR@8ik2oh@KYl4VQRBW1tiAM1Y9yupu6i9sEc5%qa=AV?n@VPEu#lFyhd zAlwXMhF#{jwSuC&Re$3xj}Hc$U(}sl&Q+FG$?|J{C6sQ?xh#9{ZA(*C#hSp+zwB8P zD1shI_5P&k()5#Yw(>i>9F_RVX<{%G^2$F)f{;%oa`If$vU3++@6p%SOuc5~^de_l zQxY**ao9e)+dJ3BMP9s9e&xeTOJ^$>#Y_5NSNVkxc{Wae)_>l!qmBVdM@b>w7k0R{ z-O_#V8&J%^z@#B5l-7f&hzUIiv-@hC48E?}R!m2QGkFxKmQ!z|mC|d13TvHKD<}oS zVQeZGE2p2SOiS*fRB~JEyY5~KGJ;?1v!xv(b{{{OVsFYag~X8Rd9#6z|MlOo8g6Xl z)^+{o>@scF*5gjtTR+LumAaYSHPJowX|$@GVx?yF(-?S?gV<`_8%dX_NPS7$OzL+@Pos_J7b>GMec3Q<#*h?rx7Kb~}!SD0`9- zxTq|=Hkm};E*Zm#vli1k*iOY34pgFO46p&RB$3>*#gVyXaT$;b!1V9BiR}nrp)#Mv zG(;eXl3rkvFNMw!sq;jrbOLBT;_^rCnV}d-NDRG=7NB7i$%GUlpg%$Fg$%AGMnoDC zWXRx=oa1W#aY$7d{Rdkpe!k8cqoZ_fnlbvqRv8rI?j44qen)r+{?9%QKVLGiCiGH^ zx{379j)fvmJu3EMcC(=f9%-8x{JH+9!XZzixkQF?Hzl_e%pKl z`}T6ycQS;QEwIANVl)VXk2y2Wa9X3h^ zy%WOC*~F^XsiVL(Q%Twm5EqOuGfS0TFkBzWNKVY_!f2EcB{(o7WC0w}%AX8Ru4Wf= zy5-owNsb2<=txy%4(=JFVP@<>iVGa@D}GdaShG3FnP+K6lx)7w^W7O)+y*18>akM} zZY-kiw#)L{gVe!FLrVGHk~IdU`m{KiO_WQBVh=lOJU9-W0iC2+*iS`>X=zECxg_l+ zN)zYWEdBXAk=<+3n*vxt}}1|*IPn^6;i z4d7G3CJ$V-L11VohDPJYb7SI>VrZTLFvKJsB3oAM_3t!d3dv0aW`L~@1QDc{!~!q< z!P!WJ7_D4{&XQ%WzkM8t(^qBWcCYDaV_;_vK>C2Lzy|;Dqh)O{qeR~ z$zXvD&^9sqgV=47be1$Qlx(|)#_MDC;lh(U0|4q#9AZjga#=*1+~Tr!-d)${9F0PQ z=pi!zuCnV4t9|Kw`smbjptsv%Nl~L$KW|mI7?_sr`q#f7!A~alAfOa_&V^5xqCGVV&Yn-T%YIpUGzQr()i?Bx$$hYgQ!72 zx%=wwg3?9aOigvs=K9d8(;#)T--WtXovJ|VrkcxWlah(q*0VzcPN^w?Yy1f4VAt*V{t+OPGC(nA$bDIy$-^q@AlPO9p4W z6`K4WXK$R)Hq$~-8pcj8W+t9ISzA_iJIoI@p3vh0DsG+HfCM&tkk@rkHFoY>OG)?Y zz``koCeg96xuU)2`KVKKDzAz+^*7hHMr>S`>jDZ>E8UA%4*pmO`5EcieHcPkDsk+^T&>sUVkrk zcj}Qpdyi66Tw&om+YZw6X!r8onSrX~;d4K-9$6%MR8CN%C)y_#!Js@(pcpf4AMF|( zQoYvTWT&m&<~d3inK@az*&XC;RAo?oyuYeUFg@z7bDvh;zV9uMzqsavI(@fuu5&Jq zcf)g9&@V!3jo4Cn)VR(ac=>9`A2Hv3v~tV;q(*BLn$@O9}Ux&n@R^Z`t%0{(_=9;hj`v< z_SP$3I;~t*evO^nxR>}O{Yi02JczmkjUIi>>YS6xwFm!H{tCWzP>?M6JGD~KuSC6BA$ym2wEp?`O>$pbQpSd!U^*vr zxvMev!H^J%`m67gibUtmSKeL)m(ngazjh)!9CB|S54|A1<`sV4^kT^CGz>;}tmMN6 z`O#X3FpdQRr&!wA*cI| z?EC4!LP30SauWC`3or}il?>t0o%P@o{OOIn=8~fN6O|V*CuNkHGFeyjg8cQ}voE_L z^9G)kfnIEH*}Dy-^a$jyH31( z;pC?bf;Q7J<`Dpf>14nd<3b0M`vd8qR$#gNlj7 z!{MlWB=83SN*z)KiF^tk0h-yj_sX!p&x5A{yXUt^K_ft{2q=`>N`7b{lGaaxY)+XK zC`X@zjq-->9c6`ZzCIcNr2AbtD+(y5aV%;0y$S4ei>Y&xja2Ba9L@r4fLmqf)Za)5G4sbarTn9D`08#`f23?atOZ+`=3Q^b4wEV z*rE_LAnBIx{BHrpSB*)umliS()wk?V{5Y^SfTb~^ayAYJVkr>X1o2wM^EAX}c5qQ* zpm&R48EcQekAwqDo}vjI@h%Yw?wnGR2pV`nFjCOD^91;*NLevDLLY5akZ80NVkRPkE~SgbsNsjC&|nq=8NnmV8MMpj=FbP!=nd9z z23tB5%{~6Cg>;b%(;-8e{x2gm`r>i zrlJaCSL(Kv)=%^GhYjp@i3PQpPbKK#G{M_2$?wD=A4BoE6LIp_rh!ybqg}HxJSNzz zOW)dSJomu(#Ffo2ouXG|_s#yOKNmhSxR#hc$nBgOgAi~HQl|N}FXX-xHW{~c#Vfo2 zaR15_!+}j4XozMdUftH$0l#4LH~jmZPCs@(ujvf{7o`GAL^-Si}LRUrgE1wz_B zBiv+?s-ux6+p}>yG7xazv~)g3A}Crv?V{r1T&v*3KK*)~rK3yF@88YTISbZhtM#3E z{emgG(Dkc>>jQCn1P0d8@9g5S7qYvFge(7CM?G7(HGIC6bt=Ia_w!= z0$2Xy^P^RV^!!=Ld7R_~q=l$`oX;Wh*v>*=KsBN+uK$>KW2fv<$Ur}GH^;bRKNCYs z4T}^>LUCQ)gC}nOZF)=2maeO&^q;$>+YZZnBs2o!@U#-fgiQ0I%1z*zbcl#j#_em$ zw9-5aaSQ$|CRrxx(N5pvsO)WJ?IX#UD4UXm*|txfJoyp03yHs%UrcI^dYlZdMjVTr zEOT6O@~K>{)i*_xcg`t_`!5jxvpG^)BdebgOC_1xNs*oTDc$JZ`p2)y%IK!N&14Nw z@x`CVT`iTVx9SK*1B`>kXSKB)XN(-O*nYdEFpMY^Mi*AL-!=E5n5N}Smb!3vNsVvN=lU5qclQzOVyVR+;dD{rX{lpg(2hYtf^Z$%=s5ypx%6-3aw5<8y}` zZQMkahnVLqjWeIVe^V5-Q^o{`BUzs(HPa(KQ?nGc8BJpPEYHI803

rhV$xrw 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ν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%0Aa+X} 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ð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 z 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 G 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

YZRQ+G-vFVHiltS~JGzygciT{7io1$qW!6^- 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%0A~9Q8%$r9wz~ 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%0D>b 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 F{{Uc)HwXX# literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/image/mmcv-logo.png b/cv/distiller/CWD/mmcv/docs/en/_static/image/mmcv-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bcc5759f8fe3bc7d191d411c38a9e1d3c1c27a84 GIT binary patch literal 27173 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%0AQ*iFD0(!vwq&^ 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%0ArY%0TZ=nd2Ec8 z?DRN%SbQ(g^jPq3BVGm{8(XCDvW#SXR`7U3c|jE^2rfK=;%#T_3oEc4W zR$LaPvY9`03(Ot)zkHplWDbcc_$_#^@qcwV0+R-aeUdlct=k?C{=tdB6&Qv*Y+Sap zO>|ztzxyBt@;*QfERdJJ8l>QqDZ0OAFxDL1Tn)kRvGrTHogP>D878~<@QEz8YF6_d zvn7uqX69!FTp6uWWzPg3IL@Q<{Cl+mcHXQL%8EWIQ)8)TF5R7-MTjMrwXO^e>aJFG zCF!LXCcbUqIfG^~*RL?6@DU4l%(jj?ZPqTUDnBE;rkh%p{DJEn490qlMux%i^@4fK zu4+2?7aFIRwD_?V=nTG!&R+HYyN~+tqL*Uiny#!Si*8D+v><X*G^WABQG zv`)$-xMz;*A)~&!b)4%~NH~O+L|TC5?R=QK*x&Kt_%FAo^c z{4kih;#!lWvhFgGK`T_CXdfzdJZ*%Cd)T@_Jl0tg+a6*UonXi}Ow6Q39;knq%4`Fc zv4tDS0+2^kS>z;Wy1W1)`|P>)r{<`ax8`5|2T$ak4xCp`(|mk}O%jBBbD89V*Gn3A z!9F~c=fnlc%>4L&3fzy{Kc)^XbaFUFO&we0-?fmmbtG#cf;oh>UqoE!6V3bfbBYvR zMI%GXWo6n5w6!{`L!P1a(;Ubj-)?>SFuvJf6m`*KzR^(AVzMu0foaHn z3LRvJ2(1rz?d{2aAB-6lI0RKxlz6sJCjfAY=i+nwDf0iSm6I*YQK?zcf_Rg2{nq2g z`mM-dhTo8uprUVMh^5ahGa2`PS#E%_8Q_y^?9Y%%+fRC%1@pOCN^?vgL@(-X#ieta zMDozh)Bny9F`BbCOLr9L>z7W&8Vx-!oZL!2?Fh@<<)PCrL;w5q=zS>y#&bZu4h9Zf zm6lZ8-$cCxA}lHNTZJ*z|24gI?E=&V!HZ0m?PCQW?E@JlDPp)eoTpic_L$3hNw%~uxi*;K8xYyyj zPp!Pl7Qr%?!ha?(=&*R*lFG*21AK-2UY-5wj1hW9J0&Wjn^3Lpnto+MiEPu(g22Ax zsw-uoH3gy5GK5_#O#q=0L>!HH_lNfUIgYj8ECTlCZdkrA4_*9=CNs08)Un5mg^jq` zjWLJRdu5tKQp1a`b%Akg=lHZOlEpXQfa}*?&3IIX)dS3^FY-I89;sf+8(-Rt?(hlE zUxcoQrDxC+h6K18`=6!Gqgcxn$5f5*8~iv#x5IQI6XF&0qgNe&lhd*2OS{d`;`4pM zcp?QQ`wM6Ix}(=H)@b-mN)I2Uo>Jp07 zT4?OzY^J8){kpPGwJZ|euAwI)C|HZ?Z816F;2$H5&@#-J7ZcpLQuOAz^G_e@?>M*) z`ITs=m|IVr`&;qW07T0%_YE+O^_(5D9p9Ls!MGNYJt49xtu70PA~qU3!P0i)MBG6F zrhX~%y`-|%E()B7-NBSfI+P)ienZPpcPr9TQojjF2wyRAdACJ1aO#|Sxi#t1zy~Ll zazC{mvVC2dLJ0}gQ})wUky` z^iFX-+a+@0{525Y(_=e0`^z5+_4J*kri%Hg%EK*6-6%12DPJl&YI|IBE0f_{I@Sjz zfd%Fm2QqBl4@V;Vb;q<>jRKY$!b%~u%TUaab`Be|Lrts~-P$qy_DPZU)4KRKMxK@R z+U>^u*Q7FBM*Lb6f@w|#gn#k`@kk+aGiDd;_|iwFFJ1bpJ!Cvi4GTU7qG0s;i(@+M zBj**Jq`gMqKa!QsHFRPeCmf zgNt96`Us5_ngH{OMKn!jzy*%ZJ;+UQPs+Wg6!{O1J{A8i9h%*uWv=huLV0i*0TWXG zO%{q?U3r7u@AY;Dw3A~%V~I4}abOvqrJ`)5h>WPv%&X9_q3L%J%H-c_lqTqe$#nhi zan)1YW86z}H`rA|BZ+3gpB_!~1?C9vC985yE!K-~OQT!8SWsg&fu==1Xd2?JY|&%t zY^)Ym)MHW-opi$1v}>t#s0N^7@g65+Qc+&ZlGTd&q@B!Zk7|u>HG%RIf15;)yHb#( z@h}cxzgstF?`^MWK_DcSpHW=B&=ew@* zJyi{;d*gU`UWt-@9#9se01I`?=Tgdrk6YnJ^27s6EHPy#?45;;Yi#UK#3M(RyqgmoITbKrNC3K`^))rNaZYWg9^E$Ib&1#t0q z!|f{diAwE2;QMNNr8cL|fD(VaS6RdOHZAwEX0Qo7u~-fiJ$#(oD0qgSI?brxYD)nB zp@si}69R4K>7)FGRA%`6j03d}<+2^1}oXq%!z_a)naPg&5o(YujO-@>PiTIRi^j6u1@-cO={_V$SCgRfU+uJ+BK>?Vd7Lm{uskXG= zisFdo7pC3a$+smBz6}zK1@YUKPq$S(zbc$&6_TIX^H!}Dh|8dG1(Q-LsQ7wH-B@MSm{*K*EC{h3C7EJ?_MI3 zKH`1Tx|`>UnRnxp^TgpM^f@KrU6^ZY{SrDyy2axepmfOCP)q@%Gt%UuOjfu9xAnse$~oy56G0HbU|C?lsfe+alw zi--=+4j4Y;D}I0i8bzr8MwZqy{a|i4K^YAq5_6KL!)HC{@VN(a@v@`!#AGdPU4mj= z(Fvbf7-pOCGYQCWsosS=Ckomp{VTrvD>wO|#w+Kai_kxiHuH<^wzf#qt|6QyR@>Ulj_x%uB*I8BD=xnyR`EplAZ-yCwMsVKrBp*_w1UJ|%wF$6IeZ_qT^tOZtWui7146E^eH8^X3l&_Cv0jKl095pfQcKBEnH(CzHbcW zT@090)qFu>(0XdLJHO3G6$iC!+kv+Q<&vLB1_E=waQ-4o_fP(13cxYh9EM{wCc(B# z4(&Apn-(FEwh*72r)Z;+#i7b&jL|4=95g@{0ck!rA3Up~xN?l*nEw^4#uDJA_KU(K z>ni3ARNQahq3_&0yq74{uovV19NCCYQ2$yJ5g$(S8&srZ&2ElU*nEO~kpeHzWm zMyAodw&3It-ku-&W>yJLsNv?=VMtrV{CLPte5@Pt4~}g7F0xs_&F^%`M%Oj>4X!4D zDCs(=_|B)e^w$=AHr<6*jz1zp&9M+R66~pYOFnhvb?FxiAR1Mr4-2?;soeHKacR<*B4ef z2d(>fm(JHaUwp=1A5F}RACXT#c2cMHVmE`610y!WH*xT1e6B7F=%u2J8#t?~R6oCh z9_W?|x$2ycc&Nroc^qcPXw{vI4T?V<3v{TB|BXjLH$gPj4M|6+By_o0MChSc4mc9X z(kAyW3BhL}smnlS&<&}SoBe|~TOg$_tzBIJwhp4aYA*|m0C%AvkCz#)g(JZdsvaAU zBAU30x%MI|5$y8msE}JIR(IWBk9$+x z3D&bvU+@lD={XLd5VO#FK6Ol>@iqA(D$|-&==_nxk}{)(?{UB7@#Bq{tyMWnac@A$ zzruY?P!Y0jXJ^ai7*ujTg=G({Oc7SZFX*kR|=Ndxc6$0 z85?N2=i5UQ*m{W33rHg9omU5<#q-Ud$A7y%Xsph6Mljf)TYob~vFJ1(+GyT&D<+QY zJxmu;M;>xtm^*47Gi7EEiia5pb?!4Nhregjspumee&UBk{g=$Q zuM=}TM{nQH`;YhryR}&E-Kq6RW!#>Z>&GZSBK$+&w>6 zyQ!Ep7n7&p_rW7oktGb5?U49xib`7p@wOToI*B4(FMs}X8KXlZn ze!6`^I&xz(qm*&t(kbUMcn(5GOf|@VeWu@70O)uN<~k)C!~GY`bNMl-LK6}}O zNb4>bs=#MH=I&o}*SjJts6evj(GnQ?q43s&Fq+~+79%_6TwM}drTa}QkIA|h zi?l0bozK?Tt1cgNEqN>gAC>nQ$MDS!2ah?meo<@5yLS8-Nw@)FYWjQJ=Vv_gff$Z6 zPz!P@b3^6Wc(L&!s`nMC`S!s4-VmDzX=o7P@j;JZNI2^KSy`qE--90q>xJz(?@DczfNk_`A)Gwc}~t=kH_cn@ug z#^Xh_WtA5P^?wg~D6xnhZ2(>TmHnV}_(Gt#)!#JvAoEKwLbq7 zT=g_F^6m`ZXb8M#sWUe8Rk^)&xus#2zwoaWGIB%ziK`kDFh8%-!IpP&mqOB+Qe3PE ze)>4{t`HDs5|CH4(ovpM=`W*~^%{?d&v73~g*!lpCK8y;Bb>AnkXQo7&MkjXL|OU{ zMVnfMFYac7%&$R60*}+f@i(0!d1VdQ!v0W^gf2h`rTC6bgE07MTGhwvvEq#}H$X8c zoTPte_Y`+T<1bfKR1Z+@NB%VysxMFn%?c;zmM5I1?IqCkH$76S>epN3fT|jIr$a-d zOiCviuZkC;W@XSlV2nm8%<9(Mc+QwZ?xs8HrO>M&z<%xJ!kh3?FiB|m%-Bj}<;(RH zw`Z$6mRrc+0o3@d!JAdb!2|EXAxna~?4XKN7>Z}Q2Vr{NSk@_1WV$3UbNXk9?~edz z9|~8K5wIqMWIPU^cIadXce)(|=t>}a!C3jEl3h*pCT4LWC3Q;Wc_U;@Wv5mPad0gK zZZY5&3Z~PokBh0;=laP>-rB}#t|oL#CmAM~%Ygd%Pc$@D?+A*G$$K*&r5H5D9^!ku zb=pua@+1UM0svN>N+(+o;er_rm6?2yk=9r2-&Ud#_j`Ib*NPkC7OGUEQ@!S)Z#> zVzytqh2U@jqvHg9E1MIiCd2}J={&oyYao1Fnv6d|DT5qn_)VBQlHDI+N}vf2F>3pp zmda;hlb&y|IPgT54^MdLNEeefmM0xiN$)F!{m#}ARX_Y2WIF$hOv7S?BVQClbxHl) zh6bOx9U$KVN~)^4;7O^kf!C3tie$)DZ$% zXe7(LUy$QDh71Zd934@4zo!Aj)o8b|Y`0m(jZ0oe8yqQmjgGqHd5oxZGg9ipV!Ch9 z3^HHw_RMCUGNeiO?j|uq29rqD^(1ws*y8jY3Y<706b@khvPh1S6H39(aP}Pde)x2g z34&XvC9m~OB5_1%ZQ_a9ht$Ng)E?&*j!n0Xn6Zi<+=(NF@I{AqvHYaE!lkQnoQS_I zjfhaabQeYDG3ZPVOM7LB&NteA+aZ-CmX4-`oWD!+0}Pus)5LNEC*ca0ewIh zf~{Ms%r~ucHL9aqf3$mloNCA;SsDIxDcS$IrIGL1))J^T1x-t@=qDSA4UJSkmj!%b zt0V1C_bfS?16>2|zh#zzyLN+A7Y#Buj~f;*;a-Ap9;3M*a$$nXce{dmXX3-lW$EqT zCjtQ`Vh0XKp>l#X=aMa0d?9SwYCG(qP4PBk{zX|@6>r{^hI8_!rnOM{2Rd2Z4&;rGR+NT=s_u&Tn zyc<~6V864}tX@k21^9RSO0>FrwzR7|MoTl zBEpvtnIGvvER_l`SaX|#MJ|w)yoV`7oO)Z7Y%L$iQ@zEf#5*4>2c+U}bDO0VH+v~)2T z=z@jBfHwk8&nbaR!@3RkJKth}mpwqU`Q1>j%yk9u{>1{bAk#-yIu11V=6M|9x$LOu zRKr%*+unq#R}P~Jef=`5+ySf^=<39m+39BE_;EAQ3@;-*OkUC^$~TlXnI${!@=a$l zXB}r{lwotml)`wMtqh3{>XEmcXu^{0)vy*M+ywUEaKKL)H5S736tZ=*Z-ghPoW~Pn znz^3)XIoZYAR;=ALEaOdqXBeZSDkD3Z(SA!OqG-+EnhrFoLqENr zJZYn9dlqdKs0kEhVRY#;AUZ8h=QnjIcVPGMk7L3g%K| zsjriW+*eK+Rn3~9VD3dtnu>zRE$==2=5*BP&K@yGK~DF(q{pP%VF$a|0AVj8o4u%+ zP$P>PHVb?!XO%mHCb5r|f@k!8<>$2uD+hGp5`knaf~+m$v1BwnF0_7p$rI|>TXz5QegG|jRltb9ekHIMk%{c;*t6_Z|7byu1K;qY zc=A4b0S%Wvhx9+nD5>;*wWj9PrOHwg;Z4ovl*Gp8mD}j^*ch7Ik=CoK7L%vOvX2Gbop2No@f71z-p)yZ1p_gyRvRlv&)_ghYD zzV;|u`v0m1`+lU*XANyF@UF!Kv7l1cx=>y_cH;@hRZq#IawqxlYysBAoSJbH@HTiv zB;}Ian!G-a$kYDwCMcgY=QHD>bS6cW6uQTGT+PioswnUCW-G0>B69m6N8+>j7Z=Ps zE;yZFjf4Yd3Z3;t4|-jVDEjmHTi6E)H#*t$?hyRKRO6hjFVJ}PtDa^X?zgG+|Fu`{ zP3fnqmB)|JEZ6is_uSOBl!Ql~cO!p-mqfMX%(@lag+#s~Pog}#XkLLP3%}?deyv-t z;!y|v3`G;?K!+5SG+otx2#b0lQXg&*sl=MG@-(W7lJap@a2&GZ&7?ANKsuHNNQ)t6 zA{aNMN;sfGdR5(i?)crF?}|H`Pw_mOUXHZBU#4tgSig_#*oti5;>NI=vTL@UptF7W z`K%jgCpq_o2Nh`r!X+``?&XI2ZKJiiK=Er0uk#xy?}BeiJAJ(AhY7q^Gv%x9S+{aO zfgnTP)++*-0ND@XMxDwUL=FvTr@E`Ip_JVmk$_7p1fQ30GD zU?j2)8?H}80-@x5ZtK~LV!?#emw6w%HI>8O*ZTfi_LQSXn^+kTYysZ3_&`zSII9N7 zt4Es!IRrF!DJOa;y=3mRJ?iYVBOuqEF? z7AyzzAK*x^aK171G~mvqxU*VPUDiIY&6{Xf`r1(&?xcV&s<9d@`q(*8@W3WzY1BG>#~2vfp8p4Lj^i zj^{7pQ}Aq}6TFL+eOSB6*D1={)pe%coliv+#r%8UBI|EL)~r;?kn$*QH`eY<(^^BjvU3{{YKS# zl3^EmIxi7L7Wn|O8j)MwtcvRQn(x=Whfkvk?X#5W5rr1ktb&!xbQVT2SoILugRnf= zbq|Ri5^2zFy>#sUhWqVA$8NUfZ@<%Um9PQ${xQ)`pBVK+1lcs= z_pYEC{&FwK4}u&hPUyxTPV&`b)m{X7P|s(C451W63Wch*MfnP{+D;kDDd)H{4xn)K zh>WWBBtro|3A40Ryt*m_Aa)rduff{2t`f>Kdhxasz;|2}Ia`*V7|>jl=3%xWcKeWS zOU-3ZccWjMIf_3UVc%b9eSa-G1^j8ledCfIw*j{{IK~{!=XnNOZ)vi+PDNA>u+(k_QNh`a`|>#?EnYP?%E1wr6@4?l}aCV#gQD7^ADatM)|lVfC4d6=kFR>J%qqo#SW zMFI-B_sD6==5>_Yk2waQHGgZGNd5p2DOCJK!(;p*RVCxzKvCL-?R|s4jL1<$`lU(n z>?TeV=ysQ@pt5?3g7Q@>7LlVM&sXv}<67nUl+`vVr$ty&UD>7QU3#DN5IF$cjFrHL zqOm(R>%=?1$l@vBzdAalM4rOmPJKN3SseuV8ox z;f2D7EC@Wcm`W!7rDr^wbjNkxq`!h|ypW?%A*RDL$`VxaXJ+SiWk)ZItNqFfME0QF zrqxM^uvRDeNw-zsOL5w$_;q`bVEy2_3B#x%2!<2=jJxNoC!J}R%qY~zeh>KNhWq|3 z@ary$YpvRzcTsPXs<9tM^KZKv?0d<5&tm|J#H@sr2%w=HK(d1q&LMIFW7ZC%6%Wgk zW1{finE(>a}ZXZi4N zT}1Yy3A$rmpR(CG=kFAT$d--B@@XAdRD55p#+aS15p*~k8>9D^4U>X^fdh}qnb}Kf z6l!E&L@UOcj7ANB{}Xtf7w}(Q+wHjie|nYAI0vu z4#CQKgeS2wJ3?2rZ(bxXN&XzdlL&S!+^*vsTE42T4>d|n@Wei4UzTvrN3b^CzY5n z;oFb0bf_n}_ee-{Ic(4>#a~_GAh8$t6X2f!fA1=v%cmQH>M9q(HL;J4>*SN_v9?In z)H`eXGRUJKR|-0Hn}bK0Lms~7+0tmDE?5=i9qK9M`Ze~I>PfLglGzfgqN=q|7m>RV z*+v+4E1U1aP=nizYmt@9>Q+IeC?COY*??5%JSGr1L>R6qo(p1=U}5dGoTC8vjS=_% zd#IA>QncI9>aIv@?7s(o?kb+oi)b#bi8UdQUjqJMj6fkCrJ7!wAo2<#k03HrT?qsu z>N%xf`wH+lRkM8?R~401JT;dZ869ZG6`57Zi$@_(V%i(Aj_m@9$~u8Sk#%Tish>Qu zwVKfG1R4>H5=~6@lI5}aTMuh*LuBm`P-6K98&i=@hyi+@+me}El!z*xpm|a|vi}6U zeTjj@+kr2Ul}7)!Xd~Ozvfo<7_xf$LGvSrj>dQ{jkdOPGW-FRc|as zR~e)Cjg?s5f?=+#5-gTvjv})E5qR$i`%ePD5BxA%ig~r|7l40NupkN0Qq^|@pT7#{ z_FvEv?#V@XuTPBgV8ded1Wz8H;auBJp;>;C$4=8(sX41MqzW>WOYYJv{aSgm)HSljj5XMP^0Ct+%$ zepF!$vTC^kMG*KzlIyW{_wd{#_Sw=M=L~x+e6^mCB^OaR`!evk5sxwLB9mXdiU2W* zR$~2|il}wM!sm3=y1~EFqe0VuE<2B$ zv7y7)o&%n8^5Vq~FDh$n{EQa7NNRv;<%`D&6lOe0SDTtYkpKlrfM8d-eQ-g_xgYN4R_2cMX3Z;5m+CcFD z@UO>otPi77K0i(IOoegT3P+uN3%H}^zUzVi54dHKf#UZWQ^{(HeSF*p46;rsEv;NZ ze`FoY9LOUeujKpwRA+UX&o1j|POs30FZm|I(+G3ptpcK4<-F|S&UB4u*|uC&+Hsb~ z8p#psYa%mV02&$1qf{gzd4FRUQe(wwT&`iFi@j-ObyOh&y)JhBYG1Lw04p~k@+#G( zvau??7}aE@Se|^LB*qsvpYac9KBppW8-V|SYH)poX7ioPYz^?&9gFaHMmYWsN4wp$ zh}Zd|1B->Sr_murW3_H_MO+}?ZK|H+g!O@^K+b38NmuPIxxesv?L#_cuOfUN*Mpbn z7_ZsYZb|6_nbePCb`Ft)9))%rbRx&9e8iCIzD_pTMU_$pH@jhw^V)*QULpa>I@dh( zWJg3`KJ@**4X}oeIgCo)$5aPm3z8spE$Xh7MTQgZmZqHt{vz5zJg!LKHZ-Yv68Mjf zmilhPn|um*Gw@NgTX}j+=lCj@H~4-^C1A!*KYe6@j{UKPIA}Mwt2mPzC;$s_tJa{C z{{0Ey`K%K)S>8Ucn8>7YBGtKV;vi-K9tZQHm&cPDjwzE*@BxlIfJ=QyNqwgD=QXAr zd}^mvWK73MX&hBadO)6V;}%`L%a`%#d5K#mz^++N@babn3Mdg|qKm9r?hh(p2!eH3 z*@dB_*W0SAjKI*Cp_4a3_5Dx?6ta|o0yF{okAZu~eB75xOtkZZhe%;>Dd0Sg=p>p-?AEOmPe{O+}zZuPAe0T|c=1&9vY!TmY1}&BS z$uS@I0pNQJ1Qe9hLq5-(5e$9ujB*8)i3o}-^|tNz=${_SJHpJ(){ue$ch1ptbV zFVx9)lTIt=;qoa-%x^e)62o&DpfKsEAg>86PT3SWO#y>N%zcQQ@p=qR4gVoEn&YHq zBb}tFvx0KqaSWYIuk@Q9BM%fv%e=V%TT)80DH#mdh+zlt?MCiX1eu=1%*+oz-$W1T zb=~wjZ*HjL?#}}l>F5F^68v*Hh3KY{V3?a2HKR4C_tN5e-Q1l*mE6&#IK_Y zy5UuL?>|6gHpZDqUofBuhUGXVtI=lm7{Zy%3bU;IPYPDAS!9a-K8J8WaL)TNtR;Ox zNz-2rpj1_=BxV`d{P!vBy=c0POOMEA$AHEqJffd7O`CDy!$H;1O;~%on|jxv3dtLs2av%QF`#M;AGuT^!USc|L?pzU@tOk_WnAFN`Ntegw*%{z%=)8~X(f$$e zOIHabK*utCdW^^WDw^+E;E2MM&@EN>YyN8WStLHtJE!NMN@iP1DJqL_668rR)tV+I zMuB)+iIhf0Y9yX>@QgglUdx#LL^St#q^hSl7}_MIG>9^6Ho6={5Si}uRfP6VU@OA8 z#;4VBax7CZEvI_dt%EUJv1TVm0%8HgAaaVLz97m=$RJlTtbVc{_mN$S@*P!n!hywS z(F&&P!Di9wu8%K)bNM9jGh?LC7RPfRT(tL!3ySLjgB!@Vs8spTW`Cn~teGHZeOre%>bOR3+AohRw=yYb8;DaL`!U zf+paaoz_GzIpVawO=HYX3{%78gQK5ppx4frWR+bIQBfTS9^!W&Elr&#U$A&HI(PXU z*EmQVL)C8YTO#N4$7to>hA}J$7gTUCsAM@9NwxG@L{4W*DJf}WD;WuzbVipD`BOx$ zIOSUZ=D8*_DJm6NO+LL0zco7e1*=6nsX z4zW8CD_MDWnYs3ObVWf4YW2;=iKRT=y-Za|+QhsiWE-k=EB6 ze?(!2Jq|^5OJ&tl;a`rU-JaW%oy_rP)l?rdf9l?OMD9bxuSurU8ErKk?|m?7e#}J} zwjkKZG}4)DvNs)RjKxfhA0H(uiAM}%%VXo?Koh+JIp6|OPr@?99zc_M&FH7ZYQMJi zfL$OvHA)DQUuPis1r*lAzE8osLgJbXCNfU#Z@E?Qe;_O2y;SWA@V9~gZHayh9|wMZ z498ed>sFR(mPw3LNwpj!o?yu|?n$u&kV+cl1e$2`>+WqrJBjD9;y_T;BltHymAL+e7E5ExNrF7CK^7V>2t9q3bvV&(VWi^R|HIqh-HC!=>_7_J@OvL zZ6$x(YD9Kjr3ZA{zz!o4X6wF;1|Hu*|FaNJ?@ErbO`1@*K!>XyP(wB`rl&O=V%r84UN;dXSnrU=Llx z{Ojd$fZPUjGd>TIaBw3XC_^7*3KZPWrhs-bk{gjt1G~^X#Y@dTU*iw83B%T?$zS5v zJ&Z9vo{I6eo+)+M%2Y4;;Lug6u-Dns5xa?Up|L{4tUA)Gx zn`9Q!OU$~c7}l$S9SFM;Cp=tH2~zS@N{K%+oJDox-=Oc8(@d7Z16$@K&mlYl%z69J zk$VVoel|rb?>w1~0!(I{qI)sBr$ zU52YOZ<*OdMG?ioJ z-bEQ5eZ?&VzCvr)EKo#T*L|o++kbLV#cL3G3)-Zz24m(*y;kvGE}~_uSD+vtk`W3l zJ?K*y^T0qqs1hU?J zt)^M5h+^m9syOhIIM|6nZ2Y^7^sHjzba8-Ed2Me9+Nrf004O5sqor04x=`;A(fZ!q zh?w$n)Y1pxG}=_PEc|%~9Mt94l2RY>1B?z7CZq2( zcH4v|JU_n(-|8gFkFUqNKFiq+a@_GwF;VAplIzn1&TZhsrXJWZ|XXa z);PZjWZ7VaHE^;yG6)$74*|myz|*zHnGS~BjEWM*1H~xr;uYWt zgiFA(N@{1YgiAbF^T5LhkJoxXP zd<8L&P*){!ROybo4ymq`x>UXQsAa9!gl94iByK}XB4-wG{jvefuH=lxDvT^-ph>1>w1Ha>IHV7JzYDJ~BPM0b zMC+njyODqbv}xv_BJu^aZvGD75XLOeef~`fXoN>WPB!CT8qziy!M@ZF)}w+eI!0cz zULGJCh9Z2`3tpdP?6q<)E_Xoj@9~!N5TrW|LD$y_PXimVp%|I(W5YQJClDF-_f+Jf z41yTVPZ;;TiVsod4-^5>pf4>QZmqQ&3MgiPKXco5v>W%Z`~Lx8x6Ut)p4Y@O?IOZ= z5II@P@fi~*l^X&@Ixvbklh`PVLdTv<{}d$0)4(xub?nF>;W=z!EH;5sPwRkFUY}k- zCa0k{={Z%9^;lU+*gq#>e}*ueL&D|8&QBV#6G+(8(RFG4mDG1+BRO*Miz@4_S!U4k z^e=M#&Z};%1qv@a=C;ovvI?zuxd(0Y-w&)qWCO#5<7MCx;KjvrmZm&^QZ$2Gj0fOI z7SM{E$tb=)Ql=eSHhaM_W4-(SpK#xKwd0-c!Q_?3Hwv@ z`%_4NId*>1NH~Gmo*UU3q$OC4fXGmq#fvuph!O$Uvyg!6^MH+ zB5yz?Mb=`>QB=C4etu#U)!4%F)G|l!k=yV^fU!)wizx3#k(CAJQZ>D1fq~;LR88}k z*LOQP3CpIcWlD^J`S~gOW)A5bCk#7;GJ%+7gq>y5?M)(flF&{O_9wCP%LwPE40amA zp7M+`h_D9T>el#Wf(q4WGd2&LbX#k!wLnqukURi9hU&@R4BUgr9L5}Lbi~FBX~`ZS z0SFb9Nu}Un#&wbvAHgDK0_k+!M7G-22f1KuIFIx(gjSvApkl}@!2NhPI&A&~US+bL z*G>ewT|*~0PiRlj>2wHX60ys$cAC&mAu@$!O2Y0m;lwmnro{HA3Fjw~a5@O*CXoIV zhR%>4G=cHqHwQ0odnsCLfnr=X>$aECBzVVrHg?=m2P4dO7)@%V96Tz4V@v>I1%eLr zdQBJq7PulJm$0G5h9NebfPNPVJBF}_kxp{SJd$->M6uERY%87rL=UDXA@m3~1;N@E zu=X;c?GefpVyCd-G+{V}uncP_3C$E%mSOD_)=bgwPAf$KI3qh=fldGu-6n?; zjVO2-;Via;gjTS260s9l+eP|4usx*Tg|K51iD1*@GZ-|Py#q~dS9fXmx-i+(*%0M6 zg)oD)r?Ga5&`uD_v;swEN`XSAu`*3)mtn&dSi2nCSx#3hRuJh~LOY8MUm>)8O@_~% zMEYO%|D59FXey7Ly!!FaA($7uOzGl9W*;2a`n zuqGf33|6KPnZ(i+8}_i$L*^%ta01)!8f*_^J6P#JXf%qd1sVp;Q*CgIgz|+zucvv6 z>WIPu=Ll^`7)}$~X{DV8z%Yf#GC~(gh4s<6xi~Td!2VO+v zd8{>bB*4m~uEOad!335`Yl$^=$ASZlD>5{7*OJ4X;+#+nQC zxroR-#>`_(h%q6Uc`*HYkyA@OwblZ~5(z-e=yReA%T}d=qRR9Al2yYU&{+*SzP&zz zg^2(rCcrkLJ9N^R0!5&kIO>T>ke+h-!Gv?N6GC@_4inhE_9fVG0_pc$Zli}t#~6ar zYpBhbyMb>|Rwmo+Vjg=GZas{wTn)2V%D_ilQN$c@nNIgSrqjd91f8&_d3v$*`xX(4 zG11n?&{tq+9Y$*{P+UL31VwaCqXT8JA(M7UcTxu)kx5+9)p$lS^#ckz9nDeLrd3b8 zh{#H;7_99mEu)}-NDmuM(iIn3NDmuKflOdKJwiJnA_^Fxoy7KgNPj~66v9c2?IL2b z`t0T=2Nct#KoJC(=g(--!k&G|>eUeTJrUGcOlKYwUUAdvqy>W3TDwtzVmx${!4Ond zClxBk7L7`~aAhz;a#W7DWna5b%f` za)X8%66Ib%AzJk`(Sd%WWAzbU!AgLbE@G9_7o!n_NDpf!kst;XC@|PyVo*veLC@td zCb4#sfGMq>ViM`jN+_2Rd)`$}^-S1bhMgC%YeA+_nfhXzn8G}JOvjeqaR29wMILktghAvfwd_nV@OIouCy*uOQM_ z>PUK6JAv3qEE+vnJBbhhMGs-h^;t|HqBKzjtvoW5gWWL(tSZJ zFPi?`QSAH!;Mr(76+mYK=I7hHx3$(NeYrA*!&UHr(~PO^-7VoJHi4_D)#m@NtoXOt{~7vBv!#EuR&cauJ1#JOYE25NqcU zxr{aE3FSq^p2PAAp}l~W8H5m_@7{YBUwyA$4^BRZ2}9(zLon9@Mr*CLK(X*<(TbbP zsA}yo;M>4|2DTw`8^+v@3K(w6`1LaIFeN<{X3YH`CQuoVW}~P>jJX2L5(FKBPEVr+ z(WpV}l+sB-6lL^)E@A^hu~^$jY#)(1LOTOirCF?<$Cx<+xk5Mq13Nl0(oT_Ut+f^? zt}19;0iH$0>h1@=gf@lkLFAx|I1XXVesz{*-Pw{HUR0?*+t4~)IC)&FK{s!M{(RHV zZh<}lbBLM2m`e_QCJ}K-?$BT{SSwgW!x_^@f_bdWxke62ZLPJ|S_>4{rG;*L4xQiq z9dtU|W_0k*9S%5l0b7A}rE0N~&Phl?RMNnVftf2XHwV25n4cT>qht+hbWT1|^U;|%aU;A`kijjh0~Aa|qv0h@spz@)m| zXjp+HF=8BUI0)eUdF`dxvJI|WZoj40T5GKZiX~)c(W;>bfiD32fW0ol(42q{7#vv@x>A+kcUU(i>tZWm$t+m!#3lvM#W`T#?1|nO4J2lea0I(Zlb^@#rrfeR#&uuHv>Zx}EM-Vv$W1^ofU4nbDo{+JiD*!dq23p5AM(BeZTMb>$bJGF);L>0`CKU zLNo#R2!ILza1;P=1ON^IAk$QE00OT*mdc-*a` zJd`mW<`y2#Cp}UHPe|ZSn0a|=8hfA0_W>Y$$!UJrBWE0rlGM#e8i)KP#r*Zv{XI(`1Eo$Wcdz;h9mAr-=*$BfTMR)?Lx9e%dt;)TkKk@gX0DiIOU zWQYLS_BfeDBX`P19?_37FpEiSyyO>i>5NDGmE!oP`U%Fi2_8WS7yJ@^LXy*3QsR@S z(|W1a7MZqonP)w--W|;iBIl;u%`ItXdV1z1T+U0#%6GTVFB!T1(xJFL;#Sqv?V|r! z(Fv^bKGyU3vhdSo`H$|_J*z3XS#z(Xwj-i0BmcphiN=a&O{|*c=lw0!*IQbbpC(5? z?fdntzUf)(NZakJZJcLq12Zphc+P)uofWsb8`-_j$NQL9`bK{ZjLc1xq))WeP4qr` z`|)7v{==z-mFbDEGsEL^E4y<$`|t0UynnyN{dTZ0Ke*KMd|6rL^V*-S&d%+&#+}iw zow=E>6R*E5tbg0x`}t}2*O#^5?_d6T^=R+&+x?G2`-b$7XfV5yGmz{p_-?bhNy~ExU&D zp8v$P&(HQZRP^OyEw5ti8}Gg>z#p&mec4#~>N+8C;Ff(;)zD3Y==Ir`P4`~kA<}uJ z9h$30E9?qXPY*QLjNfyuaJcR8sCM$cchmW~fk*e>J|uNrm3DkwH{BF6UVHl0;|K4a zke3E-J3gtOYmNK5KKIJ&OC~|h+t{1a*?Uz=)Yf&Hz2FRyvCwJ*UK%JmY$jWX7u;PK zq6?(!|1e;adY4kQ$QXkyZU;ZwM9Bf|ao0`+%1pJWPQ5tDOp|O`mK=Z5vc1&*b6`u8 z#G!$Q0=waTSgX=<{m%#QiWLyCp z^3m84*#(9L#?sP>;9wfMcWsu&ueZwbHu=V;0zdF5bnyrh&_sYB=`Axr55g`*A0FvQ z7c|)NzaeK&)aw>Pu+f%$(C=hWIPyD51}unSQ$t?_Gdt1*gD6ux$`DdVv=og^OM#`L zK@b50E(IjE#Zp9x#Erfu;#$ZZ&EF`9)uxUtHGuuJ8rQ$rJS07 z*P@kg30k2CY#h6Jc~e>G7&9!@N*0Z;uDaer&9spgbMm5NZASVn1)?&Jro(Rb7)Cs| zE6xK2;aIqInB6Qc4djR@3l{d9N(7n{s&U5-FHVQ@n%pl8d~IBf{y^iK4m!R~G_q^B zs^BPcczrqi;Af7Pj?`zs=h=)6$%%` zYo~C4wH9_USO~KanxH^<+zs47Fqg5@ARZ;VhTY***?EZIe_iSfNYq9XkGVil`D^|3 z>W)E!pcouFsH*sD`Z_q?HO(|FXK&|o%SwH#h2~8o^biIy0z!h>TcBIKzkFR`?UYyt zv=2rd!gk=pfyZ4eFQCB@Y9t~6fe$+cBO6nQfE5#pHRP~DsQLKE2U`jjzEuyXJVvw0 zR(z)}|ElcVKTesuxW8Jml&~~NA(8j+syoPe1jIMbg5K&P zLN(AJfCv?VbuEV2jOH3shJ}7tTMc|CqtTBmC1My|l4)c%~yLF~EBgEYHtIa+P3 zc2nn}vx*ELWC5zOA#uneh$$$(B;LnNmCfIR9JoHTK?|PBNMb>@t%)J84Jp9JLxBE~ zy3qBLc7HF@#R0Saa53)=^y-fn(Q{`hPzF`xD&=3rVNvNv5vYw8FqBKmQ*HyyTpXuM z%?ez->_miOT!F%RJ9)?vYtyZ*PSJfOzLmHhF+@J}68|}@@d%ZeMCv{@vvaM_eDO;a zT27ru;3~hHj5$LAz;`P^EH4gZ-tH|3f#9qxSE&-Cc8@yLNSV_&K$u6iOhaBWB5SZh zb{xuiw#~g5FXaIwVC#*rPB?B`g+bRe;3*IA_F)1}$N_s$Kf}%QDZ?ytB}tj0ypW>W zpk+h9%vWhf-^yY~D~Tb!3_ae3>uyf-A~!-&l z5D*E(2cZ<7dKpnZGgyjgWiTR2m<4vI17Rbh7Wy&0#R>ZTWhanIUoy%ba- zCEs_-j}3;@={cY!bSwn$?qGaS*;R!Rq0kPwexbCUAsU2x1I(cc4vGVAND{9Z7|^83 zi>bFvFWeIt=M>b}_SMz*-8A9?VOye-)B_F&A{yRtoUa@V$Kv=-49U)GpowLEQPB2O z8t4?qR~YYv74YshMY}nOHR={!JOsi`xMcu&?grhrvmW^7FuzlBT}7ER3@Fh905NAF zp1X%_==M`o0!3_gVOS&1Ki#TyB4KJ=$Z}sx98Bh98F+)?NGHj++|_KO>;jmkD+Ppc zdBQ6kBq#&`2sCqHl5Z3M4z9Geml{AQfCxg0fs3}U)kxKEEnFnHEG<5ON@@h9YP#z6 zV_apgxie2ac<1?UohAOsK*aot_ffGsKVQ1$G&=7K6?aTgp!yj=YjvYDD(<80B_l<_ zcz^1ux^`%4&wQvDO<|18IWY9TKMAlau=zu*YJO++VCIKPhv+UZOoPp8L2Bd83pf{4 zLa6W(&am7!XG+mB)yUBm^5_H!YJ}hP{8z^QX55c({iey=u9>|qBhvc5$igtG1H7hb znBj7*vF@C6Sn(Fg3hg#{Q=SYmH5syYbfu+ekxK=vL@R|=-duwOybZSHm7C8RD)Co& z)mQHVU&;&)m$xoOSXbi=vZ{pIKW|*@RDJc~MV2A5q+Z0uTH;6kyHFSPUi@`SZ)79mX7Du5 zwB?52<(tAXaYR(~0Yb!1%ewNKK5IFMmxmvq$+xCr#oI!d>5U!!T6*8=%A2!x3{R$A zsa>d3%Vq}h8Z%Xm*sDTA%p$6M0l9+q%4RYG4QUsYao* zWBAA8*1w<0xvjG+E{FD1%x|2twFP&p7q!9~kJ#ufUP$#-`AiikIrp9VIi06-kFRvvhPi~3GR-Hk=1v!S#? zVqcL^TsH3-6IrW+cOmlckx=hRaNp}_x)ywlgWB6dHf)7kpilo{rRZhQ zjr!>hY=&VAy<`+nfkizbq6q!;w@*U0vHXw@z$pNPpBShaENgFzex?LSOII=C@OKko zK9mGegY=kP(UM@WG>59$5Ml-3-zLHRiBKOBjX;FBYze$4Xz7xX18m-(2W%vh!~eX) zV{Jr$iRF2ZMx7@oBg``gM-a(a{ud+&uN<&|?fDoAD~ij!(UMshl384x=|fEY2|%7> z!G;JZo3BzbBZg@NEfPL$O7!?cx0sNrWDHu}6YG6rjQ1lKcFQ|`%pjXQ3br9biL7)j z&7@E)L`B=r@h$%ZI-J=6UI6d~0gyf9E1_tIzf6Q+IdB2XKYt0Wd=K?v7h>az7Q&wX zy^^yv1>UjC1xVz6HGp|kqaJSA>5`eC28(Jugr5V^<^Y7pPF9tn%YvagM6f3T*QW$A z`oslUYxNMv#5)8ecfuv<07ci$F!Orb)ofg>YQAi-;N;jBPB z7zmaiN4CBm`}Ag8{L%PKtcGa8G_hb=99hkV8mRzHGT~;K0+-3Kk$70j zNW#@_upHSZ8i3pdWHYx51yzcMC2o%$yo7Rp-5NE#U73j(k1PVad!GBA>c3kOEDmg% zMh_S2BjQ}w0erU8H}`+tQKM2NtJ6WxsIKlTNC_2oUN|@vJF5rLXR6%R&soxh=-()4 zCjw0*;KCz(8%)Szhk2edS_2EM9YL5wByxX3w3sTl$f%ncH)t$WBGG0E2jpy(;buU2 z%0L<3a!YKvFOylxmT+MqI{`<9C_Ll3a-bFpv;}CymO+$A$y0C^LY1alr;Io}>tuvJ zgcV>^r5u?aAIGwxq(e%o&N&^_t+HP81gc}MiP&opB=`Ykig+H7G`^e?- zVF~neL3aqK3uqq_i~k1)wL=lOS?nK7Ms2WyELh;5>&QJKYRVNcQ3bw3MDBA?iWwJv zo=5EyP_JAOoxNb;`w#bw{;Qy%8kopE4lJ)?^$eXu{6F(EWgTKi%wAzC~EGUY?2=38ah#)5Sq@STpxe;M@R^5)0zP z#{2K!bzqNU*g=pFR!o~Eq~-_vt}YlvJt1Ri`HPl|8VFgK2NW;iYf8j!*@_CGdPL&stj(tYyAGNy2Rx zw;gTk_G#-)Z0o<-HqhEO_^xgEPn&x$;5Z40IdsS@3?R)?3jsZ!efQj>!$j`@3mB3+ zWcCUKBTBye^n9J~xk_->5ltD%F`N}h%97NA2~fz(1A;g}F$usw73Ti3B&sc7QcyG+{%RIiUZM|KTHq1FFrgU*o?1ueQ@$`Hk*PL;theSU~G8ComXMvBsuXwsA(M=OGn zE$sN_P-E%64iDqDw*}|4HDydY#rt+5B({K%d(cxOx`JB?(j1T!8Q?E|gk*pdELVFh zq2kj9JngG+ils&*=<)$TSl5$f+D4VpMl}^j=pbafYnhy}iTis;OhCD^i7M zfVg9!BvSuHEHp*32Q%B>+19!#C46c_MsO?4m|}B3vYpS>?UdXAm>^dk4!G+CeiA>> zzZa&-1O|o=jd={%7zf=ebP!8NUm`Z#O|Rd_qEcK3p$#3!jR(K^z81v2JY*<0F(ElX zb7rd?9}hosiZEcnQqw_u+}o3XctiRWw|61y&a6(*y=$)D=%7m@@O)Qf?+82_%NxqN zvfbAI!+5OYZ9B|=OgBotH)HH%-O!h^*IJ5zCWS|V2Q^SN^a#HRPCR6!YC~SaK2AVj z*w|zkY8_Pl7)@Y;(~M;-po3qX#$4573#`Ge+LI@oPs02sb*ZmIf4%-FJImhPKrKboeQg5Giu6U}} zF_~IP;U`NyJ82k|w;Y|Vhhjb%U-z}-=d zE97)bdHO6`Y<9wD zUG{yI9n`;@K)w7;V1D=Z``^#s@6Em6|N9;w!v&dgA%0xg6)vKb%iGT7pXVa?xoDXM zA=3pBzlBh@O3~5q0apJYO<++Whifg>tXR6J+PQDe=td0w7TDt`Cl{M zdfByf`BeL|@BFgg{xV7CV}R+$Ais}iuY3$C{dm6pWBB~Xi~ApUhsMaJE5nkVF;`Xs zc;C6?tRxLzNtj=uT)e(4y~^-gO}nxxdw^S+t{qbzT2*=Ao*}a)es2iQ|s`LG#gNg!C}t`%dVkQJ^Sb?8HPKe-gTNR4Vh9ki-`$3-a^nR>0by zZ4kLvZ3`%;h3@EZg*5C;2z(i9!3-U2V@A!lzb(IfJL>F6CfzUxIxbsPa|aVPQ(EzxP8GtY3{feFW%;LI0BgjQ4Z)Z z+Pc79CCTfr`NtnB_Nwg%fw-DR)iJsBP93x?hwmO2o{Z|bipdB0uS9*I?lWlz9MqDe z<^T~1zsVjiQ;cQ_0Q_^`x1Kafi^De^@ywOFGdr{%Wtky!VQ)haqh-}^lOt_%1u`AU zIHUwL{z2;ez{?buG^~v)5c=lo=GIL_^CHo41-l z0To$<2oHe2RzW&Co8VPT8Sm`#Jmeqbu)M3iI+BaXjhYqTEwZJFW;}u?}R_7-WV!)7T zRhyc-m;QA1SPI9#7uW3k9>#-W@Z!{Fl*5~Syx|fNM|KLgayUG;ts<=5uZY!#LL@s>U)}0ealjndye4> zZ!7g69Tr1X7Le5vvVe$}#x15vts20KG>k_qWi1)<7uvPHWd;jI2mGQPcKKctgpf(# z0LMDl*?qD;5k)JgnYxxvVtpFN9}0~pZ6QPUjVX^W$G zBva4G90oCB<1z&F2!>$4$ios4Mnxflisf2N(Exg4Ebu_;>YoTo0Vb{u@ zsu+%>ipG-5miW`oqyy6oizO0Dn=3TBZYMO3_6cir$-db8dZ)mGS3ie+fY9oM*$165 zT<>@{H9-f)5UsS=`kRWI^>Y|Vl%CJ@GLdkthCzjbi{AnCh+uT}#{<320@nIt_r^n5 zHDwilARmRJ2Df0#+X+qO%W){m)-MfD8uV=#(=4TThSSX;0q9f%E4j;qvACNS_K&sN z3Jxg+!z4RJvLdqrw`lQ=A-#zDSZz`96$NDgl@Ha_R2sM85&Vl2yvEd zU%#qu@bo1hEiC4?=6@|tXZ6N!yk?x$u{|!ytc1lm9u$(c0mVQ`EdWsSro^|qZ+pxy z1o7CiI?8&z`AXHP@`t#+dc8z7&lcomj3yOn;Gbg=4uqa??T6G-P~jWO>iSdX%*0-T zMJCEn$sygAQn;%g(p7r$fBNMmrUWru08pyst}h#HoT~#c&ESY`8x1`c*J3qClwQ*?JQQ6r}*veQ*pT-pJS4*b_BQMQ1%KjZV~hPS)O7 zdjo*6G5qyhnEWs7;ik}0o6A8wxmP)Nh8+sm1kW2vnPkBU9l4%UIDQ}265&H+ni#PY zV&%{aKO==F$Ik2o&l* z0gDp>Kte5l4hhJQ_Wj!roiWvT+>P(KzRZlJNXHe^+5i zY?=s^`Upg%Kz}Gg-mQb5XuL$kpxA&1lCeB$s{oL17%<=h6lR3)H6q*;{Z@Ou$tyJ? zY5C}x-=KykDoGqrIENfsLT~F{LjzIrL3f)7|mjdTekM$Rx?0>vt2SX z6o!e3YidY;m+X(?G`T}JnW*YtA$n190N_d%g@4ZWk(CWbL8ExE@)fz+-=7%1sh%PbcG?S7-nQ zzG5eN=POYP>4cAaRRq=6t3u+Q#aZc@SPK^K@ zhNcRKH`eH9`2DlYC<0hPnqJHai`i17UAtUDfl2d-R={&U2ujbXeC(d^TG0+RU zU1Af{>nC5AI4dLG@}N1uV=1SG9_BoHpnl?fKv9XMiswp$p#LWe{dd!^(=Io+7KR{4 z%pC?d5l(trfTcFCnOvMGdg$=F_Awen7ADrY^HkvO}2jUSrOkbU*C)%>^p%kAHv zM_l>&N8XV#GY+f83N#xh#9s{8qYc(&C{PalQKU+qvmU z9~8~v2fXHYuJ(k=rJqT%l-XfEPrvdlRG$&#@&5PQCr7_O zeDOCW=KY`d*RSmML^OPkIM`f%vHx@OAa}d#Z@b#RZr`SQV@7RLV6ZV$&9^M&Bt@=4 z>K8>HQU7b{HV+frzmwHd@?2{h5Q;5HZV}B1;lQ(q-Nl>)3a9p&DcLm@&o&KjkeRVwk)}_AZu*#g348G*4E^8~1w2wKPB7@NegOmkTVDbULQ4OB zdT}5H`d7j(2I{}trktXr8@L(?D>OhA3SiNo! zm8N8ueukTmA;TiMpjeBS7(}|ov-A{hI^w1cj!a7@rp2@%v_^mgZ&(x;&QXJ`a2;Pj zoH{%>X>l1D_^gdGxUU`j3Mt)^d2JYzHYMV`(lU6me{g7H@HM~lLAbbc4wGV!wp`R1 zKB6G14S@ZJPA6ioE*iV+vr^w?4NWsxa~ngkSo-&3@P)1P*}cAF*!09H%S3eQz=X@t zhvDxemleiv%AN}qi=bn#{la9>itWx%0gtzsq6n#P@1{Sw>-@oZ7)?m^oknP~;Xmy~ z_Uc~$e0FS0zJ=gT?!S2fo$tpe=~KYnlg_1}jGDE>fip z;QrivCIz|1LVhAt%NnG|O~Hr;jQ?Kcd|u7@fEpt?gSZX@tG z1Vk4AGyF}nT1I{WpfvtDzKR}})*he5PuS?5z%l!BGfpgG@R#kN_Dq=T+|`pk9?r`i z$0kqUh?5p39{Nmx&Qy8?^PiWLeldiuffovALQdJiFQHT8B|&&Zx`(Nb+u)r7QTXI9!YJCZcEZfOIL#^mfjAOAZb_X{~-DM*Z!j(`t@Ixz(Yx z-z~X&1a@!n-GANdI#ocLLmgcHn8DAGp+Xz^Y>mT!o~TT z%pnGQe8%u|S31z%k1^vh`4WcdOS-S0rw!$!|^bltr;D* zKV}$qhDCAQm1>?$M{Og-nV|Rz_!G0P%8R5#n_9AC8Gzi;0~9>M+SNoFr!k;iov9G>3@mOjDQ= zMKECon}I}`it|se>0Md6`YbS!4r`r62q4nWiG$;IU?-P=|9<}H@bM~1kh#)_LxdoM z`I7oyl1j%VPh7D#nP8Zo!C^ldz(P&8 zWD;xVFk=DC%~B)rwM5=CqnG|&grq07zibl_IpMK z>0!@(Z*FGrBG$|116xyNcedeQ-EKa-Ci^I|!@GTY-6zoX)Ov;KaM0%RSLfr~z_13> ztbcY7jw)O`@_Kkh8h>`L%&pSUt+G#zHg^gy-uZcQgI#*3Pn@bha%(hz z+J?1M&*)f>K8HbC~rB3;K-MSL!dU4(U@$m=k zuhKf1*d-m#08;Of2c`gct2g(yo`L&MbdUGy&jT)r<*fQ&_DqER(thIV<9((D53 zeGr3di78dO&fPF3cCr_YPbtmhRG5gX@zsR%K-ubU+tKeZlcBguFzv@&+AJdQd z>SCR2^dp70nyQKqSh*bZq$%di&n_nJs33*$)bva-mDDo*y0inY-&!}LDlGyycnG>b z=BaY{=ONfu>fd)SDx7C3i`<_yDj3XONK;xgV1J(1_=OvxCa9*_#4&=|slYWV&j>WR zCH?(pM3=Q%C-d;L#=|tokLuCG?K_7#oj%uMH^KfU{v zQugKki?K4+>)+335==|U1Ts8;3pT~l2O#en&Hgl}1GVkoq1aR#E~N6kW21gz^FycV z>j||_60(k-_%{FQTV9%Nwc2Hlf!GK*@n7sLBsH=H?nVNi{K?aDJ@J`W!pm~CS2MCh z59?l)*ac1j7XkY-t9$; zy#DElK0MSr)wKFg@g3BTH(Y-TWRO+zwDx}Mz+v{01gnS1omzFb&(!rM)U7=F`})ko z$kY2D&9eSzsT(aklxi_`>8E`-ps>&xeMX7yW_npYzWi~fbe4NRl90g zA^xdu@9vO1*9?An6tbJUy%o?Yz2MsL($lH4GAT}{T&`f~I>TNrev3k>!I&kC{)kz_ zS6xglzNfx{G6_WgjZ%{fIkWbUR)wktEqp1P z|4mi|KfIE0ZMS=hRA_u+Z8!P&-5|%w`zLWV1y|9v?-}t8=a-F6Wbhq`<@9a`u8TAT z^yc_;$QDkaPlK-}SoqDhteIya-uK@2`MLSNI$h9x^Y~DyNqAxc-kv{G)4=7sMI@~4 z6e9Rlv2Mz?t73`q)c6mCTL9*1)JKPWw|kh zITWCjPE4M&UE^JPh+67p*AkOe6{~9~fjq?<7q*GYH&E+_Rwe3-H}Dn-GeM&j%$?A4 zKIP9RQ8Fo4)9|G>8b(2=EG3ci6`_qi`5|{7$AwlEY1Pn?23+C|)g_T~NOe`?hw=Jk z(~0}nEP}3Q9r1<~NZ&7cTz%f!7<*Na?WNRh$&Y9dQA6#1Zpy5-k}3IkFY||ydTr#j zn(*fF^RF)Cw<>u^AAw@t1v0-oBpzx1wcdK<#oyn5j&S})y#&HzthncsRNERlzyg<~ z2;F}gCAVJ)+t$!UTH*qFl|P9@i*^1)ItpM4f>t>AVt2I%;DhIJ1-%1~kN30+CqspL z*e@r-A_h(V>}ijf^O@+hJBs^vXWRTHHw#V*{cR3mKOX7i)vUu>P1+mdK$@m;u0V+5tjr z3d|S_60YVzwb)c-5*8wl@8EG~(?r{_FzxCNfhaazW)F+7#CHnjvl&XpINsycorfCP zsTxT*{y=<}#27nGuMLNcuI`fFVW*q!;m~w^H%_P_!^T)nsGz!AQL7=-B}q=C0^g(J z-f-2kO-{6_x<@^#;Xl7UIq@!huV#Kj)>&hD$?@u5-NuIOi%IgBC48UZSVPX`HhGz^ z)qN&A4Y^nL^_s0BdZ3;@-H7}i`8VgGI z6!4ZR18(_^g;mCis>f>vPBbsmV+xHX+bd^DW zp{C+qV$wbBBciCVZ z<|@7CDlTvd^#989zXksV{If&;<@q519th zq4$5{2liC#@!E~J{|!G7^8MxZ4?j?k=MCohU--dVXPHZdmb9wJ|HKb;@vrMi!S1Ie z{xAH%j@dQ4y%`n020fUUr6RJMdvWBvOV6fmFX?`_)_*Tfa1pA)5z$y2dYndey4 zu>7i6JIrND5XOIo+t0s%v$DzKkmmIoE(1M_Ur4afP?Jhkz=o^ zmSc{e`{}mQm#TX$i(bEYaWEup$Z|A|YfE=eI#B%XCc3_A?MFk~;Qdbmkr}oq8RwP> z+KNHToiuD3Ud}yA*VWM&de$JoO+T&=On(|f^$$P%CS)mFy{M(%G($XN$@v?Pd4^G{ zg3VH{ol;GZWo=PeZdjrE$>ZmYM4EC!P!2WA*UW0uI`zkQ`zyVS?A&sW7~}Jni^CsF z_}e}d6dIO2!~9s~HU6EB2o0NGTe&kk+6RWr?YZAWPXSfkZAHE{4v8hHsIJ}ZN``>3 zP1Pr7i2AOl+-%*si)mHK3Fp^qYT|=H{KxR4U=%LnfC&*xF8l3jtKQ6l)X2`Pe|mU6 z4_bFRsn%e_@j&7JMq{7eC-(=#Hmwtl6Z^szh{JXN@P@I=QV&9v``OS4flO>CuYvJ4 z#6m1%t6S7)l|nCgS4|v@Rf7Op$?Z`E*kSiYP z9niztT{>TUdgoo0WLcWZipUt$Qbwl(dGrqVASze$hft8O-uny~SbRC8E6b=nM)1sh z;?KXaT={LRwZO(QP=sDSVJP?^>5stfb9r4trfDZLpI4y1~GR#nqs?Y0Lv+VREoHjqIjR6<3!r`OH|Uk9yQOjA79(&(PVCo$ zHNm|*W-`8r=yzOJUyICxsC|u^pz?(_yOJZamN4l*bNQpT@>6zLU&SqeAuM?TM{gRe zGcsF*7sC6IovI?$MaSJZhP}NPgttBEAWg$b&rui(?Sd#>rVFSb1Z8ePNegC{qgsRd zs>|b0`&7%3~j(*quTadTc9Vo;zjg%+n1coXz;N?`(+;pt&Z{+y%?#E05D zoho!Lfh<_4as(np0;H!$D28p@P%4K5ZEwjZ3ePz78s-2n-|=?V4(?YG)v}p*Evur05%Yt1I(NO%qYEMh#zPp|3bX+`U+hWWN-YqFmA-w`XfVh9VMZ*Z8Z$^~OuZU%<>{5du3iN(AV?-Du{ zpW|9s2q>))4>=rmYViEEyE4_F&+h)|ODDSPYg?40B}da*w>b|Fo6H(zEzmIRC8;PK z75?Ux1pSGLR%l+s5HQL|`r`QuUa` z?3mYP&cWcbqhCwpJKe&k7Wm^#yJQv48gXl7ZAuX`xY-aTm7XMHLnaP5!E_TMvJy0Kx)jKd1 z9c&TJD?YSHb#%IvJoVM-@P`FQ*pY`&Ms+&Ag?-=epd@8uyi_D zxQ(_IvnP*#lwfl&5le7AJ$?F~9T~^)fug?s-f=%Q1#BR4h4sUIN~En!vd-$%j@6=AJ%tLB3u#?%NX4E%$X4cx+e~6 z5lbwx(BJvp5E_H~d89znT!EXKOp<@Ww?IX5Sp12*fikbWPX;bt@=4hOCk9KV9UR@< z7I1Ir5Iph>ZEI|Z!h)ayihz)?pj0fnp+9lM-xiLu8+{Vm zWFTC(dR5Zj4^l>v)HcRZK>jRP;?`AGOV-c=&;<<(BO2O7s#|yqkz6JA(jhKtEXI|6K|H-$C3A3-?;z`2V4V zF$XVi*$e;gAnsLir5nzwK=p!M)0&x}&Mw zGAtg*S=Fun?k?kzc34*mx`BpeDcC=j^o=*~E@+a@ZFF*^@QJlw6;t)(*`{T7iF905 z3=<8?Ku24~F3T;_R-fiTuOe`kY5D53>%FI`OPPMDE@1(4L#2F4 z@NEJIy{>m<&q^iIky}7a+23@QvXCx&b8K#7^uW@_#?VqY|E&6&Y4I0xanj}k_bBo* zCbslh+^t($3?1sXjSjG5o=Uf@J8H;37teO?z7;)U-#2fABhltk_px0)gzuz`Ig`iT zL?R+#OFma>+#Z^yvzXWCdQlsyyp*N$PYJsU^_QXa@|j~p1}SWRKbNhd3IXl)jImT7 z0YrH&A^)G0!WubwyA~XEpz)dX#yn<%pK%I$g)BvbJS=1i8;+?33$gS0G=jbgNO%Us zU{UT91P8PDTk#^6aEn6g{4?D!w>(>=rypzuoOTpcYKU5uLT8yfFO_#F^1-U-@hgDC z2U}kU#NFaYAV)WnXs=98%cY^SwB`=*pX!?5oDZ`WTJ2N@>JPf*s-JESEjVLZ$H_D* zW8+*4{%rVL@mt=lMni|$!f<}0=6`CgUI}v6G;~5`DikR>kY?LOz{38HnB)t zhvM!xd+bx#4%|(8CBuEys$25Ey2dP{XD@k;zm3!j>8}DTk)L#;y96BYWxmjnLiyKv zX9};rG)bdWsy}JzxQdqKSmiS=G?dk8y#haN+Ywg3XB<6rWE|5p^zZF~=+}_Fx~A90 zDCw9{gZFLG!}ehHm~k7k=gnhQ+9r?2?aoMFdUN7t6r2dvpu44mdch=A^Ps2IK5=G)V`twh79^L5{F}U+s#S|qH)iHfHxy2TD>?h5bf=B40Yc73FD|eD(r^Rsww2u;# z2&2qE(ukbwr*=}58X7k^Gev8E7rP^ zy6HZ@7NsYWNA+r_(oc50wEgpCV`2$ANwzV3QBhtB$rMU(%>M=nLtgq7XcB~d9u)0N zqnsWJcXl4zJKEYiQJ4y4B`3)bk{Gv`A<{J~^xby{M8yY4h<9Y0UE8?y<0wO)_ua0#9(4 z-2hZ*nFe=8W&O3B3-G>{U<{Z_<(aZexyy7l|h&@lsI;ltQSv4qz>Kx|01 zXslH=I&D`VH;3uMJL0w4rK^soid>7@-D=JF6WTD?OzH29S`%#z zm+Xr(l`2;oED$H1GGyEv4_|0Fe5TRu>h?^theVS%&Y$!cyV^cOpMpQXW8_R zuNQBckZxX_({w2?IV{KUvfZao7Cjedez)%WR}$$WswG)jAi~RL^94XkjOsP~6{m~L ziCsh&bdRWC4omj!3lMuu95qO6OFbI5B>xgSV)m>pon{gwvtBrE^d&4iEG}plZ+61s zuwG8_oFAPd4j4dO@TqR!a+v6vZp~TZ|Fi;fm2Hdw4SdJS{2W&XtjSfbV1JX@MfV;dneUWI?dA{Ff4VQ zml?24_}$gdJ({HJ!vsghS;oKoa=RyLjcnLjEiHpfVmOvIxXse`gBDuNO-={c2GJF{ zcDs>gpD4+WC5y-`qJ{3+ZyAOrOH#b(F;$)Lj9e1|37(jBq?T1;9*2`s0R}byE^Q2Dad!y#16=&p~ zX`bYXR3Z+`#ZgaRsTiRA%zn)AIHHVy2)=*xte!Cel=N!==~}oXox1D<9@MW@uq%>? z6iJX?req$bTO+mBY)v#=+Ma%}l=%?NxSin%hkLB~N{23+8b{&7Y6c>Q4wdO02(~3b z;<=?N`xL5tT^v3DzWs1ES-M&g^C)m^J!3v(Q1I>hc(NJ(lHUx zhNWS|Sr3$IH1f%iz`{V}=C1LtVW2tvEizR4RS55@^Lx=b&w~qh-ve=p3!+h4bfk{& zm7O<=SAO&={x-hK`}^a8E5A-z^EL{u{E(vZ45`2CE(?xd*-@qbT}Oo^QxW4-xEB>| zM-zk6q@YxxdYWiAO<0YF9H-${XcEaZ{1#0zI$l{VUfnKUIyqitC0=7IUK2{!!qOY2 zF5DVLtdQ&>Y`fQNF`5D4eg~#rO6M0)Qi=+Sq(BaHL|Xx&7wh1hBlcZ_h}TSrM6LjY z9eNfmr9u$mP?2gmD%)(BIu7xZD|9~_^Q6=KOB*_i{%3y~87+8)BVo~cYQ);*HA?`t zSFMNb6B`dzvN)Bv7s8*-26YQW@Vt_u3X`(d?LaO<3pVJlSGAxu$rB^VYVmPGm2vRR zvomc`#a*7of59P^;v9z1eV~9$5K&VQ>`zQQ+bXb9U@^}^ej>nA#4USg)9yuE4y>fz z8BZI9rjHZTNp9(rUILGz(+AZuChXE5*kwG%X51%cy!6U=7@hH|FoP44F>jao8k(`R zmGQPd^L>5BJGIP@$(i3)GCx7HJ{M-LMQ5!iXKfT_{n*Ny#WEM_=?dm9oN16D2lAeR zcu^~6QUNw(gA$yPRV)FCK#-EN?1Xzrk_zN=?%5!Yjs-`GNCnHrC_M?o#d^i$jmldR zQskFFAl>9Je_8Dc@C}|j)SGLp!aOw067=CnwcwD$;z=_6eJD%x7!jhv1~sYp9Bvmf zBgoH$AwoG)wXD#DdgOKX=|5Xhwt#^;7`1wAcp2DVk@sXOugM136LFQmy!z1+pg0G` z_gn&hW1@|+C64L_9?jpZ$o;fS;4TLq#Kys<)V5oNbt?!EuIF!M0YNMIEHJVd08PgU zEjXV7xfDdri78NoYnAn0whLTI$=xI!>>;88oZ&RWUdU9@%~094)uPskqTBYx-A2V- z=79E?V$iqZJJKaRbH#(9B_l_R`x;7EtHl#N#SddjCXGrS^^~yfOQ&N>$3shpCrY16 zmp+~=I>su8AQh zpf%2Z_sIM=0WqpTJRrdNTh`xf4fUzRU&Rmff)z&y@IoA7y8?Do7bg^MvV#+$RS16S zjQZIsOd!kq5(Skigce(2pcjZ4O5x2VsS;;o>jj4;4%~@-I&TWS^aDY7QPFCEyMFth z8LV@aTXI!7O7sIE`H=+j7EbsTQ}hZ~KzqAN*SOl7dHQc$O**N@hq()11kNFgCJdUP ztSgUJfKuxhi#>!ov$wN}xt*#ntMB1|Q9Dn;^V zYNy-9Y6nF>l3?BeB1t{hBQ>g%dWzseaTOorD_{6mZ#Pt3Y^+IbtSxG6zSDT)L+o`} zQ=>*xi$l}R#!GFfO}84GI`21i6&3WrntL^x`yHBp^q?Inp=`Wp6-R7x3Nf2~{0UnC zPdf68gM7<{dvm}vx*r7PQlcy{%@OVEhIy0E02tx9OO72#jO;1HuPt^TVw#)b6w;IS!tGZ(1h8%%-|QPY`1pSk0_N?GSx`sY$*u?Brc>Qc&XQl+1Ei?k zi650OSDquuO4jO1#Xk@b9etAb;AJs}Da>2HB+@2Rrz_L4L}<|^LH;BJl8q1UH0Sqc z!o{1?z-AT2vr2b6E2YXDx*$F*!8n#uwql!4E%UCFRR-|)`Bz`=Qz30c|v*RUtB6KgTzRWfp{Z^S1ZvpqfH(ss8B zjruRg*8h)A4#1BO9)MN;Z{vf1JYK8L$$XF3(f^Idivhh=&#e59$BS-!zK{@RF`BOp zu}=1)Elr43>+DI6Zdd*=)988Y?C0$S{A@L3@-~HM$ z=N0HM?_BtlI56t_+NTdQ_O|J`D%j`Juk{UH_&$8-Gt3%X!W|_-p1*ZJwglbk8(qGQJ*uSWKQDA0Vq8m5!b8)t?h^`ZC#Ukp#y8(=+eWY z81n15?{i7>StLRAWu_6@D|6pu{VoS7OXz~R*r(QYVVzBEgv3FeZstS7AQAuFISzWO zyYr45303w`Xxt3WaoqPaD9_a+M)~Bqe09|#BjXCVNvPJ8q_X=^QoJtg~u&NiHV(s3BS~_SjQK;nqgbTb|4jK*h-|GIS z0{Ud5dM&I>S|fW{^3Ry z#`Z0p#^k0Ji>j25S{=5Bygzr&oppTQvvK1i_Qb_^xubQVf)4BohC*sR{MF^Agj(sh z<3lKnPdxIvDqh2xpD^TvvZy_dH>@i&8y~A^a@j-WkogL*h*9&CNra(V<#4$K$u-mD zW!%C??=^lq*I%Wqxxu!2k|0RP-o0>@VXNA|K{}-QH{^+(JxI3%n9eriBLX7q#9r@jgX%&C z+SsGQrnk~xAUM0LMB`PgbHTp-B)%#mOB8pFq3nLbAf=@z+le~$va#I zz9D|^mTuPZZW>OnrVpaY0&hcA6igTJCAR zwaHywHzy?!VbMQ{;Jl!LXAkMwO$ph@(dGBW(_|(G(rq@(vG)jrpP=r&PV;mz->v(O zqh2-zC^h-3eL*T|w#+5kKkeDBrAonAdom`sQ9(v>Zrm1D6T1l*lb&Ix$IOP{8is3B zoTMKdeRc$rNfFYOp{0e*fR9}XH<#WR5ViR`D=fouNy6#cr28mZt2(?wHXSFh>zC~r z9g?|8QRM_2L&kgnSZT^_@dnOB=3d<;{8avB;h6Z{_LA=jl@?O>os-EZkq)~g)2gZD zNfZ4lu@*Hc9SxV%V|hZT&-FG&MN?Uc9W}B7>NciD)4A<=HGA9}?DkrsHDHGiN^la1 zu(r(8AuPGqY-u2w59xeHcLazEo_kSK@};Bh0OG?UDA?6Wc%Z@LySno|lt#0~g(lPZ z$9Fe|RqairCN@PhpMQkY+}Q$IQ2_eUzzQ=sxfn4m|8mlE(yCHhnt(P?Nh%4i zRVkUZ1QfYXK}PaA(4-FyCySxDV?8;~TI;2sn*PS)eFqjbEh})Q#T&hHL4oo{*iYI) zHh{V5XSXGrXT19wpH}>cyumqLA3e6;PsC#%pZF8GFUWpk6`uWH$$OBGieG=fz1jbx z^k(cw**80Do_9AGd#Ib5WS*qgy{(LMhu#xOb^odRDh)vs)e?{S6Kd#tGSsnf(A6~c zEdSvbvW*_RYI!KhNo4Voun6&Q2k=3a9pUiVA%*YtwmJ!^NYIRfuVlE{mC9IhEx=Gs>rY?E zlRNO&d{Ngynod?FXkm5~o9{dlkzi4u(w31MJKT*ntbKUyw=U(4l8?Jrj%Y@Rr4&b< z0n;lWeIz8p!&#ZFJ=y$L5AFN8VywI+bT_)fI538ky+KKK{%i z+%1?=+&VjUCTc%P^jM>N=flqjsuEwle}~xkF{4UfIH~v;`VWHpq~kR%)@L4AbP>Kb z=dL*IJf?YmwD;U|1jQI@@o`?48~+B1_eG4ElE#$6YW$ zj~S_a>9VNhxh%~7DSj__xGcXr9_O0eMZZ~iMM?#>yGNMDx~S$FabeaJmrRRx!|^)dPj zej!L~_cA716>|NA-~EEi51(HMjiO<<#NAm4zB=a?Q_*IarT~q1+8wW$Y^h=wFFQ+9 zg<7d6$7|Kc?^%i0h0=E=qyHOz1*3$+uI}+>V)+Q$2@&J#yG*y}=EQ{6BYRSm{)J9_ zWqX3j3Y}CBQNSgbx$e=)K9Ff62w&PwwoCAL7e{c<=-C8Y0iw4Kd;nDA8m47{T2Hb)X$t4b?&d zBoSl-E0bfRkr{AGP)G4*vmokBL3@C}Q7kNl zDbmB-USSgJ!RaJe>v#BV6!aEYna_dUB;+WCk)tnqmkS~Nz!-UDOI^#Boe-7(nT=0T z(P95#%7?Zg*1YT-$p%quL-x6~99#?|aK-8GB^9~VZ1WV=0cF!aHYm1Da{(Xh!R2Jp z51e!V@~^}kpMM!0xmZ5`#v0@($K>c_U-h25db~#<(=K;kL*6-B$Q#yGK3vBN7+U_z z!fYD|`=aYl;RVXoKxXPU0z8KVSmg>GugLeYhxx@YoMw<0CZJJ0o*0}EpSz84!X7`< zUJM_yUJW2u=4v)%Gbi%%gwrW8xwWCP3~@nW#VfE4dAM<*LT#-^JFbK5 z-?rzUQYm5L5xFYffAE)e{$Ko^!b9*};a@zI@U%+>Pv7E)ZaIWfwnwJA-W9q>rL^Ql zLz#ov5p#ehu2GjM-GKkod;bl+GRFUm7Gw%s8r#vJ`o=~Pb>KA)>E&oe&iBTf_$H8f zQ^Sj_S_l|Ik*)rL>nvjKG=R%!l3okVV;W#SBl}P*Aj0Oozq(4tbjSvu6$g?x+(Z4mPp`!GD-H<9&e8 zRL4bgaZ_LiINSGeU8l2VXJuunXK(4>UE$3Ta~7>bsz!ZguG3vJ1qw9xlkIdpg)O!) z8CfqmtgB`9vg`6r*MV$Yqq*z4S~s55jq}&#L=heRyOU#SL-FlmJ2F(h$1Ap{Fjj8C z8g;a>>)HeAz(8Hxc2AA>o!Zzt^~JQIHDvS4J2#5&w959j@9*tM)4CDc%X9AKd%XHy z_TDWP>)yF@?>`8u`u~^l2w(t>|KV^3R6IJc0tNa%`m`|wyS0k(|MF>T=IdksB5DI+EgD*6M#NA!$(6wD5Q3ean>MNb*q5TtMdo#oEA@@YA@JvIB8f0#KCf zA-B%hO{)v5ZDF9I;I$9eWAhVPs0@W=YW4d)uR4jQd6eY=di>r?J#nXl9(*l7aAmXB z^kKcF5X56`YhfqYD%?hV-YoXF=hr!@PAT7R>deEk{&SIer>E*)x^#_Z1Zx zA9sO88Jtw;A2Z4S*s%H4uTp0&R*UC;|NKOFviEKA#f#sCpEMXJMk6%ywP-rNYz?EE z*`NCzPElw~I5~Yt#31I??QEg`JUU!;WQCp)lYFh}pk~dM64JP3ArT#%mQd}aMLhlN znRXTll%|vzS~G;{pIL&dcKO^&IE7_Y2<4)IHKMQ;(>aaFpTfsJZVD_-%k;d~bZGkC__ zPc@MEwg~g(f`zoj`q5hg(hl=p5*CXW+7m88@mKvK#oIcON^y9rISd3870IKim4|gK{#vH){aMpy)%0Hc$mb*z$_Mp&h(2M$toZcD4-LXUNp@YnDAtH%iU{U- zIb*(ISn>WErCxTmb6|$`%ZwpW+%0kE&E;w|d#E^hF)EN*@thy#uL}H{fRujM8Nb>Fs&UHJgV&=wtpz5AJ-nmf$ZF zW%4AnC&wj1Mb_$I#(c=O{0LweJ9%5r^}az<_qbagyb6_dX=|X*(gA&MBzN-8R%hi=dfGhL3cF|Hd)>Fo5ITHxyn2)(o5Hk&MGUWJwCj9e zj}e1c7W5`Dhj7pXo4=M0hu7Fz0relw2V@<1gH@7i!y51pD+%ubR#zu6s&N8mb+tJa;+qs0AK% zU9dGF03~b>D;cgq{p74%0lLkjWXH0nQ8d|=5W4Mo0Mv#vC^sAemZBJD3m;TcJj10* zo&G+Wc0LR?QBPtIuO82a# z|AMX#DM(@`P;0!-TN#SR_k7N2*yIWT^%*( z;?PFBMZJBtj66Xh;)=JG0~q*MpC!66yiv45!#&lxR`5M4u>{JUso$4_w?tVY4y<2` z-LT9GdewN;G=}c{qUu=i=MR?6`2>Vw2eOm}(Bz#~3^k)E zKsg+%Eij1Kj|y&ve0*Aqq27!hfAox~KKXU7LF@_%Hav<^ljm{{0rn#2&tJTX<+0tg z{ai33%~P3sH6Q_}(`QiQBte)%P=l~Ed91@tBq*KIXaleziUSSa8Ar9jE2V=W1D(2V z9?+Zr}G>su!M3Qu*PM zVslLDo@k8kZP9gl-nL;M;L$8%&^;|oOW&CHS!=90K<9keNncn%=&YMT+4b`lLOUq~ zM`p>3#E}!Vr;W>lqH*`iUh_}(Lz4_@sMR$hgI5xio4gRPJ&*|hL7>hIXuA`Y;*@Ge59Vqi1^Z8)HLaJ`a00_@?ZKE7F6LY;=-6u>@mEW z)M_#+1Y5$f(%-;~yv5Z#K^cYT6wC+xIN2b(%$+tHbbFzy6zrsLohtLOQ(V6V;iPhS zIK%C`^{KPjUF5l9KiW&{jTV<_Ve>CdJ+4`gPgnOVkmzPbc)1iG$9=!K>DsL=XU;xe z$BSXDjaKl5q08oGbvjX9no2b5vy?|`W?hyltketKA;q_?C(^k6pJVDS8bAG+A^%1E zYy8I@{3GzHMf+!N+B>S)*iVGw^b<;iA(gaAEEYbj3*1f zn37B|`@~}GZr;c)nsx(g(QZ6b-V`()&s!Yzi%cE=Nw|B=_@$wLWKxZ3PsGjG8nyL_ z?gyox&Tj@;Ml&}by}tCB`g~_PH*M>7)DOZ*UhmSb!Ke}C8lgG$ISVTs=x~X!iP@ad zQuU7nl0@?tAL0WU2_A~K5~vV%E%|A_V9wn8$z8W^UfL7F%bwr7yxH|N`D++5?$vsk zas*|}v*vPduG9&w`Sn2{K;i^1j6Kc3!^+@_sxe3&9ND1fG?PH>h*E z^kx6Db>m6w)_W)3w%FV3HO~o$&yRV(cX&JimI@+LAzoC$XezXj3hSnd%u+?Ss3`uO z0FlP`X-h`au!S_4ZkpUIO<{|M!^SHS<9B<-t3=1E6~=3H$7{{T>ukjnuyj2lUEhno zFPcs)q#JkBO=jt4TXYgO!D0oi>72md?OGNlXpVav9QSb8N>JTG9w9Q^pbQUUyjvlI zM`8FRqg7FYS}YLX)1*ZPYjUEnx*)e!pe$Dq%`q@R0WJezH#o37sv7hg@En(~cuth7 zWVp{V;)!TI4j4=Tz$t(vEZDgYeUjG=1Oq_m3U$W{;XWMvMk~CXVq(bxh>!tD6gVUr zO(inu(W#j1NLez#N)@b%0*asjKol^Sh&~wt2BM;*xq|IDIE@V^QUu+qE<;%$UH)G? zOo3GapzKZ5bu~skHY4&mSdI+n#)JL2f*JtGL8^cT^#X*F2CP6ySHRjiLM{yO;Gp72 zbh=0wM86{HaW`YyE34o+xG7n77eU}@2*idBly3!%W6_KCC?E@dgOGHC0yAd`?8!xa zCNiOTuniX=#E!t|X8q{SZVbr~Zp)Ix0r+Jhm<8IyPDZ*gg~OOdUP-;J@Hj4{8=Va^ z&z4NdM)NAOWshdbH)MHG1eWXoU=(Bz0EDT`ferxrTH$phK}P_rw*t0{1Abth3!6$e z`kB6eB6n*g8`_rDZ6^&P<=NOX-Kc4TbFg-j@cjW$I}2`K5$Vx@HtxAvKbxy)BybP~ z@X*b-j>$VAooC;Wf4P-(HU_?{6>?3lAiX`^YYufGw1A#maNJ11-yU%JXg-RT2Vnsy z?6e><#JNG(zCs#0PzY&-aG{ym>eoD@L5W0wq!9o_N!&#iD7bcwnv(x{QLv86yw(jr zNxF&(O~=>+_Qe3m?@=wQMb29c{>8;U7Rae9D|W6RsHZr7m0(B)<~b+Tk%1zoJxjh6 zq9#&uQBx(4q%(>N65UupFbb%OiYnLFP02w?b5mrU%L-1QKlGFVUZ75n1La6U=aMgI za0O*isoI>&uy5r+nM&a{$nUN5;tSy4ArQ4|Xp}}J=2$|l5jwOBlx3fKY_-xJ`~SOa z{C`+z9tNxckN`FIV=eXd6=V#He z6`qBnGoewjJ)>YkBb7k|(4z4IQ~(Ur2j~p-Q2rwi7A^;2$bX;N$fEVE5@6a<^02R@jH<+030IzP2E~Nly zbIGg{@FF)G9#W9L}>+s3fNpGNICfZJaHY@Ul9!73z?2oL@mDwpb zH*Z)y#L=^?eFR~dfs+W1`(fkZZ2>-=>a*m)14w*p?{0;C4+1c{Y0G-$ce^R!WB#qo zN*`9PY~R3TH*i92`n$o^66sw6c~(SQ7Fr&QIOPVXp+=2c>Uv3F`+2d z;_R80ef3)z7h*Dx2>{>?Kv`Z!&wmk_9b-6cL_08zRCblkoWfYtQlU#WRJAxQk9_aa zt@AOu0BzV>hA^yq-#Kmhgm1LPE7@G$*sk9e?lDn$7Jt;PtU87EWp|-|=lpVwn$pcx zhj%CG_mZ>sf@b~i5s-ek;Qtbt(nZok>SqpUrKc555axTcI|fc zvw@XxyO^wkf`j|?Lz;|@9~0zuRjiTACTu8%k-+w6mxMQ-g1J@qJPbmPdFdQ8>DDbZ zq-C!F%xDu>z0|1km19(fnyViKKE|@n8@%yNw|R0k)Q3Vld(6zL!3pa&MmPQPI>^<{ zy>Co=l1<7&ujnphnt0BM-`L)KwYpmHo7MI-HvOTI5x7BK(Axuuw{n zc=rV!)*pJvP=zcHr?*YbV}vck>1VhemzJ~YL{0`^1anDhF%&KW+m0piS-{PW_Y zc?}35kP$8z^bU9m)SUQLrFRQ1p(#1$T507Zk5pfL(2w}gxjY)t9YEzumD7JeWz$)^ zcv~NtE;P*D4lwQ z(f0?i$TL4Ujiuy&=A#(JRMB=$Gv_m$F^(s^-9wFkH0@OePSjc@8Iyv)31+zqN+EyE z<~L0!9msiXW@sFV6^+@9e%EqktL`WVBEmU`mVYz0+Yuz3se$|`l!P*V&RQQX6xoC9 zE+zM>t899{cy+cm>X6>H=Ce~lwIpZ5+zTcQEfyU|4>khZRYfo3Faz9 zzbR&bw4b@KaodUTEdSa6wm%lOeU%O8*z_fI;a2hG&Joo|-f5X>I>)?mJ_7OAH$~48 zn;xikINf_l2Xba8+wl)Et;i8VuCw8K5I8`q1(@V4se!x+R9M?0zdz9TlmU`YL~r!@ zvg2HjE|QkJM&>0j={Hd)TUTF6us6OCiV40)Z7n8afiG zrK&S)lYleimJF~0n3nKDn9G;=`h}GNHQQF7)JLRJg@&z9O=z$vkOV=-nW-S$AecqU zs_d*=%D|Q95wWE{H%$iMiqPtoL1Y0 z2DC08{ruOQfuN~*6{Wsh-SLy9G196CAy-#h0pp75f-qtU z)$arexo}7Bj^<{%LPBOU3LWWsp=j<8mwE9XyaAZWx$ynOscoFeo0I$|w_yC3`}HB^ z`t^{`w781;bsQJe_Iwsi3Vg_!C1bha%*H{P%y9U3X@{K$5aFbF>2Z>sQ*v%iP~DoO z>@3Ai!z5GZ4;qzTL*em?Gf zT&(yf^k#WQ$%i~NR>jUgmS^i}_%b=@&V5)HVN$+|6X~RMTKjm~w*_WM1hepcVRZ@2H6FTj>8gC>W0DIuZ|d?;hsc#|`AenZ|0Y1HA~ z9hlfm4j>XcwntJGu1;7o?QlOjDKmBuem;b$Iz^dus}jSCB6AJmA#Y@QXkqJR#`whe zb8lUSYhwCtC%2)3GZ;so8S(e8+y4CD-6$y0IDPU+xODpR+ploIKWVPrgh-8P)t*^M zX@^ijTciyO|JM(!s+@qvo94+5wi^0Eywo_%cm0yXKx{8J48tw9 zlRPgxcV)m|+%9h^uKJTq_+{rqa-U)pYAMe?7p_Yg$~*hspk-hJ>urB;Kh}GFb7!Fe zAVh2`ZZG7jA14h1&=Cf|-btX3GWb&xImRcf$=-OF*4ai6ELndW`i`2MageQX~FvTCxAoF4AW_dGP{Z}a}s)hauKX@##2Sw`{1qS*KE8bhBBGj&Wf8OZr9)0di9ydNC9LF#MD35LCQa~E zwQ&(oazTX|}pH-DYs*Bzn{1XruZk)4sG< z$|_CVdLwoKN7A{=#VpGQ=bzqvQt6iuS92779m^+I`{iTbh$;%H&?_opzUBL?gAYR& zTFFaT5;0!>6@a84(I=66DM!-ty;2_hG4SD!yt`b{%wL?VpCX2-cqWtzwhiu8CfqY; zuNtZ=b>hY7T1}z)C69YP6F=16M>uy9# z$^*>lpqLYp#}5b7*g`>)S5451SiOTOx*e+fd!bM|@pJKGs$q#i?6%KR1BfqXNY5jS6waF z4?%S2)E}lT?zRy|fyECAQ%`dnssFO6(wM5>8I{EM#Iw+@rP^4jQgy*V_(>#3vl8{v zW2K$>%jQ?h^NJwP{msH=F(o{tdNZdf;?MBQMS}A`G1^O3cHba+?~K+3=&)b-21Jf< zFt-@hT42DrMfof?+&}?&W^caHJF@$oiI(VOvPB1Z+Mq@@7Cz(9E@581`!L-Z-k)vf zkT`&Ylct6r@G=V@>SE(V={{rMxv|F54(iEirXJ z9mWbtYV}A@)P+~0`K%!@|BHQFka2f1g+$kI?$jwL<5<3Z{z;k{KKl@v7Zhz-vGDo} zUhQmOr3D?hf^D|XUXP^EHG>lKwq}j!C8Lf8=sH5NMYn(jcY8pI@)jbdJzZepbtKo@ zZP|5rQfW>-x|3a9ndca#qj0ED`>gTTPw3?X52;GSoji*GZSnTYf(ydAjOXUyV$C5H4fy=Q1dc7#Mb_RKdo*W?G!n~s zJEox&2X%1pHHhBR4sI*`WnEwF{ys|`WNVy=IR& zu8<%*^U_bIV_HF(xud7?-!;B3w@L(NynzE;P!NRVkLRYtO6_4k27i*o*jno-GKD=i zS%WV6)|y}3w^hQb=LMf>tVto;c9I~PyurB{m|^WPS17+bXU#{utS7;eLQ0FmbAxT+V<5=mr+vCqp_ev$^ZzX*3{*QO#KhSOZ1>~7!E9NcZ+yLe$ zm*^V7xF>iWx*sB+#{Z-L^Evnlv=;zho&P$tfZDJBJlvf26X%!#aOG~-STOYM|5p6( z#)EKNYU1$#2qT%2D;7YI@uGzyIe_3P*=Gkk2jM*Dl`bGqBeef+`2R(|Dlg_J=TLU+>}@zf9m(x^3l1Be(90Ve z8>4h({7qA)vJQE$X}q8}LWnu9)2?OdM*k0&P33d)6>1J1L#-jL)lL_J-&~g-4Ov~z zZY^p4>x7FKg;TSa@0%uAYrGx_@P+ zrnF^Yw(dNPk#9bdJ4@EhtYV`QPghXG{@x8AP@%%pu1JIU6fZ|1yXS}+GScGEAtj8( zlQD_|@^9v7@FN@1oMNu16Fog*n7wy!?X3c5uZhoA=`2vUvmg+CuKQqq;1wQSr?jsi zttL}Y{`*0~bAN2713CJLUau4#0XUQQQW62B51okQV$Ot7cd9~v`MZ|~YIuw~ql!k{ z;tC~aD{zMp`pQ%{KdLX45YBawy#-Y3!T)r=FL1M@RW(_-jEsCnZTZtOTq+~>h#6QUj=!nFrW z)tk+_FLrt$enYCdav#Z%F@A|dS@E`<@M=~l-DPta$Zk2p8i*yHRF=}V{SYYFJDv=4 zGojHNX^5q02~SvUF@Wv|G)i)Wsn$2Bttz2HTbC8k=+|I6rIG`MEG-Q zJoU$Sog$(47e7iso||{;>xIH0Jzs-2ZqcD|_3O=*h?s~~iBn;ijsI`Uz_o?lmu$A6 zw5Cvu|D!PwV~`wrXEGsuNyea#4^FP}iSi8n)Ai;&HCDme3}9Ae~$H-jOS?NpfHKwD#kY^{0G z#^14VYNtp!jrf7B%$4Axnw^Cx3h5Nvl>sS_%UdVETa4iYwuGH`x)Vy&ot6U&X z72U7I48EFcF&>e0Mx~CW&N`tm#X1&l(*kQ%3wqZ+Y<?f=I0(XRzMF?rAQfL&4q#+qeV{=4xRD?S&n#err;}Sp6`p5R zSD1`eG+0&7ey!!M(wb2=xm#J}d7UoiTt^S|ehog{Yc3;ykx|o*R4S?7o;!yK5g}O;+(&kyqxQp?8?0m=DbGqntiVBZl{fIhQD-SfEcDdW#-9o$d%5r*ViGRDf=>q=Uy6&H zsIhg9s-2dl1D7R-MwuvnEQ{5sEgv(6(Ft7N-=vKPogEy>XOeFS7JGjm+wOVB;w%pv zVhuC5`93wg;z}MY1*z<-ln^SzRPCvTq@^Ja=ZB7?YfRvu`?RRT@N61tM|>j172r)b zS2UloZ;40`_bS#^V5rB3zDNRMG>ULs&WQ-B=pkzGZ09Nz)HBSd085(ICx>fE;5)rt zWe!)Lk{NH=9vST8@O^L6AnbhjOCQ-~uH&}HAzTI@8X!x*%6bJ!IqvGa_`(oBV6AeZ z&y$}R15upxilX1i z!ow5xOM2mbW@Ng7Gv(J8w{NTdkm|vU=8`g+q-G7tgo0afUEpJOEjB_&uDmKSAZ1)Y zhZDmTmR?ZcbVd&g(f4(<7Jo9BLkx&bePJd4k1`nS0lA$2Rb7x8zQ?I}jL4F%`i=BG zU)(JhiRfRhunKgx1No^)BKw6#6aG24v7XR^!za?5qUD1+Mo6V{7N{!`1i?TD3CItY zsrpUZbq&zEq#a#FJyO?4YMD-SC|?BZJT6A0&czwCpOZ^TX;(O2c?Cog^Xx=2G+V5r zb40#lFglh_Io0C=Ty=zxN$Hq43UB3#l7M!{AspjtijVgT<&(LW64d=0wYkL+O=N}EgfWIQb15*6JNtlIv`N()5@d$VvLEfu^1 z%GlH7zJ!)bHvp9ws8FX(M!#sIlT=pC*70qTEO__|nc{O}|)J2V84dh+pn8 z7N5g<7jL|Y7mD;h6+H(mpiSK*?-o~#0cGUHlANOJ@=`uW*G(J3_;RFGx8j2*<){fD%$u1RC)X#8{gfL17)w=dwq!9Ii6ebexmz zdwGqoaEgrqKV}K6gz?FWUP7-Eqw2Dk?v7pLqyO~cE3MTGztT@5F>i>;-n;8~xDj6S z#s$<-MGVMcwy?`f(rO<0rI+(wol^I19uRNMSB!=BLw#;@xtGyCaVgcr|H6+9xWBym zj_><|3}HxY{m9o>sVNK4*5mg@Qp@Z+KapOWnVg&X`&ovuf`ZPTI9AOlcM+UFe- zz@M`V{E7Lzq?!wR15ju_#|w!vz$czz8$T4e&0po`fVUOlW1nm5Upd6kfy-8kf*+=4 z>*}J=`t)BlYD=LOMULX5vg@Xg9u0Zbs&h9c{?#9TegNXGz{>X)+w@cqkkAyxfx^&4 z({pKu%StIpH%+k|hGmr@5W_-eZWCtDILnu*UqL|Eqp}{dvFFr=qV%{_SZJi8&5sIJ zU});)A1H~C>p4C(8UG9R)VT#WPUJ>4w`Ya-64d!W=Ag9)NU8$+c++c(I{ zFRq2EeoZ)vIA~(#GBPc-sy^pBmCn~&u(pBT2Qw+(><;P1gH-msor}O2*w*lbAAih) zXh?7fuYG+J<$@d10A=6SFv~~xl8l@f0rQ&aRS9C&To8uj=N+UL8yy~at6Zv{4950Q z^%FN}HxhU@?;00LRS+6SmH2CMz8;;g@Y0Y}tqh1Ijfq|_Q4U1xCNhp3vfOMLKom~2 zs?3KH91O1QJS{4RKcW|FD$_NckIz)+dd(eKL=e*&aYkFQX;XPj$?oa~v%Q=BItvnH;5?zWw`-4v$=UCW*bgY%tEJS- zeUBKtm(AZwlQ7^ah?+-_(4$=GT{tvmuUm56u+l}3aEo}=!?Ga9jkIZvi>UX~lv5Yh zsh@a1ThcS7K8Mv@UO6Lqol5hR_-7MqRZDAmG-AKj)>i{nsaAyz{UuJCq%2h7Dcmk} z2&oP>NKSj)+vqs8F+s_krBJun=Gz^+3}$S^^d-KD>$vgDi(tht%%%P7JRf$0)k{Z* zDAzw!UdJ6zbg5&9^3KE6*7Zd0s{(-#amTr5kjTf@O#Y;{x#p#MJ?SL^1BqHil2LX+ zQ3ncOIE@!~Os{v^*l2W>yrQQ>@2XRYiEl>`9G8m4>DE*VzjYuM`w`6KVeozD&^6P< zctOhZ4UC~Bgxp#%Uh%=ZMyl9c`7d-?Sg)hpEZH|gtRyg%ECSrSj}*|p(c44UH}KR9 zY{kv1`c3U3UW?LdQ=GY8_uwoD$n!pY@?H<#5maK&GdxQolx5v{yIY%IgMIrGx&a3_ zWs_4iPa-DWUhfOwEEi_kygsTkdf7?(o!(ny%2LlvZBVPzId-bxGw|qAu_9&1{0q#1 zA1@Kte3w?^D)87_iq^uPdfPqvuAi6I$Ow-ZKW0-VJe~G=nWN_v{|x!chWkN}_VB{! zpo&4C^@L+iMhB75%<)lkm^y>=$6z7CiQ7i6*j|YVD;PtMRFt_IHh7dp!NBv{n5+?* zKdj(zxiij(mFp27KDz)aI4_&xc~|#UaXUG;Xn=P;XOR>!6oWdQY8vk|z!qA-d4?^H z8-9quAt65uIRRzjbD$n=tryT7X#M`L9)f*pOJjcJ-q6lFm=ajQ|5hDsK z3yEMzzA z-s)y1Aq5G1tO}`|ja<$!xuNjJ5s2^JJ#TxSc24_txqpG?mekLL`QpmWTzQkKvTy6m z#Z*2%sHO}&SbRlUZHWwgffcF4UwE3s;9L^2Lh+)*9{g^iWE3J8wtVZHge|UFmtGs; zXu%xDP3`x4WiQC4w~TzPZnC>R@VJ9P`SffNWjVh|N$5M3h7ESPG2W38kqbfgX!>h~ z#<7{%!4w}7CMP*Ohjby1`bZla4s$a6NpgalFaP>KDD->i!9R#{4iJZBz!u7Xp;MI@ z6#*;4a$>W!A^IJ|Y>|yIMyNLg(RbBuv`%U}6}#UijfSUCP;tj$&CYqWAsREoR{ zQyPEEVJe5vS+PK`{$t2$=wj<*9?Q7MrwwTTQL_#YDmt7G2g3|EtG*W_PQ*af4#r3G z$|=HG13jN3=EYYw<77KKIVh~DmS^GR+lSgv?+LHf+}6g|W=nvxknq72)U||W-s#@i zR`nH}zi=;2yU-$w!%CdlM8QE47<%Tue>bx&+rI?t^JR?KxaZoq2w-e1Rz%9=AJ3j_ z1_?KNcZy|BD@_t2;;BDcSEPo(?RM)D2oY7n$?*I+gf9rR5qf-Z=}?OQWiUVYnoB4S^p(%~6(oJZc8a@B`?wRv! zj@07Dd`)YX&v!?Q6Qdc(skKK%XYdyZeQCmlpX7w$p^r z>w3)NLF4dpDCNa=!LiHtN)W))9Q=pG@jS+DkPLCz6GaonIv`sSGOez0`N1Xkex2Eu zK(y2_m^{ij1)fmXO^K)xe!bA!u&~i!@{13$EERYD*~)u?!*g|z56a5O?ee{VNZj_^ zKPvcgsUI_{9rUu9y!5=Ua)%YwwOl1M5oZ4ZnJw@vlsa}fULA}aThws~xcZb3nU|hT z;rnZvUz_!3oK&Xz0Ja) zfFos}ZO>968lKxyvpmyK_lqxO@iRaCCK06b311ttEy`$W?n2aEJg%9&O}*Rm*>AVU zUT3aUili zf(X%Ebe`kOd2v^E)s-Tx>9*l*=*@8y2bW!H`JI}_Lr1Ol`h|ZOBm9Kd1dNK`pgBpybsf zTSl8vu5?SI1hZ-3fA(}^h;;8hDCEYH;ZP!^AcR|jbpE7{ajPIOJ7G>~UjlV#EDZ6n zSxyZU>@-PxQK1?}Bwi}qMz)&VK$@n6#m#sN+w>MA4=`5m)b!~r9aOR<5vT(5o0)ng zL%*T&Jm0dbm(3a4DI?pJf48Wd$6ab39@Ests&(_m#fk@j-Tn@)Rr$iUJmIgtZx*V9 zdIjm{J^9;O0_BaKUo8K?Ka=jVFK_sG9vjoP_1MME$w_o1-9s{&Qrl+k&dERaZFyOX z#A*n%V|GDEEec%{ei7^zGr0C?yqT%jIG!cRue@-rtl~Rs+N&OL%Qr6@f7V!`J97^n zPc1hUDW2(y9v+02Tki;?PI&}3i16PbWF*eiUM8<4*zzVJXI??1CX3xP-*k~bdW}>Y zH;PW^1JW>34XK;5GFW50e#jYNq3M&}`qSs=)!8H60`23`{Mbcq4Tqobpl?}CGk;$pzEbVAi-kv|ueB94de zZNP19iFq|!{D|*|HVVe(x`C>SWIQuu)&r|@mxrczaq%u4Kp;eRS}M>P>#-v~r&7}V zS86 NSwTa-TGsN*{{nmy@fZLA literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/progress.gif b/cv/distiller/CWD/mmcv/docs/en/_static/progress.gif new file mode 100644 index 0000000000000000000000000000000000000000..f2a6208a84c31c09c6448e495fbd4ca769ce833e GIT binary patch literal 100747 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�`)&iH?wyTj{{0kXk4e+23>Zz%;0DOFd;4l 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

  • 2?l2DaFHz==2a zM2_oP>EIP2W42rISWd$-v_bFh0xc`Zd+>YtvD5z!69QwjU%fUaw9!-ty}ulS-$JC-hMFLq*^11Ka7n&b%oa}%^Wy>gp0&1yYV zP38AGpLUJ?XJ`%wNfOco6xhMBPg}D?@WTW{xIGPOO=F*N6JDe}Q*D9pj{Y2PV|`3v z{X}A&-D4H38n4D3$L6qwr+I~YVzZk!rNms1PQkC}Us|aVKdWz&M`Bh`e(r5pgTWN@NX|6@L`P&SpSDfexBu-1QiuaZ>p9`SRipCq43s1~t zwN~Wj7-gFS@~N23T=#ymRyPZy&e7)JOUZBx8;Kct%d^z-(QBrlboBfPx@(RTsxmmJ zAp8l>Sz`61z#mgreLb4KV%E+oV#_7TA;v$7RZuZsLi3^U?CF;9ej@S(Mz9CSj;dg3 zB(j7A{yZS3(XoQM6&wUSe{jV}-ahLQP_4iO%8VDZuHev(6Ks>ml=z4?R&a0tBQJAE zUConfCCYdNOZf-yt>Af7;`k?lRUBdtFD%MasfS8k~;Z&g)4eZnJhg{a3;72#7ziZ&%C_->J2F3d!H;uTnzT?XcRJ$5UCN@xq@f zL}8yFe!-tUZ7ncOV_RC~Y$OUMuR@K0B6MQu8g1cAg)kL}E|{htxe2Z*Va1+2-&z%b zR3MDR;fXlT$q~_GASS3&b$eCSu9Mjsq?u%=cA~^PzA7>U5%ODv_o3i|o!Ww3aFqj%SudD=mL(F$olUwTk)O#LvMo{o2mVF-M#2 z8{9eY-0yts!L#qR20ri%C>i%IefA1lJdENmyZ#xLjf0W^eb!=lUph0H%KX|pubhVP z+b{5(f?lV>rfE_-36K+e8g8SRkhM!VW3RT`!&Suj^Fn9>eIsm(acrwpFFcLxeu2;;Qk5J z7DO|I%OYuBt@kSm|B+D_eDCO|OWf~T0r(q%KGjR+-w&%z&I>I9h1b7{e!}yerPls9 zw2t(!bgF`zP?5o_$OA5o2pkt15Q+Y7TQp<#414zTDq>IBa-G%A&_Od*!Zz?j)r$~& zhwtfwmO_^u_&x!7id$UPGlegHzYwH$vHP>4d7z*f9Zb)MGIw7H>vqig?kJvlsBY6w zSQRAzS1?>oCpBTt4c$Grvk&9fz>8SnXSUkV9?2vx@ zx?|CGu1{_{Ol>asUC=s?1x7;`F%d3jp6ifu_#8&O^AQF?#Ty-h+sNkng~WzLlTL}! z@c8m@G0UYhqH-@N^_w6G04$jB+J`#VG3yb&hLPX_Nb>*|B>*?pq^A)L>9bF`YWrk! zcRBFv*|ag9ZaAhI1A5^WcRSthJM6CA6HuF50*_fbHK0qPl%k+;>j@jHDWc=d$2>aG zjL1&JK>sAtjz?pE07g>Dw0;1#fbLs_@w;cvUi$?0gHF5VplDCz+5&R7t%}fBIp^&a zPbxzM!$;J;$Gj61eGxw+*=i7}-K0APv5@4;DdMG!)}c0F*>MNtPCHL&mJX$ZLviey zbf)xpL@|}+T0Fuv9=`qom`8Idzy$Z*4*r&l@QO!J$>%Q6=Nvs$c2n$J<1=RP zLSkP3YM`B*I^-ge`$lBGR7mjyQxgJiGtVqtDp-dI2w%InuXc*j6^a$J1kpUWsUS)` zEPP(8*yEPt%cyo|f>Gqq6kl^xVWF@BJjB z`C1o!UGl4Z25%hvnLN9vf9}Xb`%m)zQ9ao!8*wBZ<4_bP$|w0}6Lc8_Jh9d|&n0yu zj7cS3!X!CS?U)XQc0b)*MVZZ#IW<$l91k%Mz}KjMwd2q4eLOFMv6iZoREfYUk`vIh zglFy~v7adkdmy&yM7sxQhlm?wX_I8QO$3!4j^*rK<&(vuaoD~Cu9O=QS<4Z=nAPQR;x=DQ8sj@YXcUMq zN|Z)QHn5}@=~*~rz3I)@D{*=?8E`?Y;C(Vft_l$P8B|7(ORx@%1^}7iBuEMz6scB! zBw6_rc-Il($S)6v0wZ|x5UH`!eK(xJ`YKM5TEFs3`bwG;gH9w_O2s+icnGEK)hWxT z;c+;my&nZuPyXaBb>I=!_vw7<8bw?=xKj(8PM5O!na({~klvT!RHdxfnc^y5x@VEY zg#$9n6yDLILIpH-jG`PWsh_u~yYPy}$cnlfW}hPN7{_Dg!zlmy;Ep(^!>#izYnP4^ za(<+coiFB&tlf_L1yAJH*l@plMc;=^h5g{MDWGTkOUwYUQkk^t!n7^WJ1#u0s-gty zm#cj9>vkldclihxr$cSO1XJ1kNa?Rj;mnnD@fG*S8^poS!=vu^32dh~-5=3znuuz8 z)Zg^@xM@MV`FT|Ha)0yNvr}uJQ?HD;yDw&w%Vns;ZC=)O zPN&;JM@uPB?39YwmEU5I7dtKv^aKdvhQ29<2tHu4dvNo2Pn=F~P*n$T$prDN_wP58 zq?>&u1ATXX_f_ch*WB!H80c^Q-QTV=(0y~DZ(v~P_rQqG;Ka?rN0+L%dIuKjG4*wb$Mt>jV1<{%%vv*Tye}B`!uL}eTBmD6r z70iWb-O)1shuf*8a)Uuv-;7E|kKN#_XzrIs_E+dLPEJPUW0pd3-vmA5o%JqUo=75mVf3St!AE!gJgU&0 zsfnIx7@TSTGt;g++Z{dIH#j@=XLdw)ZX%k&eVBXvXKq3F@$=}%%Y%>K{&{@IG{ct8 z}5E`jBG`Z?>66`XVvv^`V~>S_noIJO&_s=IO!ZUbhMi8#f?__78T*(Gu1r0Vh=y4Kj zIZa(qSQ0)vAhq#9KX$!PLtPAv>lwnf-M=}%4wibc36l)eWK3WbwMrnE5-SAPC|E^+ zs9ZR-I02Lm0$?uCPgC84&X(HV1}T!|lkBe|qVwWow|*vhXVAzEnqrmP;@2O1ctsS+ zZfEGUpEugx_X*H>D`AZLpF0`Bnn^x6P>ps^=aZ;FkBcLZ&8#+qurGAfk648x&Zsac ztYu<_j@{HZ(i>P-uWtiI-0^x1Z(oPx3wz=flZXdjS4CE^JYCwFqxD$$HTGi6v-=m= zLU93SiR=$eYT(!E&%i`{@RfXG{`r`I2jrUT3=Ev5?t{*pj}O0meHU11S{pGBTgQoT zSNgS6AsrungxqRL#Y7^E*@`iM!#;S>jl7OkflQqD#JxXZFFuC|d`YmE*TOYw0${cg z{=MQ~{ApiH$ejNkVnrTS04vAh1qrEqx~Y^@3ML|XD~}h!E+S)g85N)0Xe;HpMlVL^ zPQ2~5DD-?>d9*fn*7g+Z=h>4QgGVe9yDbils{W3gk_gU5`o2WHwWeqKp~bXVCJ(>} zIjI_4odCjG#sN%6+$J+6P1Ct-#A-%)q=1H7vhTRnpcIz$MCYmv5vKWWw8G znnxnH$4{mxIcD+w5%v4@l1C)&*ul$=YNd zLD70QRNYm=0?mtiD7J!bUb@ne9i2nQY;e3YN zLC6&Pq2vY_0G|kjAcaV{F}zv<@Ex;S^d27NDjbC8Q+qf60neEl{}kgREK!62%ws%V zjZscx5tRrd#|YQkKjVa?AT$sQJd`ZS5>}0(c>@3Jje8mB@^2KtlhmCp+?O#toB*Hp zaVTC|!a#J>U^+h_P0`P&>XoILZ_RDjbl=+2>odM}cVn3wNw0%G-pK=SsnXcLI^l`Lh(xe2T)h5g}5Ix9oJ`ToRG0IXw(toPA^~Y{jP_qfocIM6! z9>#AVU2)>3J+}l#@_X+4ELJ%Qaabiqh8D|FH9^xy6J-vV9jS#0{) z<-nGX8x+XUVf^fi-Y(lLHWh);E3q?3b1H}BkP?edn?$9t=+<5)m@O8gpL1?6n#0cQ z6E(zAudEo~@^*T!O5?rXS1AKFJNmu>uZwP+vB34mK07wXpCa__UL$F76Tt<V)2E=stHcBA00<7z|NbDgsCRz}=j{pYe z*G|!D$)7;>`~cQGs&WnOsRtKB=PIp(K&x>oT(9&Wvw|mIv$m%WMDm}X@vOm|NROn2 z$xi#z$ZQu-Uoe50AB0|}OzG|frI#H9BP0kK-sK=Jw2)SPQRAa5FzYBfo# zx9gy={cyb}VxGwm-pMfvF|Q%cklax>HZ@$DY) zZx!RFJ)bBWTEQAn%LbzY{z(%77ExEQ8!yW|@6OBdz5>Tg8maRE=1(v<=>!~{qntN0 zUZi4PUzj1xalWb)PAkTrnpS?Gl}be|>?Mln?q^?jw9@}gf+FLI@X&Qao$hxT>m+CB zm49Y%TT<4=$~rA^8nKeA2FT(^8GvFiH{?)xya1SuXfYj@VoUgJOCA6eq@0pjHI_}p zH1t|4q@^u^Sz!PGf@o20JLu!uPv%Z_zou#|JvIyj*sv|7wRpG5x!&oR1Y+nwW@{Sj zSwN9!F{ar+fPfE1LEK0m*#7Cj{TyarC(nfUbTu~z1e!Mp)UPthM9{$57ezAizEQs2 zd~TzNV?KVxl;1BSbIUbhIw6(JG)gr-w-cAjazN+%cG7FC$~VGx_YQ{TvCov=77&TI zuV6L^oAAdlGyq-q!418@sFymzpA#qDH{IeyACK_sWfhv!^bvvUvQ65IzcE zhF!zV3p;`wRpD&?m~0pNPs};C14>ZFx`bThBa6GA{oQS!$5Wwhjsb_SK+kDeN54YqnhVoVZvYf_0K}|SaWCv;4q9ZQV zbOk0_GDd#AL60a#A_7JM{-SSQu6*fvFpT_SYC581TkKMjLF5rnEYmh@OO%u zu^isL7MinhJwmRIrIV)bj~)%Y)q0Z-Io&(L9$TPj_$skfXH*CMP6)k8#J{n6f|kYs zm*9w3XZMt>c6f5LXeIFarpo*rCf z&p8^Gi`~x*9Q+{4{%hJi_Mo73aN~5&ulk~H;8hpk$63EGRe=w`-D4Vxm2xoucm(-s_Uw<9-nhjp=YKDcy%Uk!(aUf&`1XS3)={qm=uCFbpY<`$?aA{Gzd6BU zc;1yAEw#q#XV9ZRKE)hqPsRSoJ!#r9e}BAwzVy1?9{4>-<8VATjLGkBDT{O^_hH?M z%%nB+?l_U1@64NHgL$StQoz!J>oafbcPS^)HAds38nGM3@djfcQ-BkD8-U^<@+enCSP39$Enzrs^WFQ_(G(}ctWBJZ z-L!+KNU}#$;>L103^zo(4Z)A5Se*CbkgpO9s2~$Ev=$e~{5=6ImN;XR_(d(oG$NXL zD|+=*Jj^lvs-}$Y!dc4&N!MfnQJMiQNKK1mmU$?WWex2OP5FVf{WJv<*c6negElIJ zU4o$=WRNr_mF*%p$%jh|m8weQW~l^8P!+A~LCY$*d=t>1HJcRxqNW7%AfhC2AXuE_ z@}ij{icgKA(7&3xflj+Pf8yGTPhVRUl%;|sZ7(!OpsIb+<>u1~WRUEhRdK3xH5_7v z;;Yb1uQ7qtnZR1(GUD7aTa_~>wjergS>q;PPf8Yinl+OKee@DA9syZ$7&zG?;^y`oXVLf&hD+xcw4U!AO(3go#Xk6vvfM`EB@#Dzxg1AHU(be(bFw0F*>D)w5AA zNkkdaOh-mwJ5<)gHe|;<+x8yfVjE2RQT|y(!SQWy6%F}QiTyPhZcGF3ShH5blU`Ag zqB=QCZnp%knTt-&Svr`x!-s!e? z$?Y3^0@uhIKdHzRgim&)>mG_Ff4TS-rS$%G($q(AEhQR7WIn{P_>>?idx4y7+1#(P zs{rDXrr+$QqhwX zgcnU4av-2b$1a9*u`Hn2(P++gO?@2OS8HTq8*GdMlO>_~+tI>qFv+M&nf^+{X%0mo zC)@y6Y0bXh28*DvBufQo&s3dduI8MF9aE4cbi^tRDWVLFp|L-wAUc)UwgAjd{Z)F$ zRlYd$U2C=y3gVFxTgn~`gXNHLp4hn@u zbGf1UD$qi!=mh5aQ&>*fh3eA_8mexbn#!zx`O!5PrhY*DPp#zNrp-l*_ugZr)+?f9 zeJ{goK;^`QArgxRom#YhtE*G=FWNO~Fx#Z32Vka>o+LSQTJ5Z!pG)Lgu5NMDvh3WCl7EcFR5$E8S);C*s&jWyOkd zVp5}|9xUcRa*ux_cZZKA3qrJlWsllrM(eV=Da5M7_#$nC6a7}P-*w|h5#2UeU# z%w9*#z*@`_b8nCaNso$Nl#Tu6)O_cr&`UpA;ZE5JhjU$3Olj6ITpQw017WpC9(2F% zp&r96fL+G0o+2Vz^as3%1HA)Ee(mh}RJnNv$g@SZE;87Tf_#ZX4=c-01dC`hvxc;p zJnE2td?4RVhSB5($(!774-{5a6d$62mAJToS|AIT>Z17&lN(UzSR1p4TvB4HT1Wbz zEYm^Exweo`_XVp$ku#293Cam8tE$5DV1*q*?~=R1t4f7-CuRg7erl@zqa0*=7m4TW zp=tHljOux3z?fEO%b@nb3gF%@_klUm$GRc%;7pVC@Cy{}>kF6lb3xHr;qKqc)^Y;774kq?~pam zTuqVdR?gRtK>c85Vt8d)^ap(9S^dkI4$>|4Y&53YkajefoXzOy0kiKne(jkv@DcUv zV2$9hGr>X#y;TjexaO@s!3}dGL>DfS#z_`Zg}Ds_Yk==D$Pg6hTLz3&F-#JeX4-%B zeV+Z%FL};O8aMJ!G+vtaCV!iW?i`=PAo!F<=4joyO*n=NCr`HLzJ8BrQ$us6Mj9t4 z*mF3L$W^xTNa1qNCbglieCDifyH~kVjKw4WXX=5R8d_K9I#)Ej_cY?pXeNbdq=wun z^at6Xnyuw0?B$;hE!-PTGH_mL?)qTiFfU2WWbW&byD6<7`${mN961b_f@RGYv?+<< z+D3PC;1$w|N-V!Hl1xAhpKZ&158Rtf6oV~Ua}71Lf-~I1>3*0W`OW>L7R%p-7e2&G zna8=h0bkIOp+po$VbOr{@TENDp2cw4W#rOt>EHL&wPPOX20Y7cgEf}IBLDVMWFKKA~Oydqu{*Hv_Z=*$_nTvXOhoJ>T1@0_zDFpC%JQMa~c8TFN zi2^(i<%hTgd#=A(fEz5bLGV771l~}X;$ytXI@LAqxd$bB9K%#R%UUWJv#gEV>nqisX7$x(O$MuA`QLp_04SZ|iSwm-*h zug|@UD@6K|AQt6-K}z)HOYEPCE4gR4&)&`-q`=bvcE5N2OE)LJ(0Ojx!R9cP3}%o{ z%ie7t?2HJrjcQSMn!fCKS#e|9*>_PNm5e_se799rvr`MR(}I4sQrrF1jWw>>vf%!F zz7TdGlg+>V0mrsCT5)NxCbrn~=?0gJ#XCdB+vkyh$o^AvVW=lHEe}^;2hPn$Qa0NE z3LvQke<^H__u#LCPsLcXuaSJ1aybG;KEjnSq+tkbjlf zAJgGw{de~yuUMC&HgwqQF>F8Qk@?oC2Ik)kYC*9y)}OQ!1`e5NHwk=t9$`L=tf1F^ z%R*^Vz>YMQ$BS%}N(YBmUAJmn9cVv(NW%N`q7QxP4BV*Y$)SO@Mka>sWlc%U*YB;> z4H%m%*WbSk)&1^p>$}qx=xf&=jKvSHoF9JYVSb$l40!o3CZW@TF0X1_G)`Pr)tG{E zjt;LU5^#s#3|#|mUFmxlmr4J6#J|@qdMyIVQ=ooTO)I8D9pLoBM`aOW`$X1tGQr(w zaHQR*7TRvy;e$MA2ur@`x_T|l3!`U)QZ7MxUFdl7OTbUc3kLFrE@)xbxk7)KT7%%V z+|l3pICaqwtv##k`a{Vj!I*HfJI}cOISNL=PzD7jaIDEV1}!khrNSa*Ty!Q0W3URA z*rSh#88mXqh*hUi#Ec6Qw@V-|E?wt7`^Zrn$YR@S_A$FtQ>OfoWQhXYD z-RBtwkHwcp>!#+_%+z7<%yY#H4I_mJ?jNI6f9#o%lksffGMg=@F5l-ZSKqw&e5p5R z<4Mh>mtR~4Bfo#yc=Ph>``hw^)h5`F`jkqTcTXm^PCrFZ_3nWs;+4uFKBM8fGtvybg8f{P)e-&9TGt@urmP%2Ckzqr%hP z?^b?Yk}=9Osi@#t4;6pfJ%Hp$oMaYQozUs4JaNA;pkKHVWpw+C>wp`nnrb!Vj6Lnj zB3N8{!`tKimxr8zgL3kV<_MY4*V(mixl}gpzmMmyH{u!W6d~0~|aTCV1Q~e=-<~ zg>c9tX5E9$Wbbz!n8|mpWSmvV5wDk!EbVoZsXdl8!HfD9yCuWCq$}by-u#*GIBm|6 zZ=pC4YTm8(KC?4U-M7u=Jb^{+(At30A=Jhwjczh84pA6QHDLpHZx z*5?khw>4LDSf~u0`DXtyR6s`gf=6N41xaWB?(Y{ahdd9v=z8<}_lv{??r=x<47DGQ zp7{>pPF`hU;Unb#OLEvtuqhA-V7P1H5QYm8^1ma+I)F_87hoCV!3lun{~=OL%5%TM zV~Shty7Yp{|B4i|t)Z~5d_j0jeHqIVRQR8fV!VOjLQ}aDmel_dDMrA`U5_?-xer5@ zTXp)qo$2;Bz!Dg#DCy7dFL(MpV_e{fJC3=8rI|bC4-^f>Y$uEY+#j^Q9}eH|f6LO_ zwmN17<#fR+DXvXX#P4%i6t;6r<(=_=$7-|xM#|t-u!v>9>c-Ow^ZTyCzjm0~jRLt4 z3Z>nj--M(s`ItZ7M8570ViA4#{i^281)o^B3`BGP<9xnZ!0v*^9(|$H|3>6Duj#Uv zc7Z3N=kH3q`Z7G0ar)`Q7=!P7Z)fk_Lp_W-KKjPe_4V@btzUndf4(QLL!~isaDq1` z9HE|C7RP2}A{74D)Mqv1nsUTyvQYTeY6>P_+w|cm2qzS)HcrJFQ2KpcSHXC_QZoGD^)J#H!)8)RrN!j zT$o*CRh771tVDvMKS+#H$c(Jq-L^cWMPQ#>wUCWM~gxsn(($sI7a?;`494?#lbm99_oI%KLC zGFI;YiopB7UC94`JorzsIR3vW7KzdJD&wsGoxi6ab=g$nf9CJmiOuGy{h!5hK3+rT zpU{8v_mBxa2LH|9Q%NBFCx6c&Ril+rEMa~xT8Lxm&t<}z7{y|E+j6$2`BL(g_cM2X zt1G@8h!~N5Jo_NkR-McT_JZA4&4)lC}(;Kq;?(x8bukUFIETUF}z55@g^X0BQ8SMM^ zalXp@p4CwQ_uW^W{_md*4gCB{AIo4A%frE6-?pCJzw-3q(C?pnA7<~JAAb1v_tCfA z_fLn1Pfh?ZX*wCg<3o>wOV!ikS=G1b3IEOCWIqfstp!of7vhnesb|QT5actMyFWy#puN>MHmC9YTYc^s!$} z^AlN{rs~(s=$4ipKUC{O!jgX*(*nr=sK%u%-wu@-Y5IS+asdDc01VduZ>rs&IlwhDbQ6jnXcWV~V`0~uto-D94{k;x-tD{qaKFwGUSB(RFrICaTd7MMWz z|AXX_;ZNVnm&>7~vZ@6i9-$_opcKMhQD)_3`)!8Ct^Dm!dAdM5%1|^kT zIvo-wRovq7e@)gQ9dXAbv#uSET8mECI|7nAKjd?}qo>xU7mQc*ZnaNK%XIL5o-2{jB`_F*!IW&xvIS7GF5y_UpCv-Stj&1CjJRkA+~1kyRs?{ z`cQ*q7^;Leqw=!-UNc9{tlVreUJlVMs=-eP|~bqF!4 z7S9m3QD*g*l3klGzD;EfkjA9_cMCqPj!iV$74k6PHl(KJGUJ5WN0~h-`}rtBJ(U1d zRT_U4j#{0cu)d~Tkieok4}hR9UdBuOCmT_plF7gPAqO9R)su46fRfOcpwLiAT%PhP zW@%0QWH2jwSqf#5%OTtQ$Xp8wumMvo&oOMexOV_J{wH zs+@s8zObwi<}pO#<4G!LdWXNrg7->$}mOK$xrfcQcv zBKXVb8&$R$=~Xvb>z6=3Mad5ubRqm0<4TF3LRFz41Ektz<;jMBrH!A;f;hIn46kee zVPA)zv3e|!!WNh)MM^NGZ!HBSeP{gE;wG(X6W(?>}+(Gy!O*L^!0 zKE(SgW}2L8R`oZ4?~ih+iC`xzFbzuP+MQh?=e4rAa;s3+F#6|#uS17CJ#Gzs%vG*L%65-2L3q|KxG^OWjQI$72Td2W$Qly@QnzqV~yQ zeioMly!k&7i)YNvQ6Sp&vaeRaPfv;Lqn@1GI(n9)_ZOp*Y=OAo=li2YP<_CFL9rDVKgg0g0c zhOXz6sOFn4pF+LPVce~JFb4N}lYMaFil4Jcnc_yNREU6Z6|0J0c8GyZPDB%seUM?e z*uuoiZ&d+Gq;V>fL8%&pPo)VIf+R?n@njRw`GRRtyWb^?3(b#UnqEY=AJ#WF+k3S$^-nWtPDENrzFJa*7B{)tlsHzM zh^dtY&oy7qf6-Of3>GltqnO$|v0K>VnH@1qO0Eqo5%BnIM?PaltR6a91lxOK1Sq(; zpCQj^E_z|W^7|tx7|00wR;r=wFQ3cnvOfzeEDSA-@Y%-m6>|N$#v+hVh?sC4|B=3z z%DWLJ?(&b3`V)zf3%?NoFgMWBBYkx24c=XMjXT-xN;(hTyp@aA81$B$(qbmpiPLOF zp{xB$k4Y$IS~7?NdYad5nD=yG9kp9DEZ=Ox{%}9-KgNjobYqdpORj|bMXi>b zU(@U?ythk%vKM>ymC={HEXw(XeZ96=UbW?%^C((0dl+hZMz~8{{y%NRP?2D2ygU>S z562lN@H4xao`%G+P8?+A$ZwfdT^vH34J*B2{@KqXH9LG4 z*BmiNnj~v5lhj$kp`!V{in)Weas6h!@a}4uK)+sUV9HH4dAyNoc|n%H3D&0*HYpU! ziC(m?=w^`B6Md9K8kff37y=Ts?3I~P4d~pHlY4g8G@5Qq{q~nTu{;_TBwP>K&4BDY z(H~!+h#R$~D{8nbPU*jsP|r-@ze59;YTMtdTDmmsI;$bTS81NKyA{sV7;H+4_4oxn zT>qwsn|*4T5SsB@D`Bs6(n*;~s3}ee*E%-;;I3lpQy}qbyEV|21dFL2#qzY>SRAeh zOjV6pwS1IzNw6I0R!-yi1u%G*n;rP@w9AJ0>*HCEv#%B|Z%kG{Ondbh|D$F8?H4_H z+S=FV&|0}08?5|;{LHtG#_!Xi74*sd`TZPc-G3i+zGNo19PCX9-8sx=`n{h2aCF;FAx%O7Q?3! z6SzJym`P+3lvQT8%8Yu^U7Qf)w}RZ{963Ioyv}XRG+Go?o&pp3$=vtyx`j$`At?4Y z3h~%G>X!!RipUT2!7vHv6C`X2~d;$t%_ zfFFN`AJyH8igSZv!uI#C9D&jC9C5rsamx>4PN-MnLBa+~;XdP?}Eq# z8p@)c)2TO!q4;jpg{h_b2EIah`Xm>SlTRzLd;+kfolu!#$ZSbI@uwXDCu;Gc*o64h zSYllYQ$#eCFWuY5*cyx+)=znIiaBUijb|?<6cxk}hySDRl9`qd$nIFsMc&JAE)|=s{!Q6ap?_{wN2QTCSqqA)h3ZN#v&Bi+T0=yO*drYQ zF*MZgN#mQQkeCJ%LYi%x8pySlEUXc>8WH)|2iQ=^WQ&2`Cli<9Xp&Q2?^NcyATF)> z|ESBp6s;vgp_B&pG++JPC4K5P3JoZZoVT^KhSqLpHU84wbn}qlD>JfzD2>6l=x{IV zNW%rLoDxBTl1Ptnobic_=m5VRkQ;FhEviN0?)$|#^s6j$yLeKjnCT*v__5T^6#YE% zPJ?H;<(XndndEFND8`ZFt#8&Q>aIp_zD!W+Cf$Jlmt4CC{+4UtFr4o}CNUCJ+jpbRbSRhAA`&9&L zRfcF)Po@OSq!>ryFaIxrnzj~#tAkfCpT+U94Z|L_Vlauab~+gQK*`! zvGXt2hCu7Zn~y)%prFqwtND%Uq0BcA7Ees%+bQI>}`jwUyp@q>YU*J^gm4 zjxO7R7btT0Ke)OJwyBoxTh@gN-i3&Ix zB?JUSF-8drC@NsPv+whJ&iP%}`6IS#yFd5+ej(!d(Vfo(+F8-}TFn^GCZ*U`P~SY` zO&3&;MV4fx4qCDo(dApcDYp_o-Xd8-S@+t&kD6b~Hila?nVt=eM!4ZCbH0(7GZxrN ziA>ZIuxqE$cMNjk5T0}IuF6XXBP{6uo1VAjfd6Mo{@;+idbHX4caQzqR{Wvn8j7vd z(uSqx)(`v_7* zH~1dK0-Z``8X)Q)6!k`=fEx&W3>S312{c4x=jZC5TI??rd{CMIIzP{P!T3M$kNuX} zqinEzQD5*{-*#N;TD6VUf(>K*ULtskY5qR=%l&_t{#-<#*V#V5J&4GyY`E-zzkuND0K#FFu|+9mH1?ubh(=5C>v#rIVa&UtF>ZSRRxp zobKGaPx{TC^7}DRpX!7v!T*jkOBju4f~a?)-DG$aAh-a=$le*;!>oftU{5eTCyV3w+WLlC3xL zbhvkF1Q@MZt}qKj&v-tG6yurB<((Fjz%NYP3sLq2awjW7Nc-Fbp;;5vr*>p4#{S84 z2*>!qQ_*`4lmVerBNHCq(2Fypp);tKx>?>k4ftwq7=F~~`PtUIp0)xPf2i@D#g#cAjqmRU`9_a;ub1l#N!k1+q|#07!DIp^n$ z&)u`e)dkTvV$R;D8Y1u2+t*GV>K>@F5<9CHBeO+Vk6<&-MR4 z#|kf*CP=S~SK{+?Oh;6`F}-bK1(GxwtSZ!G*1_nnsjmC7YtnPWYs+qLmOcJ1Prk^N zwdNqWulOa6S|qLn4X%W|Sqb~QLKJ=xVeleKiQm)#kn8}^qCrSrlEe+En8s1z8t{3J zcrybtmjixf3W)esBhHH>`9MaKAQP5o#8$k-CUIN$&HUSSZm$uLH}Pu48}ZCp%I~_> znt^4ed1;?R)uP$elED`w_0{yGPVF}@TY(zs1_GPr;FR{~x07(4Y^ynBqKMI|3t=@# zeK|Z$-f2V1$xFVUEw$yEIF2UkIc%p)0%>B^CFourtL{E5?J^Tx(uxtQF|(^O=U(tN zf@(T(f@KDJr+U6VPCX+ zc`a1`2*VaQf2lTUZ8_;>`aJsq307;ltSpWN%<=qU5#gVkjNgKNJVbP~(+&^VzqY^o zb4~GG=0o+BI3+W=8&7xeIug;I~al~(k=;8UAntlc?#hTa`nC-y>_-=x#}JT@;1Dd9qd zRFCc)nu6H^+1{ETu*B`^G_(aCaH~)d9|%{^FJ79+M}L-vztB3YtLGF~WgchJ=phBY ze86bg>wO;2!&1_r80AoA>M%p3(YgbIBZ6b1BpQ^CENnmV<8ZhyAYTAPEw!IQd-YOn?~XQm zQ<0>>-Ot9S`Ny=Ciun)uzJgf8Sv9x!(Xvct03a9&2bjb1?CVbZ8I*(jOBH1QP!Vgy zcN0!`1Mc+g{wC(xGKXylsU3CNE@vM!c zGXdF6V*Nse{dMB}L;6|tE}>vu-nDb_dl6eS>ea)-pKrb0PRAkg=|5`dMEN4735wQ- z!$%d*{tVFnI2{Jd(Ekq`d-&jn!k;nGS7UpzPNf86zE zFJ<|&b?MKfBLtw9CUo2L!>1?bZh*4Y!@uw1&S^B~6k%joL-#5>swFh_NB;hP@vMF@ zK5K%js^rt9!4QYrC^686pq8dlmaA)wGJAoLYZ3p9vsq(_I8&a8mca1hkhwzv*8Bu% zmsK5=gUY6y^$;nF>Y4 z3XsXN==lPa61Mz;NbULiHYlw^=SQG7(%gKb&t>cyoU%X}ftu!(p-efl{?GbtdG9pU|5tTRvPj8fp@#^5>C3*=CzzmzI@#s#>L#q)Pyj5cq-ynaE@Awka-Oj-HZTzxFwRX zTP&R~5i-(F`WyAJ5ssQ_@GDsM+DEINq@hMQBH`60*UcTl_IM8KM1+aZDqm);4c8NB z{pxL@djLgTnw=5zoj5YeTi?E^H014tWQ9VrrCTB!QG4D)o3!$2R1fN=Y$Y8X9c)#$qeNr4HRK9YqNa5C#b=d9k3 zowGIk3n|M3bGq5J%(RS(*M@WiG`6&DJON9SBdWdUl`RZT$()fo+57w$kjvLe zb;lhq4{OS_p)y%CUU!bNt02P1IP%3CbtQqE8%!ew#UM5MS0El9hNuH~fu1ga3%!xi zee({Jx*R=@zT-s`m7>>K-9 z>we;j-8q)k4#tf8N+&JVJ5?os@!Ie(;D(3p$E-vayW1jGc~q~;geJ93db-9(X7Mb$ zMYZgwE`1K-SynH7(=)_>smd(EJ%ES$J;BwZ50bF08zB+m`S#%8LphmJ%T75OTGK14 zp~zGH$rxWu4cR+ypnbu#D7vfRY3*>a4~MkXrq)OO+3yz$+e4nNujj=Fh&i`CxFbs` zeDonp?M@<6&L{^+M*JvQK5(uL>He*nQ_yCQB|`=FRn5v@$Hp2gg1V@g0unU=;#tyV zMSqJxAq>BOt)v)MB;7=l3f1sZ#3B-2=$QsCZ8g`%-pO%IxFbI1ccJoS@Z%)pP=;!z zO%1haA2Q4|e%j+JV?9=JH&x(6Y07by(c`<@>&aCkj;M(Fyo#lEI$V4n-z(dtRqAs& z;V)P?vgV|x#kxJnMZ#pod`gx1sYKEbustKRqJ65ZJ@j#;9#h@Og*(~vk%P65FRVZpiXt5~&(#S6Fm4!PV{_|$? z0Yu0gH$aqxDd+-KWdbwQ4D|j8v-eIJygrcfe;bH=)|O?WEHGPKnASA!;7XEcDh#YZ zWuN)uS?EnABU7JDXg$O*`DuEycC~tn7^aq=jk*;>P=zV%9!hBXn5l&aZ(}+@XPu}> zllZkv%!nUT6u{U)R(zAYfC3U4fO2#N-ngV`2MB%LAT&wGj_4?6HXTF{*Sfc?**6_p z6D<`CbX`+*3)HG2qKuX1!hL~pAI`qsofYKaGJ;gBvz^K^@yFAoo=5zA3hHbG;EG0M z`*DQ{6tFNc^_DWQM*kES26f!YQ>yA~oA|Nx`bnDwY97k0kyV`kQ6kS%RcbzNPD73x zpI6ux{%k+442egZiy5cdrK@uZ(_6*`@x+BZX3t1ha^NWHRbD{#|a%wfkE#w@^>*FL0M1Pp1Z!sN2a=9V&WywylUiZ7WT`WvShEv9$H( zvg=DLYu3+}JzUWH?~o{x8f4h}&{FE!PV35pemJdFa0 zwvy0R;sh3-_C>wBT5KxlVAlyQ9Qa+4>FfP0bJe0$?#eqmnl%ZK+gyMFONUt}M+s=8 zYOqTFUwe@zOjGs1x_N=Ys4cyiUAIc(F=k!G#VO9-k#872$u}txABWg|`ux$36w)bZ zt1uzJL69X`$?Dzt2Gp-<@@9(s?(!y$UK6|dKn@_YDs49p$Gnf5h> z{~RIJ&@H@N+~vpAx7wAkgx?n#EOP(2L0Clf#Oof*=}D8KPsyJ?+}-oLKdSIAY~Wu6 zm*hcJ_KqiqL{_ldmVgNt698}TQ=6&&%vDP^A|%{{nvv8$0xutr(%h4UpoyorYuyW< z(wxs9zdrx4+^{?7LhaOP%bJI!1EC$!2lW;r>+wgU&(KR>Ic7M>^4)xVFkOWVMYJ=XJ2)B=3_U4 zrXJe4`SouERN43L%323Y)~&P2fX)AEIcT{3RFU<)es|LJ5XN%8e9`E?D9_=bEADAz zQM0F-2a~If9!eZ$-TgblPEIv?8c!$@owv_A-|vk|RDLkWJNNAjG-36c#)(c*`~I@3 zQfu(dD?PW=LYG}nkCQ~)9wG8y9DnJLG}4Xfs&og~?|LVw{|#8Nor|1SPWq%WWu)hz zCU=zmOZH>xX6s&+y7&*Fu>FkluNI2F4SNguzsC7E{4#{g0seJAGEMqeU7CtvHCq+E zV0rH8T%|-7m1iRWrZqPia&d~D%AVQqwwoN1kl3=G>`<7_FY7^k&9x3;S~U}XA6(`& zUkg7GXOda!;^l3jF=L51Wby*LdDXDy>I=iYEKG{Mt`dxi!gN|_Saq~};ZjtHMxpA( zG|Ts*a`|k);H*rG-FEDJvkqzqmdhC8rAN@fwL~B<2CUw%jk!1kTPqwVNS~wiv;65$ zvdFyDpQ4aOMfhN0`h^@;dhS>rUMdhNDQEYaWkoP=L^tKdS?XuYoVULXq$u^AiCA&F z;rWLHLsL}!RcrwmhaLbm1+a=hhJcHd=3MBrLssz??O;-R=ppp?g~!lDD#&iwId||U z^Zi$k24AlY#+_HDzsnsF!h<(7hA>#e?MG>#tp1e9M!Bh>gYG+}w{hk2%!)k*ub&%i zZ&aUC0BixF8UQ1B8CIPpJ)?l^BZ6dfZ(HDt9oAq^B$STqv?v+_Gn*Z-1iV__*ezyA zGAd25NkrZOZ>ss&VBh$e-QdNZc8n|7dOq#SZidZN+9`y#b_xO=kQ$GLF@4KDScMU= z5QCx=X;Qza#<=!;X2=x876l9I2SXAc6<)+j(onXCkT8sh8(6@ z!kOs4Q|SsM-TrS_&BF%sDv&iM6Zyv!(}1X{^={LU zCDX7Y)57PY*5}NQN9!I=SK^w^# znRoGB1!TY5g_X{;B{PzHVoFt=l@U`=;@8}TL#F7?%w%fb_CV?&1`@pr(IAuOF!lgkA&t4CAwH>Jf+!dlO?ht6B*bjbeK+Lq-FzP=SkqJKdrPGlImemmv`z9 zD_CHEsvzHkn|m`V@>5h4$ki^hk2k<4d#E_u)mXssO6n3Wt z_F1wrjVY629v$$6hspMfVv3NRY^EI)-=Feb(w?rrkc|Ra!!wgtp|1Uz{u?txvU8h9 znOk@+wgVgX!G&*~Hv46Zz?@W!mOWQ`HcOy|%2Rv3a(i3K!qF3Zdb&Iy-Yx^w4^rMs z*_*N1K1xqG)Uhsss<%uU?PkWbpq2oO9KsIAu5<5~&RExiJ~Yi;t2w9SWFvn(r@#&R zs`>1bBS_HqS!Qv;kqwAewd47j^xETf0*%H(=(?3O+S(TyKu7eTNxy3(Y&+@>@ zl=MBExc#?WrPf^FFZ}y{X0>wb6?_iz?>vs%fr~p|TsTwq+8GA7=u*yeNo$@cFc%^v zz-=og~bGPRHcrPZ@*En zE_Lh0;*)6LhsUqS(qHv%FFz2R$`zhf$wAi>8NYu_X7$BW`lM1V)EwtS&-Wy~8Xr8( zVMp#VkUAu}ztoa><0~9G{(FAm6H6xJ*c1zIz>cl{R1d9I}zaAf;Ib6D7 zez#K19pO|+aA!|_bo!|L(v5rXzQf<%z+Rf)5Q^EmbYiYDUo$_4s44d<_{Y7l4kygy z(2fbTM;t59SKpa+T}lUB`Xcr2SzsZpeHp@2!}^|fD17NcZclO2r6J7vgK65oP)}Gr zO{#U>{SM)eSat8r z^AUXJE`-MTdvOJ%)ldH{x64HK(j%33i0|FAGwf2JyE@G~3_v)_@7+$1e^SNn1C2MN zg83{{>-3DBi_HN=zJbTs7J5JJj^+O-rHiLLX z_WDGE%lrcF+XOsl4sPfOeqi{%EM~9eWTtZ>=(geB&6Qn3`))-{VDZr2eZ&2pPrKtH ze%I!LDtY$DnuCYxKelP>KCR!oRv*&8vfu0H--`Tbb#cGGBd}h1FaE9nU7paf`hgMc zkmR}DlDVFTetXM)2Rw5Jwoo!@Qz^{bNgSM4-QWDCu8(?PY!aGKha_iz8St5M4o?X z>i47K^d0G-?U=A7>8Xz$myg4OzKVpMtQ_puhgQ}5fAkCaPQ5f(9}I=wK9{XE%1@3+L5Pis|LE&SB^w#m{q}0k;0Hlnd6jzns{7<`E6& zsSJ_iCCc9YOjrKGdiC-{^)%wRE{ z$mx@y$)Lmj`(b6*8_zHWOE(}mB&zkgL!`D*MRHQ*7>5&QA4De?Wu z=h_TE5bW5U`&*37_6KArrZUvv9kHxAitT=cmGse}$4BRPk-wlvTI|P$yhj&0B9$H= zDS!TAegA-C@~CkoY8@H%?}RA9ek|mFButO|X&AlVLDaew{e1e})kspAhRK*kn%JFMpzb`W9~+Gg(XIyBm{i7F3J;{`*>l z`6a(C>HV0`-%nrnY;=y*;SGT_$IzKwHlob7vs~gtl?l1G4)fUqF3R}W?Zov?d@C~B z43+s=YW7pN`G;OiWU1{>=3Cz@b%@ose%APJy6kMp#9XP}@vr~>^E&Joh4)v3%&$hB zUpLHtH5K|~Gck7INw;7maSHHTGmRJ-z6Gbfm(n>Jy&w;ErtS} z?!L?9^#jsiki)kMramUeYY23k{pMaphqeRtT~qj5B){8{b+f=+tM3MG|CVtD&g}et zk@9)@?t|m7Q{m!uU!K2 z{P=gW`}bYtrH#uFSwPmgc4<912O6PRf|)Q+Y1qPyWpT)uI!2I3&;ndK5&NrXY6TZ_ z8vF}Q2Re-T&}SW}ae{$)OZMpTjjXCu=HRK}{6{&%cRjvu_?v9nf&*bIYZG zK};+>tNr~IG= zC>d7)%|%8isMZ%3m>g>}6M!2Fq=8eFRE-h15J`yT?KkhK9x52mjR54r$pvVq9>5f= z+_{jFcRH_#7Q68CheQ#MSx>UqMBvI&lWb986l0c`DC11bPXK^SH|Ynk){!MS*c{xPt56luohATlxaSy~r7VtO z9(K%!w$P#U7=v`U?C{quX{sh6i3r>p3ge>+vUJlVV7X4i0YJ!Iwgs%K*~4G*ZTFs@ zQfTkBEc1zWNMCod0RQQHVJw{PB6VZ?TDfmLlVVh=sfP&TQp7vP@jbXp?sqC1Hvr0! z5pHxd4Rkf8*@PJ^dBn@f3t1TRt>dOZeA(aVaac<}1j?O7A-;f`kv)84K&3dETuWG% zJhqiTOUyK=Q94**41HE#ZJhgDo`U;}!7D{~P0i&L%QyKGJi6SJ<2id*ZnqwQ=#Zi8 z7Le^oCli1JyI$VF+=Pwfr);Ca$WPoVp~x26*%bC z{`CpbBu%^Y1)f|3?U%l_Nqsha5=)W*A^O7-(%v?dPt5(0}#R&EIE`j(?xI#>j=;L=(Ra)=n~JzxeYCl+H(aRRot;C18WJ z0c26 zleLiR+|$TA7-x#R5Pd%j(7luu^abnWU|DbScn+Io@!KAQYD*( zMADcd__i?Hb|At1b%X}IROW!dSImfsM05_brOj*5g{K-4;$?BJti9<{D-o>n?20tN+XL=0YK|GB{*)EtWHNw$n;DWzSoyI z^*rzn18=(kBr!^zqjT&S2e@cIARK!#Wz$87)JeW)Cm{D`|`~Rtq8)R4h0K^i$K~v`(znWH_qD>q@MQ|G|5F`JaLVYs zT=(}PX^&nhbwmv8p}$zZc=(^{7+B)|Njz41jr%f?D(L<$rfKjqLv?&NUHpfq^6^(| zhU(aMVRz#G;AZ*fa2X>S$p6J4;zT9nfW`BdrOyaYb0(@x7 zIGxu}Elnq7197>3T=`#crh(ffv<#oP8uVU@OWWqb?YPN5Noqx@b#sDdu48)j2Z>K| zx6t1GlZJh&rGomK0%xu~F&a{@P%!tAzFIZ0?Mp0;oPPZ$MQ>bt;$Eqoo3EVzgV`|C zwTj`_z6zBupPDv*EBl?haq24nY@pw_nsVq|AiDeuxSXClx320O1pzAiolj~ z1W~da%+>i?WK)xo3?LJ}cyCb;lT`}S~IVE)$^%TRk zYNC=7o=aflvwZtOMopCNlwVD7E7y^W>*aM<!TH6lI;2zvm;EGV!BjJM#(fD&^TNSO2+w$`lPu*k2q|5KVQ3jFIIO)`s zC-=v;zZ?y-B>(!F`WWJ;n*PPvi{}Pr68j!ll3jTnbc25`4yt(t%@(L_B)CR1)nQxx z8yc}mdK0w_P&c1lI!RHLcg5HOIgKGY$v-~aa0$IORuI#FWBGpNF-E~0uVB*vm7zo# z)G1LDHcIESSH}(Y-aTXg_3b)j2Bu31=%}=9VOJK!$^lut)aSVMA5NYEL?-!eu|^OsDekY2$#`Mk?k; z+-(K%o$1a=7FBJcCU(=+O$gRDi`po5+LQ%)KKmNVx_ znOhHMk z10G^>9Cn{A>b4THc75G@#P%x$cVB4Yej3YcoauwQX}^}Uzx!DRgoIvJk2S+*fc!I` zdr3=n`BG1d!FeQ>HY{?B6q`lmPqYkvJ@LG*K_2QV@UdVmZpOQTfQJBt--1w%!=oW@ zZGNmjB^G|qN}HL_o29Y#@3R7qW-bA&yI8Foi4I)xj4m*F89xklY;2*i19$7(+%1Dt zNvsTOXK7Zx;Kr4745N$i8tcKl(g>lg<99vZ(%gFY+4?%^Gw(1tG}N4!$efSl+=k|y zud6-Yyg)LdV23m(Wx2j%2ZX3%`TRB=n1INE42H}x#8{DbsC@Mj`H739@O6%z+IY$c z&twi#t^;A6sNA|h_ua;CaUyZ%?8o|~V?yD{4{;jF7LdjMvx@!K{ua2+_BY(;&(!cA z0QPU5Ik(NaCK3mCZIBuw1?yr#t|TzB8sOlnaaAtLnY z9D0|kX6~S3wJ6=$^kxd3RsaO8!(!s{8;a~P`&b5z_Z&fnLsB$-cLG;#1>Gw> zJzT243^0&eHrVF;E(YOrB0y8 zxWE*Pz*jQGC*|j_EL&^Rm(OvpJi^NiwCpklj_X$-E?1Tt%hFu$ahr^lTVtHfI?MeB zS*rSAmCV3+;s?&gwd9++YCC!>u9{R2wN^GVn>3rs->O+@dYe{lAm2P8=#Uk3 ztNvqP`-_I8m&w)qEmG(2;RNoMU+B5Xm)juUQO{Of{jnpWwtIc;x{_eE#cI0Lk^HO+VG}F<1@y=p( z)1dsrR|5SVA8%feFFQ}a_+TZtee8U9%Id?gk1dEhnb-Jk1B0m^Rjv1K4~n!E(-i9Y z@3bK<-VlBnng6nWL81NTonCRp2@%AA_Ue7{)yCf7ZXU&sFRywY?6vzUK7~HHvwdgs zX;q`e-lI=@50N3aZ!*HlQ%}Q!rv>=BYZP0TYo^36%rNiI^0bG;*W%G@bw3s2%6SJ` zKTc_fcAMOpG!h(DR-EU!^IV{9A*Q{(^W*f_z1Z>KA%of%^#>3Gr4{+~*2eZVXyq%8 z_JQ<$Mjs&K$$>*#`UQvX!j$Z{MI^W5h)X0>^{zcBz?3_KM0)Q5TxM=>r1O>Xb7o7b{I0R0vTK8jg%VM zXJUL^1ESs|?SQ-q5F`yN5GxJUyo63v3yXUXC*DKV-2)^_=%!Gixd4uSu&Vj+M?6*P z5G+R=HRuORJCaXB$y|72O~+w`G30R(NZLw-`O#rRpZH0rSu8d{$S93#mn2@5E>MI! zt3LMg<~#SWbddm4*vvbQ7gSFDDT4mgMRzP8>jWU#JS#6ts28vtLWNHODDi54OWxzA zibvr%{=3wh`v71Z2_Q*@Qa<2mjL>EV01n{JBQ;GGYo(Hac>p~YAnzv_HDGKSX5Tc=ZX-je%>94?{R*A<{6!&>;0yqfsK!mgCJRxK_$NEqORf}% z2sagy1u|qcipP94B!QGqfO;gxfe2o-3M@MVv|Psu%^T}Qkxv^%H8rmb^oe!0Y~y5s z07xqKwUI<(l*0A9sU=ZBbLu)P;B@vgm^tGQ3Y1;Sv!}(A?+@Kf@yeL>{b3j{u$6$z zf)Dcpx46`p)9ZIEW4 zssnH;eXn^YN8nwqFvShBYh<{Ea})dODhlB%0xM8(c&pgxb7RJrzf&xGVt-p+$hbeX z1Ypw~k)xz=0_4~0RBSq9DFgR8u2K^(+8U#s)2!%B{*jBx-F+@*MS(gRa2Y-FqZ8(R zM~H6Gsdt@&tJ40I-L|zX5K(sn(#jdjF;-O`;hrm9bAh}u_%x)4qT}#{K08SRv{V->|YL))ih@5=@$+9$icDE zB`wZP5?6CT9GrXFFrs9|p_GQ>HZM~CCGBmS8Sx6h`KN!Pkoq3PRs$mdF+Iwks0W&@Jrm6n)27FrL^lnW^?lBbznRX zK=)@7ijkiovhgMkUwlG$LPia1{}|!UBjZ}AvWKI>`Vg^}QR)59`nEW|ebA;E#C)j;5 zDFCDj3A_ojzyqwt(v0KKx6`f~Zvl{hxNi6FdfQ*IYM|?H0ua6Q9f*Xo47UwTj~^CVXy75=leixJ5*+)6}&9J0qHjJ>D6G^9^B z)EKq#*r}`2_s&YOz9I%Y+9;gcUo-7nItI)6hIxV0Dg2*;#9+)#rfmr*+dLo|Q^%N9Ro^?2O;|Pry z{GeZw*<$R|*YST<$A5h7Z(oY%>I;iFSd{h|q?)58-cKKWT)GG83+&Z;0WynF;XPBI zc;(y9!Yvn3eRC9?6Ek-89ck#>@%Jw~FCJgNdX-LhIkoXfx&YPq00XeH8)o7UnIDFU z<=KrOGM`ld1&U%>z*P%2Tj877d$r3Q}8qP(Y`mqiZl`Ps2N42#wtQFHWlr>wg$y zJuMVD1G4N194nboY|Y{fDb8f)&4!D^JPQI-CMF%RAeM7cTWAwCjh+obyZ1lLvqh~K za-gVHzvq*Zx_vB=30i~&-6^ZWa$Wh_DLZ3tp|pHfe12bTSqq_6>V))wYBSd z`rmWWPR=jWj@MnJk^@(AVcgl7#DBQS>&g2cVCYM?%y+IQcNH6XXfN4k)Q9>6%3QPU zSj}Pc*?nLpX!ek$6&3QS0aowYWWIcnXg{F0bL|DUQQ);JA^{aqeu1}05sU{xwzz-? z!xB=4MXA{d<$SbEnIBS5ED}uE5HO*x2NPM+d>w0_9;ub}&pJPWe84}};NjZLwcrqk z>u1cH)SDktjklXuTqOkg0~H%#5k1*b*P?&9zOU26>v~^{P=6v>9gYMlj)Pu5kS?|K zsWxE_%hruAVl$aC5?!=5`~BC%Ct0I+&|Hj(k3a(e+G@1Z>x^gSk)OY>7oJhibl-mTrf`ny-bMvdLS}J3-`k4D@ns5JCv60gB6tdotAcAi?6TqsUYgTEmiLFE zPqSrXc@I%(P`zCodeulYD8Q2SOuzt>C6Hwckm1ZslS^a;DG9Vuc|wR|`+=SaUM%W| zYP6hrzMq`yhg3a7PiWec!d&+wahu&qvCO}huU;L!MEmjLF=`U0%hnmIv0-4{CA~0vrESdBO7sC;!4IOE}uRD;*?$*rpSic zB%OPUy&aBY+#o}1m=8_QbnS^*4v>UGsDskbbzMtT4!Mj9+rUUP$q8G4Z zGK~d50(C_-29{9(d=xgxA&6gZ4nuW}SIbLUd#9OAP2v9IV=P}Tk>eJBCU-W-tHn#g z@=X8>i^n-*+^$jHsgd^SBv9RB)Q%{-7EW)`MYHT(I6zdl&IGqQ) z{bLD*DSzsS-(7DdxCe<({BpF-=1}4>mlqaMCp*!=C^6<*1fa7C7!t*FKD@OtB2{Hb zn~imsknU+(<2s&f@04#4Xr6^hmyrY#i?1m@vXgu%NjRyV*W6UUbKZqrOx5>I6vqBo z7G$}V%FbAiW73jLlXeul?S6=tan!yiv_(Si67j!-c(ao5pzg55P?0Qx?n~|A-cBtc z9Ru;4`2G=zOR|jDJAR-gYh}0SA@9p5i_~&MeD`@ZigUz+=`R9PsQ1LNA|Am@KUeaJ zQ~C(h(|Iyeo}bf?<<9}X-qYVPmEEzLZwtKRp~@VeX2c#%8s&4Of)#0E0&5rrp()j+ zMiDI-6JMqTH=5aZ45VrTcQ<%i49!I0An92dGFeMm!P)saP8Rp*WCM`X>c7Ysq~KM(W~<(P=1>9bF8 zsI=ky(^J7ip)nd&9~G>NY2Sfx*%w%Kyg!6+GoF1xG~+B!7uy5;#Ml} zKWeeT{ulN@pC7gBZlNMExlEOBjD;rRAYnO&DH;^ladtf%Pt8IB1!s&BelowtCsu$r z9ud={f>a__khb(vvFEj)j&2!fu{&mMioB^x>#q2kA{TW-Ky%7EA}2}`v8APRRhn&Z zq7sC(IxWlhAw@T4p;)J|_BFQvy4vUVOiA0#EN$yg*Dk&4>25ilUu1IM+9b*}epB-S zZ>#x(PNOt&q@-SaV=XYZC9P3uJ2;xrkZCJv0JRs#Bf^ol_aBrs%r9b>y3HYYoXgIB zx_chsEsWbqS#F*~a{r%2#QO-|BCLw&n9}#zaOKB?AMSP)9A%;}mv!0-{ofJVM7?;PH8VB~ z53}$8*=F4L&R(wnR$VDAsPfIF9*}gz|A@*YV#HIX`F!VE?BBiVzdzMh0PJV0$Rx|V z#{=J6;GTpOo*qEu)LyM~Oy=J&#n)Z6yS~KB*&O>6mBQ6Sg+Q99a0OaL zwyfWut-|Yn+}!^0)zTApVKtvr&?#J)2H0=Z8T@o(3+NQ)?Prz9yhRl{9a!X9;{`kg z0CLfQr!Wc1-ZLTupe`0zlAa(!0LgTM=QBW67$y|qyfhK&Y>9x+1JJ4oyElPofF;IG zmOdd1QYMR`u7tO+A}Vumb_e zgJl6wWXCcQdO@m9TB9?9hZ`fk!C7;TvF=k2ljkahw3TT5hpV z0l9XmR^t1J6@p;$I^rQ<^i`;xW)qwl4ZrjG&#OZ8wJ-d@COtTjldiM@m85c@Nr)-{ z_p?m+;@y5#JFrDDtF0Okh*c;_1#MC0ChRZl?}@pp+GSBI9UGbp?y>&?E@Ifseu(YA z4R!MqZi?_i3c&w^xON2Cwu{TDtAF>9 z!!1ID;Xm5q;d6?xKSbWC4S36Bb%`7X#vzxWEKC0xAqUh@jW!lIjZy54VE-7B03{&G zjNl%v06734fC4q7AO%nWNdV9Eg6fVGE3>Me^dVyIEB?aQ7-oR9Z26O>N0`13Wn zCWR>o3v?i8Y!MX}o083KRj+jG$a#ygmBN)V&{fsn&1q_Z2=MV)!AB&h!mPW4DT#rapAyQev?`&VGpOVKeB+?H_4S?5V{zq5-KzYsssCS*>GCtL${&e z4Y@u7OD6^D@sSXPMfPD?Iy0H??EI?2V0&qZvYT+EBhm}-gR4jUYvh@2bA&6F{h^E= z$Pwp+!ZTFAU&R;UIAQJeRJU<)dWc2dTsr_2C4P^@M2m!do5UP+n}#yb?3Bin?VB|l zU_+9;9Ok^_C%CL-Len-p3!^S$nNT8SCPy$^OJ{P$Cd{W;3_cUdCVWO2iSdEXiarzB zF-l-2$OB20$eFWizB-qqtY2z6XB66K1}Nlgimw=LZZ*;uHQ|{m@2HpaJCKrCd9U|# z^jAH0Y`teM6q??+Y|GwjFI?{UwMXXlfxTR>!~gBW_MS61K9{6{{(Pev+v{i@&Ceh0 zxbw~Ne6KarffH;p`H!Qs%VnpF$IiiA&c0064+`j9PWHb!T+)|KqkFA$dTp1ZkYsL^ z%--_}-L4Jgj&zt7V-9QvUp{}Y9DSqwA8QEwanyy@@_${?Zsm)4QRgoI@<%=^d$+{x zG+KWCiI&H;1-E=|ckf>OzKv<_qW)cOkL}}2xkVl~0ttl{`Ek8pjEoDs(tg|)p4Z3#D=3}egP>1ZdV6=$tJAHC0S-y_Q%D|Yg_JQ8fqpDR~; zyX+GfV@>b!3)l9Kj`6?J=bv=qPu31dj|s@`3&=kSDAo=vj|r^q3%qs`*q|MBGbX6D zFR1+_=$>|PZ%pumzTm-=;9>2M@tBY&eIc_aAq(1}%Q2xZ`$FHGgsy9cF}Bh^^o1Rq zgniMzd>nI`{LXRY71Z@!c(c#CIZ#iz7NV{H(7Z|M&3Cj!R;(5pwqs*KuG|=RGH;9CFwlgD@kRVh8rM53Jd#tF&oFO}Y_l@kCs~kYG7o#?%F3;xl^MCUrHN_i_*g zDIFpHEal2FN&Kdiei;T@K<2YtCn$KprIEjp%*Ekcce*2L+=_86%Z8=6c7~=1=L$ky#M$9?=$C_^E~^^-e-n) z4zHZWy4H1lf9qot{`oNa9OBISnXkdn<^y4M2~Ix=vD+GnKVMv}MC-!$+PvJa(7UqU zSy$#Q;|M52%~N9TVqrdC83G(6>ZNU@^2P91gk07l!qy=vWY7*6kQ^_a?F!8$V{M`@ zbgo9=h62K+?oM7pOnUS|(GQDqT4S%)U@rLxQLQ)eF2DPdK>}x#QpTm68N*Q=kTdt;fDkIyuXrne zT)0Stg5Gk1>wkms)6+}J9Z zgyl(06(s91kC9=@LoE5iKCcHka>Y{4m!S#50-l3Rupi`Y;WEifujt?Q4{4?@aUZoD zijkj%k~_}*tXtP& zD%z9GUWF)o(0ymBtRhEjI9fM)hTn|^Rw@J5=|y5Mv;O`lT}A+u^($ShY3 zyy$_mzT?4^Ibdo(nwkby<2_`1*Y`@RRPFFOhGe(5FC= zcRlFmgvzt~g*Q*C$SuT47Z(8d7n%RL-YEWxppS6Y{u;8-5d5PA2{?0s&<%kJ&$~qI zAFmXmLXGG}V!H~V>5T9js1)RVajPp!9(^tOjJGa5P zf|G1IQx5>v%K8{H*M9RiTb+?olg@l~{eb2SZH4t@hq77y=;PuuyMvyYj^s>*o>#sX zU!NO#bZ?bme;p!4WQXaDp8Qp8u=LK>{lz9o=b$pXR+#1W7(10NpZx?@v^s+m7BG}Z zu`U}2h!iVnc-nM#(~BkEC2S*8Ev?YyBZ&sRHob|htYXpz65%NmxYTqyH9ts(Lkt5G z=#&q;^obR4B7sHLLCQE#e`1=&EdpSy8Ax9hnQ=9gAFw%@oQ9J2Z~fBF5RFi=YuSRL z*NH-gb`c~GdhBeSt>c0ciWv8TMb!?=Zo1%u7dLfS=yr^jW0t&b#l(GY2$GtGi&n(F z-zpm!N?_Cf1<`EVn9P=Oewd=!{%*EN`_^wJt&Xj^O0#>X&mJdch?!WSjrTVUQ6)}o zoQqBml;H}e>G9PRsC|Vh?FQtdi8AI9l87zpVB+Ey(X}eXhvq2Ev!C6dJ}ay!C#l=y z=mdH&c+cEb`RTGbfr6cHj$WU<#mXg@>ONuc`q3|i5tOZ>xFfUHFEWMAP*FS%WfVd= z8H_e$Ck(ThExL}dHEVWRp969$mElD?qRwGVb!s@+Z3h^#F}wnVO%6M!zX;D5 zwT>u*Oc!*hdd{-^K0|DcN^@~$;1q}Tq+sbmUPfs#w-|QS>}+~Qlh}-CdQ~bi18H?M zbe7j^i~U{xr4kdg-_?gu@1mf`Cf>z2UMG2bt1Xlnl-}OysNoj^Sz?)j#OnC2J=C+q zNsg?{qo7f4P;QG6my9`{i)~ujZHrAc|I#=Z#Z&0XVanYLX3M^PoQW{=FB|1FlXZwi zuBAE4M}hPkY$!qgtzb@B$xBR?TW*MMcF@B zv_|400tWMvzH{=x#W$)xSB^(XXLQO1`#B=@Xd7WTHbrUdmQ?pD2q{m+GVpw!TODFn zBL&7)YOJotvZ3n8xaZD&fDvZbVUrhNu8tL1xZI=NeVB}o868;8`Pn;EWY>&4ogPK< zvA{d4SQUyO-Rdbo&>css3y;-)H?anF`SVk73kyMSOnK9~*UdTTPQFglZM{OBm1~F# zME`(T#j>_Oxp3x-qeHKk zPP;}Ks?AUz(hIiS8M;gc3PA=TrhA^^P%J>!=wT9p4EjE8!XOD55+RY9dqRg9b-(Jc zVb>TXT4;|tq)@0#YAkszN(!MDPsd4#*H{pS+<}asVS$NfK*&N&mK-lRH zmYK7aSI(1;YMJ}cX)i15l7m=DUyJR>H=k!^uCLUbc~oE;2x~8VdmwT8NfI^owNmlN z6efLey-AeF*HU)zTKyjBf`sRpxpi=7|W~OYaqr~nnDJ`($*&Bj3b^cdAa0+2&Lwgs>hl?<_QQ^;;zGqiC z={A`3)ICoOw=FT;l(ZDrn!nHRyyWVYMh`v6i`pr*Y(h?>-pAfKZ-#F*nt%Cu_w86U zS$)qI8EDXo;`flG@GVMXWJy|iem%Q^26*0`oIioJj27GQv|ZBYn~7xR zcjNsZVhJ3?I)-F)e8YKxl%18!ERp-GWEJ7NbOTWPUajYRwyW?f8+$PrZ2XzugX!9f z7AcyP2hC@OKb-fCXIyj5VL9{BSGuJd2vN*DQfFhZZ_V2c4Wri7ri!hQ6=slBp!A)k%go$oJWBNhHA23oBsckoss zI5#jY+$?_inRMB3gBuvVhSk9w}ch871{6|qdWG*~MJrT$evi|jDB8$`(<<_*v zZ^6PRbchx}!!6GWL`B!{y-VK^_MkPpA<5IaLuY;`CIXGg+@GrETNM*t;PpgTV6ow(=lrfEDCP~nZ#DwsPgdIJ|7%8!U%AD!|-Z4)7 zSR0NBNGdR9nAAw!^+`4LfUU10h4NyYI%9T+*#^F_p0u%NTgIZxAOlFI0V;gRlEH!~ z;(k-QpiNrD5nwj~^QAJ6E7Gy&G191xIFoGS8kU7UIV;86tToVO2X3Y{B%M77CK*6g z0lg!ggr21c$F0#z?TO!TMbs-Ynwl^_c$=M}984>IY|4YPe96(#{kG#0;t~=L8kquS%#gT6uz3zl0X1i1>|`^YLF7L)MbEtG$_FnLD*PXu(@6>S>mTafJN)(8q@xP7*esr;r716X- zwI@aexk&{Lnv7jMJPJ`c+cm0%>baNd3W|L1p;`s6Li2*4g$tU6r&aUGq$1HJFL7y< zBo9C`itp-RW-_b3IDwIX1hN9aO;i|(;EQtO|H6qfWb@IfyHN^YT-t-BEr%}nid9%BR98gsx=|d;0n#YTL-ET$5##rWf9fB+rCB@;%g9cCL0$S%2xFOi226Jv!e7fnWd4=BH`Rh>SU ztH4{~NkzFXS7EsHqnzL&u9^mLcopuY@jFBmXhl;uNGoa}*n7dT@u4ne z61EF_;9MQZp8ycF2iUK%oto#6TsXF5+oy8%$FqI7q%$fX*9-TP9Xd(5S9}~SRgTC zh`?&XL$vIWJ$A^kBK)@$f;$)SM`aHL-VVPho3NmqOk7X7R=1i?uZK*Y8B6QejgR8i&U+-*!`t+Qw^ixEgFw-q))F0$ z*go=AWs@v*X_V_d{^>dX-^a|5`p!hn&Vk-e49m2M$EDwnHS-;Tx zQ^ zxk6@HB0&!anQsyq;+&a7v=LjY`PsLI*_DF#NSGWXY>IX#LJGdM6g(;u>ZqMR%n(W* z6qDHJr*R=+v($T2g3k!hB+6Bl8kTt~IM$VUi!|}gQt*9-U^>$r>)E-Rdki@d19=e) zA|Ih*S5D^b14I;B7`~D;`ek|MlmwoA$va#TXiQmnR~C#o6#SwjBz;9lwuxJ#OTuVj z+Je)soI&b3S}HbL!R_w#CevzJ3bYGwxst$OMAgx7RMj$x6LS00@oC$_JiJF=0bmJ0 zE|pS2ToFqJa^U(hD9ZQ`VAwu@b#0F2V*q0bEd2m^_o0_YDJ!O;ocoK$V;L^_ezZ(o z8^-CCkT6DODqwl;UCtB3;dC-$@c;za7f1Of!819(yp|yJfVU= z=BjqcVJhdr)zO&xAxv{-WV@A2SEfwgyv!q3S!CLqokk^omHM0KU1fpZu_`KR!77@- zMP1Rw6K5bt03G4?^-(3&ufZTA(M%k6h!6}kq6|Cg)5|M{_wR2OE(>W;Ik5mx+znQZ zReIS~(6^gJO&Xs%AY!y#_3T&G$_Z7+7!gf0SPDyT8?1KwHLbf_?UFUvKEPLI+^4X9 zgyF@g18^HP_ui8zB3b4uEnM+{$ zzxN$k+q{Eq+1l}jE<*;g%2drocP+Dk*7{r757jRK)!p^g^S^I(d{VbxRch1MPR49t zbM?k5cqZQhr@zukeqjx9)Bflo^)##D9_n;WnlADScO3BaYn8pJvpml=P&Qk->8bc& z-@^C2JiH30OPJudT^Wl3Eb~a^y~{j2LT7k|P$%uDr$6=yd4AzK5i+0CwX)$Iy}_JQ z!oyjr3(EY8xt0U1_yPmnI&MA?vee^Z-&3TqP(5E-b}~6jSluQtMNm>hMfAlh zKL|WBFxcB-9npW)ci=0ekGhXH$+jw4hmVn&g3ldN(Qq{(-c#rNtj|b>i-E!pScT$w z0~8KJ&K%xIKMXxMd}3|uS89{}RotHSSUu0nl6*Z!bM{=LhBjDVe}N)xE7da+OrPMxUTH)kSa zI4vq2=0vzd$TJQu`J#-Rp1boVY{sOwlhG*IZ|#SBrDuFS?Rq+1>|Y#kIF)R^_4L{+ zVHF&vS8S&Zf)Zh)e>NPFFoP12;t;8FdRG68-oEPU=JGSL-F?o%cyZ_F{?8jcQ1!aB zuQu!(J(uLoolkvq?q|4LG{IV5QbFbjHivr4u{VW1tIU_>#>14o0%rOhMAIBQ!g=8c z`3Q|K>;0HNWG1C+_TrH&31JKbCL zGweK0*;{k;riTW}PE>iLzUwcn&Q6^7|Gw)peAh_pBrqau|3yNct?aZKA1i zy==Qoj-n1Okf*gZQsEk8=~nV$E+)=XTC02tJzw8PX0D!+{3LED*Ur<$iYs%yhFAN)eS8{75N!);MQjP08+m!{e*H<+_afq_$t)VRQ`ffJI zO9dQ5jy_k|j|9V4lMIqu_EYe$Vq!zxs2*w9C9?2DnK*CQ{^Fv0ikf__RfYU)i0wIN z=79d+D>A$`uC|wc^j14^Aa`ne8h-fwpg+hNtZP+AUT*oq_Fc|BH7-P$xmq(JMcEG! z#qZ~XpMwRv2ey*i9L;Wh?0l2<(&(fPKY=U#=lN(@g~kn*Alhe-ggP-c&yfsSddr<8 zZ)Tm)<9A3cJQi1a8B^z(>(tz<@guw1Kg>W}_RF~0r`Dv+Zhrz*YN(h$hUuz#8S)3fPzcUCrc`nt zu>EuVhvKt`wsMO0``YQxbDuw85J6_W{9>`F_27)DdaBP4&DCa$2hu0cKKt6k&7NPd zHMPU-$zB4c7|4dE=~MK1gbAX@42(=_4`d-PwaU~2>dY>*wa9Sx$Fo&05IsXlni@>= z!WWUStNCzRe<+w&kt;){YBom00jQZjm!!2PiyH{1JEPY9P?0c+;R-_J)@%*Zx>MFrdc;%^4O2`H^^Tw3P zeu7>eK1oWm&eWU%UP(7|5o7y9)w${5PFtZgy$aOy*HTB8`^(B34$D?`L@@C%Yg0Ck z(CB1U3GsbuDCoBedNdHFDbixV$?S_{<8-Zi>a$~AQTQZluTAhT^rHHcFSSCpUoVtz zG0L)*C7dQ#a0XNOPXjV)eM3cAG$>I*Q=2TI5hBj+;vaNp3K=h00h!fVW4NS8l<)dK zXduMBCK|}W z<)phwS2xSjL#9Xhn-^ku=Y@r(>b>cPv@Zl_cbRKKaLj&$xTjWPB^eGhnqV2DPJV3R zM@*u|dy=JMzDM&L{@5g0SLSQAUFd&5wRL;+*I(C&at^6LEykoidNlxL+l@@dH$@JUv zmmh|g1_W!rsz3goP5sD`SKMg*!$7WjMxg3iU_H5bowK^aM!xyBlgp>flhM9Y4@XX8 zg;gv)JzM#H6vaBs@Kzj5$HAwhl&kgIg`~b06OrYcCPrMA@8^ zn!9`TpkfeSA=-F&scO?7(m0ojml{Ic#u~+5`M(bmt6!e2qkHM%qVOiW*YWCMmv@{%7@OK-w}N)pYBb_4MMZ>v2o6<7FqGwV2JyG(37qsB<3;4d>76@7 zQ8Ig=kDNuCp|K)tGz_@l7-h^S6o)DaH9Ey#ydPK;ydiEh42R976Lj=Y>k|`P(?*7O z&2?6R3ZcT$rw_`tf0XgO3FXPybbPrgvHrrNRzHs9>f_7w{6?hIr}tj$cPk$xK6^y ziy*xHU$8+8YPb7XhajAGE5w7<{wR#Ia8Mx}tB*YTb^_tdc9RceDrJiJ2KwGZ zceh?>{!?GO@q0b`@Hv?%g*TD~M^~5(SLSqI$EcdsCgs*9U0!Uz^tQqu6>V_~q$QQ5 z)6*_O8R&ak+ekIYG+W5{+ADn{ZFl*F<4y9jHC5usRuR;&2REAJ#LJ ztceoWV2|4$@;AxKl_rV;8j|*gM7oEfsl(8iY~>RjeUFME&3-nH$y!WN%V~Ok1@>fp z9SBoO8kTT6v>RyXi7quA43dFMc;M`RX}5>AwMMnu`y&Lm}q@A`mWEL?dij&+L=|FBzIlmx?S) zT^^S|uXGw*C@b)H0?4UyyE;UxdU6SCGbTcblCyJ@*q2A4y zYZg+!zF-ya&Jt8p9F#o7g+v{8ycL@M#D%H{_J92=E}Z-;FVq)UKsM6*Zu(krem`&4 z{fFXPyzZd#XUJuXQ&}GHkNn$fz?98jgd^=GoEyL*n(?sfGNo`w@el8wryyc#Wt1Dui>ve;ZS^u zGLq8s!bSe(@ks|mK45xAt;7VXj39wAO$MsMv2K6kX9r=PgQ_c)`e*%sv(BFfPB(R( z6JzA#|J1#Sag%V;M3tM1dt}!tPs`t53DQ$|VosQK`BeAyu}<)%23D(G?b<+Hx&~0W zfns!8ZaS+L0o1zzOl-QC51ip2`WFgS|NNQ6{N8w_wFCVpYN0k?9E2BF^jUOT`FY)& za6Ut6vd)N*XnB6l6MvbPSBK@|0^mzi49W*96{(^WoXkfwXjAdVl6TE{BCNeq#Z3D! zdpNWO2e_TC-3p4TMJ7l-)M)ASv$}CAKN^={s~56nB4LZQ??z(b0`jZZ#?Q}DG62pb zq=Na}9_kCTDoC>fFM3X}clxsSr)MV{fno`)2RC01j^Av%XwVXss=G!lALH=kzjFG= zPW$KI$J_VcJY@a+LgCEsgYh?~$93Uk0OMj-_M)keg$&s=fE?{n31sOuF{Ou-qkM~E zm@d`QK_>K=&%QE%=uw7|N1RX{?s|Yc8l+0FOrl5Y^UJX6{Tud4x_8+)kY0aRl*?!u z3OQ+VO>=;l#H)4)BUlW&VD7Ax1S6hwZ zdZPgnz!O1{E)}df`J;-S-$tY?T9dEsIjF&u?gol6YBkjvY0fJ$un3z$9?Ae%FNY5E zd$EYj*D*?zP~*h7=@6c)0>f#R3~`e(kbIF5siQ&NSKuI098)r6QJ>{jZ47UO)KH_> z#DsX^t|!HclhbuB?Y7TbwuE_cg-EEmIHW!A5mPnnM$(MCU{?MsQL<`{$!rF@axAEQ~tD9`>F7EQ{aQmATQWG_QbJRSmJlYV;V z`G*Xa48--yp!Bo;(6Ff(2Ha+x$iFhmnBDt$8(YqGu6uhiN;`qf(l%vvsK}io)5>Vv z9=*Um0RL?#{6+t#XU(C{K46b{7ax7My>HS~?anpr5YLUwh-Rgpv&xJ?yAJYvArALC zDOY>`umASg6ambBDJgFvQ@+NKd{P^ez!9lu7;93)W)Jt34x?2 z!{*=nc-I9pboVp4Ym=m>D?aV$OH zeOI2-mN@5mZMup#561L_rxjQ^q8K!-F_CexuQ&Z{T(g3}{A>9P;uAFFZ3m3++ZQJO zkSM-6qCV#1-8W^6Q+8Ga_H-)sV!*3;bMf#f3EG_XjMo7zBGH<(l)27oojxjh<4e*Z z&s&aD-^Vl_w}M{8%}$uwMQLu~lp6yfs-(nrs4NcrAR~cS!!2eZ6nI&vf_=f_2}L?= zP)daCpU<3RYGqY?MjV=< zynZYc=~z!DIlnXitoaC@v>~u3j%u z`)loZ1Mhf4aZKlkj@j4&vOHhi`QRS$qp$tXWlUmcSJ$g6SDcN>XI$x5S7(FVS0*t}d^T8}CipA(-G)G(j zmcJMrI9uXRZBdru&*-dsxb{rD$$t&9^FW9#&jlyDUIXl$$^a_$PK;ys(fRzFOu{AX zu^LEmMJC>FQ_zLlr^SjMjXQ=W+1yk&!ZRO%?O-`9|BxHYRdP9#NB7X&_t%Gy7;o=I z9BQwE?}LV9e($B8>tEx!|7ptkw)cw}uh}pwZB>h*35$keNv*OE^!QcQp8)Vzd@DDV z4Q6Fm(qTGf!mPCs`>pf5iFfuphzcZx-kU0 ziyv?g{+fC*1N_o@Kt0V;?VNp*Z@U9~5V=+r?6dr7ZthlXUG6w%eKffFoG$aU1-e{v zpoy>C@3z6!kdpwvE2*lkaJm*lm0oCIf)FpvC6om7;@yT{o@q7#|wq; z-kwEt#DTnj&EK3=g@jBX#cOH?X2rR}T(k1A@NahkU zq+}2AN->h&0I25*2|2~+AImZtAT?qOaW{_l(uiCV(f`?kh|QLJmcT_j^uHzkc}4Jt zTj}a)Km_`e5&b75ND?uwlN=|r3cam*+XKW>MuKjxB9LPAw8s8Rq4Bnq#J?;P6Y>*( zE&NTIL?iB6+8EZ#z)?20i7{G>&{D?a>l(?SwZ@Ju36b2F@$O>A`(cHZIz^R%S~t~t zRPJO}yLzLIW5w7dTbRa?urewW)Lo%pD*2`ZILrvB831O`KyLV?F=V8@mqPA#r)@5# zscEDi)N-9CGM^9tG)m(kn)wi?{2IVAM}h33y(CHCSty z=$e?m__n%qQc!Uec#5R4PR#bidX==~(0GuoiSADmO_?mUkBpsvNiq8_E5yr9(V5*w~iSp!X zB?X1qr`Hw~<}%_yUmUO*a;Yj7c7Y)6TvkfZy^ey2VsUhrqc>M>AgqG5=54}XZJ5C} zX-PYfQ;dL%a*?#9VtP>c4}$cW=V*FiGX^ikkz95pn=CIEh#`dba8^BwNDkCy5a^s| zr54EPA!SVgN|U~-rdWm7)&L{G@<mx&a>eN%6?i3nrM0VYI#sP@NBK6*o32@D&+up5Dv`Yo zIy`FDP{ABXz<(hIbpjRX;DA4A2MtJq@Ef;~2V)>?7?+8b zvf%`LvXp;0!Pp>?TSe=?7pk-Ys&v6X=Kor#GK%?kticyXxJdOX54B5?pnf#ZYCxr}oIvjcsHpINS~pAZ6N1xl1wpEg{)sA`NbSbxk;?@XM) za$s60elO0wlze!!{U-^%>$-U7L>jdk1;Y5O5}|F9Yq9L>;)254yR^s88Ma$%321e8 zJeT=^;zf)p$*vTOVIP8P?E}h3BISpqL{k;UG(_*J?Ic#DM#f2PknrKz`bY;2HWq$x zh{Hw}A^KF5`0*Z!)d9cjK!q2gV=Q#SDy5Kl7ow%T=sa)pyz}xcob<}`E8*EJ3VB|j z&o$`~4B^GqI=n9>vObSdqijUs`M!0}$K@U^xy|VO!UB`n&#M0Lsm!vgkFFq@n$}en zd%-Z(*$jR=b!-f%5$I(9S7Ve#`3&YmqX9IKLHp$B>ytCz7qeLS?~S6;bXUk$W8C&) zlCrI1A`QDOqk{JuS*Hy@$UdN|Ys)pQ+_<%z*dL(+E&U#L`BRT9M<7o4h7@i>>f5d| zG$;?X4i~c(8($hY_H!f-9PMZ$DSv(9Yk9OK(b!^(>YsliUyOI52z$!9JbtI%99f5E*p?m5kM zMb&RJ+C^y2=+s#ms(O!8T*-{LN{d!?j1NKqQCuXX)QGN-8f zOlXGaNGgw>6T4%^20mRtw{RgbXmdPQ(YEuyr@bpQ?Typ_m$Zj+FTJw;iGwWBVmh8B zWnKSAdx`2(%dKYiDJ&Tha>4&zXk6ugmXa&!0B){A(H0s{YdHQ>gsV1NL!&t|41Kqm zKXCZ#wR%Cz88P{;(RaZ#VpaFN8^(DhHR`tc*xQeQGFdp%);Lo4_ z((bQvmmG z$qnvpKJ7|B^ZVD2L+Ok+cYZ;)-rS~3t67a^`ZTJq@%<>6S;*8z4 z@JMW-6+qMyAPQR(z(iJHL1KBbENsI)S*9~oBvmOlR5T^rck69B_9}a zWuF*?o`q8I2KP>V;L>%R@@Jg|tC39DD4p=B+H9pU4$6`rOLOmjee8Y8r{xb#J-pho zZG-gVJMGll>h>r+L^xLX-9jd&Y3>G}4f6cn{;XJZW^KL#$!2XA8%u6zuK!rw*Npx0 z(5#^EYk0%whv$k{Q)0&OE`O^F_| zgmHf7U8NzhynZW`WMUh$F1XVA>^0GQvcZNZS&t{PH0|Bx5mA4N(6b%U`AWs#v|C1j z9n6NAV>v$_;KkA;NDDEJ&H$9r7R}{^k3nD<01S|Q0W_hb1JJt3As_%81o|)h!~d-N zmC}U9^q%ddhv*7Eo6J!4&v_B@7ywxuEY9M6c2wBJa@6BO|>v($n#79x- z%G#$jgbLH*ov$OcUL87v^*80tX2r?7xb(Oy?k={uPjad@t1rY zA|qn29{t%Inp@Jqr-^3^g7K1xINTH_RoV*K<~aqDJJ-w~7X0pUKJ>2O*}_jy=P7nM zx%IA&4=-9g`oyd%JB4ZQ3)uVLH)E0Fri-raTxq$5GM@jd$razp`D1d4dO=brtT(Hv zJI~+zF}dD~WVUm^R;P30C0QfE7>;~3|2`Op17+Ug%yNWC9P0^K!!?RgLJA$lAOcy9 zVKS{n$1=9nti|64&yA|L^t)cbfMdtjlBBAStc`SHJ<`v-*s}zj1AYVJ>0WZI=E36j zqSJJUQcB45)AZ7nSp0A94U#S<%#+T9cPTsB#?Em8l)EvU0J$P-5X-vdDE%(qQ+~k` zdBaB8Oly{+$ACMBIEa>*AhVqlG<8+?F24Crnp$#Wy-uIaSF9$Dz{t~}+!!atrT zdY#UzBHyciyK_^}3mC}YQTin78U8?C_Jq6tvOqvrlkThAe9f$H zbK%Y1E8%_ey&ntVEA0n;dqfHt{ zn#m$ZQR7LiqhS9cxk0qOqw^JWZj zhneXEUH)r6_}>xd|BQ3a(d6mzfA&Ec+P0ep1ik~VG?_GRtDO8>o{r=vogs%X0-Hlz z)$BcuKR&3kITqfbb=_2L+c2xdI16)rD%eKFsl=6|J2$=z&Sl@s-CuZJ#;yt66D=;4 zTesBi^YjN(hr&FwFzzZ+xV)1#gPJ87qgX5N*G1{E|6_kKa3P8OMMd|aG#>p6DP3)w z)5fPdbILvC&(Dzc@7~zznQ+qwV|o6cVsxFZzQWh_Y3aeW_i4=ihkLIEBZUNJ`+L5| zh-l2W*QD{5(wmlCeskM?G)eOI-lY>WYXdypKVs~miP81JhnkOU@BeOWW4U-b@~7$Q zdzuA)uMr}yh}V+Oi?HucOWfwRexhb&qqh{z?bXf7vbOm4iCTn|1zzkYFGiC3|vAvx5 ze;K3;=AcAiY-X56m1I0OQjuZdv|WY4Vx+5b-G6LXm;3qomerO|d6!xx(n;~+tLHE> z@ewe~5#$EDNHQ~pcP$5Ox?g`fSwMq#i&lcyR-rP4S<NJ9UY2}Difd6ZM9;5+1^AJ`7Rg?#kFRg@a|jUtWy%c*1I~{eX6GWBpcDZ$+Fi z?hgIB^J@A<9a6_C8wSGul`rb179?K&u3n#>hFd^HnR(;OO>7$SJK zw_|(GAXy6KLbRl_W!N5+L66Gw`F|gpvkH!z*?HM>^YC}7^QmiZOo@C#CH>t2Z#2)D zm6lM4lzsZ$x%5&XF^CMb0-iJM2YCW;KI05*tyePsH z5`#2i53oOf#PN4ZRIY%juh+iC>b%Z>o2H9^dS+-v8?9#&I8f1QKXig(Sue5!X86s$ z>NayNHjyCC$0NY;Fi4c~-wH+enBwEB3;lZw-W7&*NK@~HEIR^90)w_C&+(cAojiCW z-ZJyvk*MD)=iHXP5q`LaPd{E^pUhTv-~P!J0I>Rd4>F$T&-e}?+d~R{A-KD%$Q3lfunviTJWZh1@)i)9ZxZq zA3GPr8$LdGMSuAd9+en|1lm;%s1g0>Zmd$@lNP$Zj10;gOWW>m%%`w$w>!zLB;m(7>+p zl;So2;PaXrM6fb=C2Lkp?v3mL)e?moRQ|qbO*!-Zh&H&&vC4h3eqUvW^*F^&-k{m$ zD^}FRg{Eugr^2tOo7dTfe_!?o{`Uq~HJWBl=>B(_30#9-{{7o`!NK2R^goW&lUd*- zBuZpts4cuX4XJ0+UQP3|vz(fiwOLOr9#W(B^V@6ZDvYyk+f2^WwkJw)vj5ti*fhB} zg+Fk8-VAz#5iq;qj}kVxS{oYJf}bkIG!3^{-5-wqbVo$C~| zU4?bMy0n?+Sg7emcPV*$Ei>Tshz+toB6uRhZmjNoiO4tFH`rn5IR^9di;1LL|2an{ zVy0>D3($(2lwYDoF;(JM^p=)2wkX2w2a-;I4= zl07tI9U}V@5>X`CL!xG}j4gZCWZ#KI6g8HFl1XGxA<`6;t)kTY=CfSi&-XgNbIx`B zuHWyRzvsWX=AQe$pRecrcz$kf)sh_%-aPEffB7#JB}{M^!{yQioBZ=A9#u(;-JjgalQaZO#;% zaf-at-P|6xHi<1NIFgvL^UR>re1vnZlw)^tu_?0yqr1AfYkl*NYIHYqQ~R&Q?LYnG z|IDQK|JbPw`}0>V{H%@hmgpD3eF} zU*ZWGB?hBPwYX5;8XAdTWe$!15KkOx)JHnci**Hk59S$c`k$JUO81uu#GNfpWz(AM zKF_E(%;t3e&eCIf65_&iQm#RpH}C(Qc*4=!W!k$Bpit85p*~ZM&MiKZ3$@5>Ck`36 z#w1SNt1CfGeWsSyU;fjadNSCpxZcEllWzm9Dvofy&exfnc-zGD58-n8*ki`cOXpk2 zs$Y@K4g{Fn!)psB){b}oVFuaVc$lhj+vNA3{ewWs>$}Mff?Njsxi5}03Y@L@T^0S7 zlla_%sxD%4?$5HbN7Vhhym;95{KzslJt%3?dHTor>9md5(_(OqR@Rf6*Q=a1`xdyj#Yz-3D!p*qp zd^NHq;iF0oal-O_v!)yW(I?mX0&ibuX(m=A{9YtX4q6xkqhrW6BTPXPwPsX)YQ(1aNmD*l6w3cW$nN9{ObR&(9&iKdVC#eW}YI{bF>%rcqnHH}y%eGRTPxBp@9@Y;$U=7TYdUVCi`Dcbf zaL_fCGcOX_$oYGlO*Nwp_`LrNamTvC7~lRH_s4vFH>iTjesuV2cWqWLEXeOvzkx-P zkYR<@*dYU8q2(fy5AUW)j?P47@wp;r^8cxHc+9avtCIN63a%vKT|6ksV(|#+&1_gEzM8+R^~qwqc!>dm)4m3wk+bssgJk9C#)N8h5l$# zsEqq{N}iIQ`_1c2=bL%Beb&634OKThn|T^~ zZZ|8pw$}erE{TJo%z5qhcP6FIyC`pVn65Avt>Uk=8l=!a1&t0%TGz|?M#1iBt~J$r z^KADnbr0WNIl*L@JKL*Ud7RjMut_u@VSOfM7W&UcD-8UP&5Bc?R^u_tpG6HU7~cPl zQurQkuD!`eu~Q4EUHm%27v?g;+CqLcW&9p^CHaW|s;fm1#9Cx$T#>h+5o!7U-2di2 z_5WKp`wead*a049Ib8+VJN7X-%jqI|1&9O6mkQ08O_Mjhj=s`^5s*{1s_1|xS=^rx z?<%p57{qHVl`_=3fYI}Gg!7ErunepP;G;4mZ2=w@taSC|C{~_0AOGcVg~x3%A1M?0PP^Y z3%JheC+P-}9vvOT(f>A-{`;ZfUypqM8cL&Xs8(BKpwbMTSxReV|+eLpp{ zaTckE@ULx5b(uXi`eGRKWr;#!zdj*7jt6lIh{09zLQ+9;CQzljrrhe@ZJu_K@B4sc zHiY3D#uo0b1{hin`>h-2apNZFmFTX-SS6ih2XcgWtfM+=_`B+Mj41Qsv9}DrJ6^Qx z#3E3z7~ZJUSec}J5F?r-biQ#VMP3POentt6Hb?o*It;@EjrIm%rfc$U9svhP43|Zw z2T7uK4CF3-QcUVLSTl1@l>JtphY-@rhz~HwR57Dp6;1e1?5Y5UQ0Q=@F^NaTWP})P z5yCv01`>SNVLTKn0em9H{Cx<@e3@__95N%xrSCz(-@-g$9lVWyfFXJE+ExZaWHWIK z_-x@*#WgM133|}o(>T#OwkIh{7X>4gKV{rWG?YxP=8|8kzQ@169MTZ~`D`7cp5fNq zlu>QCQB$`NFVgZLg1&KwGQ?6%&YpEh6+5C?l`JM_`!OgJbk9SY)8&zzdl*}SPLRKa zQ7*I=Cic?8-uTZ*>1o{%sZ=h{kZovp{H7m-_wzzH1m*P^{Zzoy*OABr3$gyjbK>5` zr*OGV5b2co-rm=;Iszu`ys-Y(Q?9sHJVf-E_u*3x9@Zlxk}?@D%^XknI`|6^99B{! zkz!RN<}L3^TP7d;n2=~OcvYHHZ}RX#)1=;U#d|NfUKp+r2RwRh~LSE<)fDzD*wwG;x%G8{0onu?dIxp$A>uZ@?+V(sIBDR?;u)}t_Pd2ycB z9E7@;^E;aN951Hu!;fo%Ffgxh3k`R}Rv|MucL>NL@=tOf27dmf%2Sxi*x>#J~u<`R#doUy;I9eV$)_};X|u|(w0x2vU(ruDCW`TKjTjLEN1V>6FogHRnHIVh}= z=)G{>G4gs0WGYF{D}Kd=b7BiXWsTvi08E##0BIccdNC70CFKEyv*Nb8%u!Wav z#c^>$F+lI#q*eVy*jO2FoQ#3lmBAVw_;1`IeB;1-x916QOa`%i7 zQurnaLpWN%+$Q9d^lX^d1rY3V&znz*4knf1=0F~&a`=P`F{e-#JS_mAL5gEIRyzkJ zptLe+YJM5~h=YC2qv_@eIYfyJ4xf$Kv4zWaTEc?{k)}BWlqQAK8xL$fng_pgtOC97 zSCFvax77cIx)795bL?Y@<()`A?=vtNCbafx>-=to!^Mk1l>*)5zg>=dYc*c4gs9N0 zh&!F&7A*XP2SUol6XrW;3Zgn#wpU&Xt0`PT&~AZ!cS1>0JZaNxJ#6)RaG5Uv7~L?T zM%I;HIduWJhkwkSoXV=7=m(D}ah7Imx`053?=U${&#TzBV9t1XroIe8 z%$>vhKAu=w5z|$*Krg~YFD6NY1T1qnd{MQ&Nqxd!^A@U~`PMG0y-0adgXV8i62wnT zf1N~F?3b_NFZ75CtwcTKGgS}FaAv&Ky}xNxFG>v7pHi%9w5}y+*JwgleR!LZ`&C+; zsU#g=KL^XB8U~+&o9Syr6 ztV-@vuO+RrQ%XA2L4c2n;k;qR=;V+al9mdtO_NCBoga@<39W)G`NTM0S@c>GvjEAf z0wC{G6mT&TaLOwflDGKqPBZZ4?HPc(Qf7tQHwPjT!a5=+&%wTz69gqYWg2lnx3x4O zJen95*FW_T3VK#xkJ5WGIT+%DK}?Q`u*>QXMfDlE8yoI31#|V7+*T`%tKVeWnm*pW z{lkZTR^!6#JO85m!*dC`UXKE~?)Q?2g_5;+6`zvnvj-bXZ)hb5K^m!|YdG+@Lb3Ce zitca{Pf{n`nKVw5)fL8AoZ2yH8(7qwqaQegfW52Ucy!-K7iRX-zm{i)nJ-psKfIZyIk1y^T8-W20lDZ(XUaFZ7S}E*7w9$ne_T0 zIh3anN)F+7!u#8&nE_r~7@u!`hGF>9a($9=!7aUzkG}|WEjQ)K`rf=%O?=_LP$gUy z!V+PMWW$j}_Zy#R79NtJ-}JnzP~M^6XQCIq+=9a9UqX(`G7jl*x390J{{Da~F2u@)uWr}mpmg3LK5t)X_Q*k8@zb8~ zxbOB=kI78Jv&7*8RdX=4w7o!m*_6cYqA|jWd zM~D?%xguRmRPH6J(unH&L`@-*mOe?F&i6$o%B+W=xE*D2KZI|ZXGuZCramDc=2Cba zFZ&M3Kro5FSKA!tu8mTPs!cM&@r;dLHS-{O;;y=rNGIdaoM)3fijy&oNyl(0I=RVb zaXyCoJl1i^ZjJVIejiXTkD3Cn)7YgT+$H|IsrFsT_&6Rt{nQc5sCoBf^;D9rN6NKg zo^VESihFMge-Jsb@p@)2x#lOiNHH~TEMa6W<+?{&CC!!Kk?u`P4(~o!fba=dOf&nb zb6$~rS)Vs|EX}_+JuoQkTVO^$BD8~^-uN+XLN}cpM=lV`s4vd6hz-%4vrNLJ^!HkZ z@gkkaMg3^A#_a7U>7Kd{Q)4NN52VX{S;ljh#`bS$=tqIaU8fpT-qWpm zBW`@8rOXCp@hW8>(zD+wo|jCEI`GJ&kgo!#PId-n*$qdn%4V|Da-RLnLCzC-7->-- zf^y#nWlN0bZv7-LdnEa;WimW+o2=rsn(RN*bDGKNU+9;%wKEW>$ShZgx(4w=23aEH zbfqi#M~m}=>bzu|+>FxFSXtdnP8Ay9vV$()oOZhzc93W>pFSsd<_aw`w%0Y`isjD8 z&Fdva(w{Os4$@>QRQ71 z%GlCMlj%hd=8GC=H%H+4ZLHGXN>&e77~gA#_p`9DFW z4N6uz2d8~|PH*VDwF>9|?(>l{sDSh()x_oeJ(aqybo$hV+fa}4gQoZoNAsOMZmo{T z|17=<6TZbYQ5}(-r5<1ABzzkje~XEm`oULa=T^izU%Z}H{=KQ{%R#|yL@k$mZ5wMf zs;|hWuGaE%G4Zkw>~qEDe40l3O~sNr!T7vi7b>GYYM`Yx6|7ZT7P-d3Wm}&L67~z% z8;hg(%RsaO|AQ*qbo|Gr0AZ1Y=G>DAR{qnv{9lWsdI*K{vnmfd8%7Y7eT=4tr--zf z@5!dLRM=hn9OY=cxQ4v6w9^Do0U-l|P&$@4>e;>?-@ffE_B2=Q*%5-^iWn6nFWAA}hG!2$aoi7w zaqo+t{n#$)CqYLE=|_ORf+P!*+Yx0QY-Lh_Gp@oAoDkC!lF0X{^IY82K z#EBGf;d6R?8}G(yg!+ z1^kWz5quB3;SH+|pomcDvfW!lRq%r#e=x`kY6S9fX1S zNi#_&Dml<_5NmY4<4^fS&ezEIrs{)+D0;Q}=6m%mX^m=s4NwjA*O10vuqL<*2KCoO z)M#?7YMLBFN}Fk2_tjEd1VDfsg#Ga+!{EP}7#zG##g5|Ky+>=jt9FT*(bX(da9H67|Tw;E~1_ zxW5bHf;6%o@nS_n^(n_x?yI#fKK}cxrM<;rzvlR1S8undFB}DVh-c3VhYdXIc{73M zSi`t@AyLc##%QcClZCQ}Z7dLzaWPdWFja9eRfn2E&}QeI%=Bsjg8)h_+{kXv+_AvU zT4&fn)S7_F1XdCn^U0*pP|r zo#rzEc4Inrv(f(Z+9R)LV#@9f+cUI5r?$-XwnlQq#w$dgIIAML3MD)abzzR+dzx)0 zfl-9OpcKgOuar~v=;#|gl-8`12EVgrhm-a>XE{rxf^PqjRu|jCi;jgZCuUvj`CU_N z0l|@8%6D@PDvQPQ$9etFpC8_E{ls&_JQ^@2*YtI(a26W#je}U|IsFk`{n2MGZDSJyaNR;9hNX8Fw8M9 zWBY}0q38T1T_CK-V>)x3&2f?k$q`-^7|*IS_I3uRJbDaGRpk?(fAQzd)46Dyt>|)X)VkF* z_tOH9oXfF#irNgS;L!T4pMu0hzcuX^vN!r6d_5*yPjS*bwlz9-MFFYS6AO76yOW3{ zD4_V>p1^7zwb&ZFuX5$^&)d&mmcsOo`insg@P50TZ;=u!8uSFJJ2J!yIUAceVZ_^X z$oFba{G-~6w8?wC;&ms?Lzv%n=uO_kkJl&d-fK#%wk+Z+SngY)395fVLW-+K?^d(b zrZxSDCMIj_+E1L;=gU!_w&2AFw zXCE~;meyAbSNf`Fbj8)z8Lo%^T@UrhJoO?~X`v$Vb7~lEJ^azfgd6MPYz2NIRqxX( zoqpve{k@dPsGz6cs7*tt;OC28^JYuWU*+wi-@Nu|u*B`gSEj5`b=X&zMJ&kwT3hV% zIn3mo^?ZD}iIlrxcFm0%?}ICE)3WP*HbPC#6*s%KRBQ-&=D>f|wsY0dE^LgP{O~-r zBxIl7%GK~;w$5y#M*h_1^tCnm@W%LyvSN`>UJo*l#z(*U`^DU(K4Rw9P{S8R)^n%R z=*y438gXru{Y{^*xKa5x|8{7|=CyB{?{eq3zI{;tmROs$=kx8|jc-tm7082h&gPFF zc{e)7Gp-t5wUsC`ao^&5OtEpt)}HkF0rty8tIw7glXoWRz(&gz9|&i6 zW&Upu-dW4yvBH?ze%pf)_={_Tj#Bq9K1k_sFgP4=k^JG{2U`NzqNqq4O;9zO`%2}q z|Mdd`t;6$ohr-ZZo<$_TmyCr2Bs~Xln$kJnDV`}cx>P=2m(?Zcu*Y~ScP>xBf&$h- z0_+N=0M&riFA_flIIAp4Q&}A4Lco5JvVbuRsSqy(O^#H2e&#wgOi=&>md!a-20&vB zf6&Q{wqPkRF93RX`_BOZGDPLPutmXT$ckfG0w|NPjw8DiR#(bM-khLj^18LoxAyerGfDW|%3xWBzj5Kyys!xfyuSX7yqH6DUU)ns!iUS@)5 z$M?$gqlvgTiqkSVxrL^8q1Er}xydq)3TzSVb6Mg%JmWt;q2{=gWNfyiKdq*)RXuWu zXeC%}SQd8H(5r@GxZf$r*>Jt5{&{WwM3>qp2!H{;UM=q<0G zq3;F~87vas`{7LEjHFe?n;r~N{&Ia`_ZGXge0s*Qn_DdGbp@AS0aUI}{edSVg2G5o7T>M7=0s)Yzr}-uA$)h8n60gVb zrtIv+=$y;)P2gsPdeg^p^Vb;5@?+2S5gN{81|uB#=K3`ik<&u{79U1syKIk6nIE;& znG5K$(_2brQbIxgshr;7D`pKzIYTPS zA~~kga@xxs2qqLLm($BSoB;Lpa;_djsiIe)U{73*hgXELFI+H)ibe`Ix?<<}Wp82l z5?D|zc)5+i+BEq?44g-qozlV`WpYI3wcrcd$7h>LmY8Cegs?~jlC+xQe;`)ORV0Vu0d#6D`b6spV_Q`_7yjaVmJsY;IRx!=R7OL zf!mI>WA(hQ^BU0WK&UL-L99;9aUJJCr7BgU(F_noB&f2#u|V@dD$8drkqZqO`ryy} znWF%dT~)IZR(n5vxiA4Za$)@PeekfD+d8e0+<&n|=0h7_LT~smx0O-E6T!g#h&R&h zQD*_JYJ-tY{q?UTZe{#?K5um2S!{s|4{uLKHv(8Mzpc1(w(gg+O-A}d_F?0FV!e); z)Pqm}QFnAr`Da7!6D%7jfaaHK66c`N{5JdV0|cZRGs!><3)if!=XGLK+KP7f*@ecuDq9M1=8V<^U>F+^1jh|1xZ^WUz0hGX!l9Hg znQqI~{B3lY`j&&%Ze<{GQ_3%9&p{Gei%~kNh~?a(f=KUMU656$F;x~VaAxL!K{Lp+ z6s^;I$rqxsqR1kYgBQ4mHrMclfS@@5$N>aN>C8ZeW26gx_#j>eXMeb%yII@z;vOnf z9`EO}Np*~-!vKiDTX(z|6f5+m*G!jtNKS*mTJHWN*sc44YrC{L=W$IsB&V9^@{7(J zF@%p;wiDtaIep>8W2$@H@bu>OD$?;Y)7Cq+86-yhIWQiD7&m;1U z`6&SPxIjf7lKo|TKkG3m4_W?lKnAX%5N>&djvr%}GZVS896?St3Xm3@9~;OWimqj7 z4i*axBCO9B^Y}O*jt6Av`z2v+c9(x($pM12V?a^?gHvf^I+)Kx> z^0cC~SHdS_Jl!*D!s{~NA)(e$qM$FTYUG^(+Oa;@ z^k|Qi#s!&SNyhS1aiI_~{(V!?fZ|^Jo{nTW%7l)N1H`#l8ZN4x4PPNY;g{xYi0xX2 ztnO3T+?L-utS+wWJ-ychPK# zjodR>3fN%(91?1&!1~%1Z?j1!fn--$?TZJ^3(#Q4F%tK8IU0UN?OW`e(Z|@QzX$%@ z5+(fhrUBf&cQTy!YJQGCw%U3-amNH?>wMPjsCsJkULrp zWW-&3wu_=ILObrDZTC_9>pMR4Cf6q)We>zwa{tl&`{U}@jKrPmhm0D@A01Z4$RjLG zb*qx!$5?a|-;%-|keP>Ppu!ErS7WDuz301Q(*S_-p`m*jQdlug1r06ENs|RafKk~9)Q5t|(>i_|01b|>O=F1nM zgR7_nIW%J25RnLioi-PmA@#-PkHi&NS$7Q}`TFB$`s`}Sw)dXC#pv35V~2*TPHc9a zC$oeYBG!LH^~X}q`1U6(LpVEF!t^Dj$au!NEfzzev9r7biS!g(3{;x-q4M z9={xmd5)Pad)inqA=P3vKWtTk#@aofXlc#54#mCY9ZT1=a4{bP?++$FXYq@}VGx8c zdTRVu>eVgybt+46sp(mE8B-j~EUh?x=Hj#ana}!KPawlj^cI|WkYIfo z1WhZpPT$KsWhB{HiC0^;?kCqCB5gh%+{=hahxyq&iQYqsAV?hBYF-Xv9MYsvV*1J>pOpBV+G8896T<-@f1T{P0Qdb~`C#B?fNQK_M!2F!*r;B^y(E$***sunWDJL9{?`6RT5py}fQq-h~t<-CnR|Rbz@x8Rn zHgG?AzGRlR^&A$_n;MB{j$w6(d6qN1V5N{WFtt~W0v3qVhTct z8ca#iT?cC%x}O@<*ga!D*D2>U(m6SYL^!6opEiX$bCqix9x^Gos82 zh1r`iR5*4_Hq0(R_NdMz;pyGW?>=5GhCeYMEaSZMoS9JT^KSp)##1KdOM7b5)uv_C*C7uo8G8umAi&blB<-Jtcf={zx~l4QaS|Hzd|>vOC9c#pdo zARWb8jPRFhOuHa%ehk-Iv7c5c#3rXmFvb)3=-l-no zPK9vogMRAgsMGo6dketi5;%_7;6M!e!Cgk>{uKwvL{<@maIzgVU9a(T2<)bSlQ%+|(I|_NI+4ii3496>qldOQA8=ftkUu4Xdh$NFt z15;vx06d+2s|1eZuM1Cq9aj`rQWQTPSdv4uI86%OhZ)hCRp&`V(1|}j-F_{<>$I|l zmT>~v^pg>#E45|g!s%(`ki!j%E9iV;_ zM83qw$ZPhU=jCgs%j&>qB*51}FE3B>YTjUd^}4028Zi^f zyuIarq7H2B6F@XJWHTsj|Dp}srW%^e0J)||nQYDp*vKJ6veohB27&S|)t#a86E_Rp zJ`=C`l(2JMn(q0!q041vL)@o^el@8rrhnB8CAR*3j@w~wGr=c@YQbZd@_j>~`gFKv zh#Wf1Pgn|y7F|n09GO?Ei|1_04JDYc3gH7bb+;ftv(DG+!2(%X8W8a7>(K(CjR05& zePlRZu}PP$uA?NX$LNty;ZlWtIbc(z3bwxxlC$1lOb-hT&UzJ2tB%ilA%q9fRbURl zi1JzJ$8E@C6|h&f)nE(SiVi#2PV(WMQ;%rGpk>#$hMoKcsDwxFFE(H*%MV&eLbHWdbb;8fj7CIFHsZ`fI!EpD#g5Ot;@`Fn6fRZ0&;*z99kUlU%FgF< zT`ESh@7*HDfHYyd>Oel<@uEdjJt==sWU_j6Mdhw_L$pszr_Iwn+qpfvk9#M7?%Bh? zI|zPvRQT?s_uaWD;PET>x36qye1@Mcaq`^Ygt--Ooc8sw`tA+)bA3E;vfLQ{)yDU! zkJo*3KMkQ%VQ0?HeLtt+2sFC99~PKVtRVcQ5~lD)OPV{BUhpytrg=<>z;ghQ&GPe&TWL<>`{5Wki@cVw<^aJ{Ig4)kSyPw@wKf0g#6gN2ISL6EJ4{gd` zUB1M5jB{pzq%n!d}%RFy{%VHSB~kb_UrDfO%xpsGvU$S zd(-Uv@UM7c*X7&yW1X!w50C9{y?^?1;G|~n_Wk;nJGx=9pJTq(y~@86#xVJNXr1+t zTWzT=rd93rnON|7re(YRWrHM%({LZ1B!&9nbN$ui9E~t{>*i_V?5Uv2%cyjH=`^{| zdQu5r#pguuXdVxA3XNZPIla6jPUeQeXL3m@{Jdfj{+(lx?^QFAKEG5fkFakB``3Nh z0!N$i*$h`L>(avMi2c>V<&!6BG)!QP;P1KNvb;0@xV|e>F>*UmG-{R&3SDPOKG3n^M4tJ+!)|dk?uIn zdR4VcMr5&-G%oU8Dd++A>ZNaJVwg5A}T z@5_aYmVF4L3WVnH>Aly?E`|*S>F_ zBoU>p&Pm}p<_?T(0SEH$*?HBp7rjmVYD}Qj( z<(=6oa~mT>v7z4p{uhfCS$7>EX@N>t8P<#~7GD_nb zWSPS4izWb2EGrB|&j@C9KoK!Cp*NV~uy5{l!N%DSVE+sxQ-iR|(sf3b-cbfQK3E5DYa} zz*q+||07VkfudZdzv>t&JqOICx(u@PzzP&@L3qty!sUChutH6c-;5&-}_c5 z9xYn|b6++jWrR3W$s*Xx6zsP^e=n`YnIJG+=^bNW2Vd^qpeK9HdN>$mIaSsX#EPS2 zMCyYOIzq!jkvR~CU@M+Q2MrM}pEKfXtYpzflXy!jp}SRgt~ALG3$dZ0KEHU1hXSlo z=@g=-Z7wM{Gr-hji-0qkzOujp!0AHc(o_nO36a-)kei|`wgz5!Q!nd|$FMn|^Heu*EyG)w^F*~b-o&Y#g8V)9C$;;Rtc%u&Fz1GKBnOn=B(Mf&UDc4?dIW1cVvBqUKcLWi+iN9fAyaG#Zgv*Db zq0krE#qE_z29cduxj2!TIS8{-TXUrM1|=C=@b*iS*~i3IrubnL?0PIzgb4}7sA4!L za)_YTN|uEJzgneVCSMD&wMC%Tv;yg+5LT%2QxDV=1XuQt6d<-HPfZJ)g5owN36 z>Pk=HU2A@D5DB*|P*?10FFFWTsO>~A8vnpaZ>7g!7OIrvu!_Cd?5mZllHGB`zT<A}o+45Wm3ZdgC&2K;uQ5$&|5<_srC+Go37G=IIcX}T}5u)34|_%a0m zI}nM2N!6gKrion;xqLzB{&ow9ozIsjx$k?`sa_vY{R>gbE?L$ZQC#Y#5CC&6KohOc z`|43l^43EDc#Ibd@jd_e%pHWUrj;6FEDrh1-)9%e=qJhgP|paCj5^);8g1|{L$v*G z{wx)H$IisaBH#Q2(PfGK{2-TytSNUQ#%g`)6Fh)A%tWx7@lKLmKe72629v}BG%<)^A= zV}^$q5D0+>o6oZ?pZB;!Mf z@L!Vg^I<8fu&K8=f*%AA7dNG11f%htAjil{*mqJR&{nVsU~1|uX3}K8v~8a?h~eQt z>vW>gP80!ECij2)(*&iL&~lIohQt?F!r`{6^QgpB5yZVmkgoNYtCdm2(e|G#uMgs- zU!LNWWjMeQAfzLoM76lwrkU(o!9d?F?0%V`5+UmC>4W*#qK=qD{@SQ3qGl}RY6ng| z7MSCIWmf$vVIQ(Bgk?G67QZ71JVHbReIhV8kGr{M{XqJ}H7ia!hR+xPD^h?%D%O-J8T%cf!k6a}z*Ez8+~;XGUdqbZCF zE}U^7+U!g5#9W?xE^PZ}0Aw~y4t2bih+9AV_nas@9mK%_066?xsrRZql?4Y3nux{A zAN?;;1%q=XIp7sH|B69>%k?QG0;?1SqKF4Sr@+US#Zc><+JxOT3=#p+do#!-fDZ#V zg!jls>cYPrV%UJ}E##D4Po>)DHM#HB%y2-Z0Qb{E{?=rG8v!xiGc#75W#6J4c|L4x z4w30FTfc=7&^9~f%dd?v<;U0Y=x{^nU=t(a)uD!j>5t*fP;f5K+n0FlPoTG#xZkQ_ zyKYHxm{XViN;!0Sz!W_9K48ERA4sgLTnqA^>w0LfD1w>4EJ(nXLwtUjX<&d>Oi%Mui+`zb_w>af3V z_Z|&3e$HHM>h1;J10*)(uE(K~6ZaqLk$7`&0jxmxIf0$}!+Xr+ByMk?Dak>lG64!I z^MZ{_lYM<|iD!;|b4k+r`y>NynFLbVxm$%I-n_ES9AA|x)SIzcq8xknxX*bUL#IF- z!BrFXw;wRS<$S)G0&KsBiSHVgtlVU%)O-_hv!1e(zzpZ}I81o`gWMD+rfj7>#j0<1 zgi5%@@{;_C!b>~Hu!XjNR=#s{1S(6?&diojR_Ur&zITJnr&+`&_Q6#1Wx6n^fDaTu zKE&Uj#A7RPuBo2Y(B=NMi`LPDswQ_AgKDQGbktP!X-wQ=a>B>ocl`z zY@a+e8lTiusN%&(wXqywWlnmZhtaJT?@cZqDCVw8Fp}Vxa^AdPV=Y0lHRW{2k8JlM zImVF=f7O=R+F@TDiYvalB2XydmnWiUc`k=~7UzCc6XNkDD0#Gd(n3*c>ZbIs@|Th% zwsR%7L+K_HQsP+YOL->PJXuGc&whFGpQKF*^y&!e6@^=BIM z*N4y~%*%?-H{aK2y)Xk2g@Q#tuo-P>eV^8_E*`AoLF!}Ggu_7z9pI07$o()iP{-hr zR~oQ4b{nYtW(pq1F71nHLuB?J!8cgy4RCVKPO;2&SzJsVzhHf z0|OE(@V+?dQ)q(a35SX{lC-G9x?`rtYKIlP2StRmq*b(JYA$kRg7w}E8wEk6#X#JR zW=CY58D~kl6oNU2tE0H9lUgC{3Bhn|NV9g>cx+gF4dZO=>N21b;i)BmQ46;8(LI@8 zMLCJ>xvAlE(}bHOnE+9hhgz!7v`%4Xb>0y8gv#ZOT=gFE@{4iXH?Alrpt!uM!#MY z8U8_0n)mwT*R# zQ;vjN1oMm&r?e5Q{ByHVR3JJhC@m-WW)_a=S2QO^*7b^)qao!>&s&#Xr#u30ywq)da<b+fmt9@0kOoN8Jn>rs)zZ_d1>j-1$3S*c>>f@!Q&~H`@zIjP+j9fSa?uq?H zvi$<#j!~Le-jfnO2M*!lUN2Urh|zrYIINr1-}?{$S~;mJ7ie(RpH;2p zd{6DT7Z|-1l(iJRBK@L+F=SoF>(^hWv!$0L%i;9PXx`<#2AfxDTY4D@yFZwVLd(&n z{D!;?{O#UiYkf>7QZS<1ceBv?GO6T$v9clREPnkG`dHo(VuW*h%(M2`clO#9{bJVn z6z$>67!(K;p=$U}Fr=S5vsGO@zwFece9{Qjaw@-#Di!LbHqNhb!RJ@{evYp?r>_f2 ze8p1pCO=Pa;EAjH`8}XKAd=Y{lS1?u&oYe>waNo2`uN<95Rj6%sa(;O;OHm@roBed0aFwM!f((Ci< z$oyh_M@H4>8XJX5VWxgw`)soI8p`v=AM8U&IsYFhu1p~Oam0pU1nssvtn!|-7s&LP ztqi!I+&bdMp^Mq=>V55c;(k9*d0I4MuX8K0C=N?^V0mhfj~Z)cBWslwpFp3{^^Om& zO?)aKO@7f)Ya^AHIzwGJYoO_3=M8-Xp!VeGUhP6zW6d@=!6C%b6F|x5#4I@OKD2r^ zBdR|GCg~UnSptyrXi)F0O`R6d_g}K?vQ0~@mwk-*oHpGHQ|}YIR#totRC}&s^!!=b z^>_v_RXd7QGepWjNxB#~txfyP?t^sP2QlgJ(H!Todi(KF=bmx4$rZM#){rsDLM+T- zHo13}*MVPTee63IIpnITP3kFcIj{$pwJ3F$9Uc4QK6eX|Ag18Vr-}g5v$?(StzB;= z>k+36;|OY3(%htE=s*oukNlF&ckX zSr0VhP7uF~*&=q|Bna{K-4*MBveY&8(G20tS%2hz z{7u7hHFycwF^xc35~p9}FoYqhm*rmN&my0~lI5!yO*C*= z!LK9OoS~xTeMErJ@%QMNa5YBME6hFmXKE#`ycRHJ0V0PJb)7iAYc_GRJ2SomNiBq^ z|H^%v3b!Jixv!5GOpTQNBATnU+*duKjr-s<^BUDQZdvO`4OaH__v&qDs#BG&PZAlI zl{6{uSx-LQRcCUU6JX#{Bf;;B&T6rSo+L+2h02&&$(_@9Dl zqW)7rqI-+EoW+kx4NV3&b`G!j@0qVB4Gn)GywsVIFK_Q#HY>=`^G#H^Kv^V-w{ak{ zp{7%B;?~D&A(-G}Y3*DCIukwyDa(9pcJR;mLCq+x+NuJnA)Vc5lU;JHR0SN9YsEUj zmdy^J$t$6K%2BA%V6ois8Ft?jxz!hH@8Y*+|NQ=lZIJqCIa}a?&Z?LOZ66x$pZjKj zHgK$?jGPVPqRp)3PEE$Xre3~kFEi9zNvowk%R)sBi65fXQVOnm74ExK7`Q>~_(MI+ zlzhp`6j>f7)|9Lq|1}mUSTwx!%ss!%yts7(S5d2YkY~Als{whn;m@B7JfZ5 z4h&fFXuD~WIAp7A*@)HpG#=*#$I19+dH*vJ^JkCmG`@fmRNUVM~ zipm=k$$o+()3PL%zDAJ1g0Qek&B)x-U2W9!5sXg&9J04bSLHq^$m5F^a_7?%)W17x z9g}S=2=cU`j#f{-M{=LGEDHfl=>=>A6p zOL8kb94f*q>MlP4XPyJ)#RzM%D@5p@egb8v#E2#7joWB;VzQW`kz)H8U3}utxe2L~ z3NB?LTZm6&nR_Nm+~JFV?%2oZ-4g^Il?nW*F)_M=q>(D^t6Cf;wn66?hc1gT7t@ zqd{hA%S(syf6ur%;ZLWS7B+d0*7qPvE=7X$P7hf0Kj}`jV0$&5oRW`6q&-XuXg8fm z=|Sl~!LzR%Px~w(cf=#;a%s}~KP-WNd8OIAHxUW#=a3qf!sIhcNC1} zDdnv7?r8ZCGM~QDk$`sgK=He}2enTB{#y09@9Stuch20JAcEzz{)sm!xJTc3?j|kJ zC&v4frul6yPw-K+L}r>RyM_jXkTH;X#Q9SKJPve8(#I5`RF>ed2@yV&z(h|_vu;@r z%kMP1c!(^p&EV8HrjBxY*&awl=5@Jdk7x?&ndaU0Z%2~YheJq;`Ckq}b z|H+#U{d-&lWOqlw@@K;Nh^RvfoDht-85a4IGR{J{j%@yH1|N|&U-A!~`H{KI?3OC- z^dHfL>~r}Yohl=*ALfylh{{`1$rfr6EOI4~>=$wN_Tdq)@j6z?Lc62%)gy2kOgN=0 zwzc6A_EFUN`BLwc&O7_2h}RfYAB{@@Re1dxo4EWKwR|OQ0X)rx@k%Sc5}1jS@wT($ znPmx3$8>*43oz5IQ{#~7K1=lGBu10C`tXAr3-^t=ZE4TWW5b2_-ObxN=c$%XD(Rtz zO!D@~hM2f&;S}GrH_taIhuepQMGvjY+QHFHvC6wHLvh<449mOPs<{`2G6;e?jJd<| zGas&6y+u33(LC-Fb|-4$!;b89hgN!7k}nSvv@9At>y>i6y@Q~A3lPyRABLG9G$9rL zbRewCiQLY&IIr7@mp!&m{jD@fNbqDUS4gVK1Wi0i8RBaFMuJlEypQ9_S(oZ1HN~5n zV)%`__P2vIiE38m4$X50fdgEww`%zooz-c-mNzx#WAzrtbclx9mtagu=Vs2W?jK^D zPZLwudbD=?SoBdT+G@X$a@LV@@6k!0zEuLa)cUrSBoh5J&yuuFdMO$XyJpu_&bnY} zf6!tfU&}(d?rjW-OSvS4vGpfH(LIV0sv$p2osgi_@on~}a#ja_&PR=imn_Vq5I7{o zXJ8)9rCN$TZx3MgE19?gl2!po!z9eZg{Ap7O?w*!q%MK%VQHmMw4X~@6;QzG1~8X1 z{l5~-HS;v(f-e$(ES9`=0`Kk0BPJC0Xngqa=;8995@4WrWsCN zC{9*v454iV>o`;8*4c!i+1Xqu>uM-o9gvs#Kv?^(M;f{Qkyq9nKn&`5q7dL7;sTXB zh`%uI9xZs%SBSUJ7pbp+ixLq66b{wA<>L%l++-@pfv+bKrmn0zC>BUxRsF3%X=}Sr(I;a?|W*Jzi7#$8lp@$5C5{xiWCVvx# zm(5JE63p>frYvgaXlfQ=Q6{{HFLT)}LoGE+Y8qov8l%}POIsS#D{8hb6ShKMw$?+| z*2B4}S!N0>`x_JXW)qHwX&ep`tltmW>!~?^nQ&Ijax^w`Zq0HY`y!~Gastyi|41O2 z(-Bv*4G=YO)_tzu5UZd+RxPD~1gyC+FVgKkDvFm&^tPrrjg!o6yW0`%mv9>uq^xrd zk90aW>qBG^g6*FRu~9>k2#7p$6LU|O>e{Q|eLTmPUit_%@`dSPV$e&NS`W6Kmv%9O2vo{A zNyZ+9UOtajq3E4#1+8ME znc~ZN#V52%Rqp^b$8$B$tyOLBSIZ?eaQ=-aLgSDtpx1g9$P>fRQ^nU7HlE@i#u6W~~D8l^^m$odUNC1FF zfHK8>=ALL*yiB4-@U+G;KvOGIQ(hfh9?s|{rol{zdHHFoHdh-0$n{3qe%eLFXuC~>#-{0<|g~Md4{j9(JpufX( zmi@lE<9e3kW|qUoC&zhz$KF=JxwO-bh0~$5Gu3;Ct5e4*?VmF@Pi*G>K&(PwA& zgiW)0$OG;7ZsQe5g@NnsKeZ765@W)=0G7?X7kv(-&E4yR;M5@=g3n6M4Q1|I{k?#c zcobzza1wFDO2FmCca3>97wL?m5K9NJWN%B@ zg2EHsHz9;Fcz~6U&0p6b%Ll&(e19-_nmw{LHqo4uA=7d8*+p^u4hMUl1!N%u|ELjE zp8#L0z~I23P{yF>oS>IhfjP3lg>8X}vOyJX!GUeh(Pu$r5I=0D#aegqa^&Ag*Gahw6 zQgI;?WgVs4&W*vcOrc>r4M?^3(b~BWKFSzR!HmkW@rLB=dqC5JD%RUTYL;IJE?16D zAbUP=eJYm9@O&fTJTAkU`9qB%=#;3g!-?>TbcBy7q(6)oW~Mo}}_P(wGxqY>t* zC6vn(e~TZ{jF+%N2M~YTQ_W;8ZRDb!odwCRHk7zC>~05MW4n zmIHJ4{k&|ii!9gR?0DxK-{9;=9a+KhIk6YnFKlw+<#V%`^PXMg;Bz{1n5l9znDYyn zp_TIa$$9xjd9R{ZUcKtb{b=(ll)0eZrl3DBFSY|Pb5W4DQdqlE(0h?PoA-KS<<+~3 ze8QL4eqPb{i=xrsqBi;BtKj0(j^g2qVxVma`SX%rDrwBA5AD^N7|ei zsNtl)U=gyZPo=;1UjBx($<-A6*GE{)ExsvCo zs$g4*mT?3d53E?BI<~WV7+doTSlgOktC-J17?|`X&V=6O!Ux>trtW8Bsv-|lVBX#2 ztbE=n!ez$2X~6TYR;tY?L`&SHw>!m!jRP%3*Z0VYr}FzHRXL)mf-oe_WknSc7#$7| zL9s6YS!jUEQ++KacC9vDEk=s1R;-0?SFMk_S|75$_gZcBP<$Wys?DFZ4gI3+Sr;He zvF*uK+bnrUvf^sCU3-~bM@CnBd{X}{b*|_RCRs4AIs^@I=y__HVy)Fgtrv0oVIB+?D@{&~49IHq!Qb}6?}YYt?-VqwAdu1u7q<8#V|*Ric`(f7tY30%rSP)T19{b z9Oj~Nv$WlF?CW9*g|oC=^P=5S>g#jz%5x^{^G55lHV&U03Kv|vKZ!Xk%HDiZ4&{G* zGvlHB>Dl^{^!kE}!;*)?@=Nw5Y4&BS(51BQ1w1NrIV*IrV?$Tpv9ERAtW7Gf4=b;Y-mETluad9bVJ(FXLu|^MAPoq*B4esou-_RZ<7L=e7>8kU#|R0 z*v_4Kt%GNui^0!(;ZHobt4g+wRL1i7=_$E9(7luaJ>Q(dC^ele3vdSM|Hl6elK23= zWnsi5U;9|#AmPqIFM&HPJ^N?`*dF^GAAM_=Ic%Tp`($c3sRC%DU+bA*Fz;6$4!#l^ z8YKKdcIBrpsi+~G2YREe=X;kUIm98r$%MQI%ZNaaHsEIEHjYu8$UFGsyonP<&QlHi zj3MU<>;7q;$X~0ECtWpvA8wrbemsp=`y0G*ruFhHvgpJN|2H0g7U*=E`tsbS=)%S6 zEC)Xq?sOSlbXoTCtd{et@#SUf$BX)nt1kRSzv|gA=S8a1g$?J8*T?4cjq~}9o28Aj zPan@$@YkC~|Gwe>)z<&pD8d83CJ<&lvqBC@baC_%B$Qm{BQq|2XcCyAz4ak-Fopqn zn@2zs%>687B1CD_I4)D~bx@u#o*aO3x(>A?KG@q!y|&aay0Pz61Km9h_y2i9&!a(p z*hlw^txS_viw+SZk1eLg)BHyrA2Hi3%yNoh@s3Nk)o(q0E%O%sH9q8o8Z`hy@6nD@ zX~9dP9;+8y0}{l?2rYNW6(;HwnbPX5K-DkpTd7o=L8cfD8u=}Z9(2VxO;tsnH=UCt zuPjSh&x1S5VXVD8M=gSmFIS4e96$fm9il3C1B^} z+>`9GY!bb^=WM0}5tN}UKdUQV=l`s!@6jVr@O#Jlj9cBOL^A)bw^Eh=ozvcZOoD@x zDL;@-Gi|Kve2$N*ayTzdQNBUk9;*6KJwNUFQ7(HJNn1v$DJKggVuv-X`=HXj zjJtAYnOkvmT1=FUA0hlVs2fmM0>@^pO@Yqe2Ya6 zjQ_6GNS)AS#QHQ3J67}wjH_JL$+*$YXu{2~^ZMS%-co1>MZn}Ve=AF|RUl94JKqjKe{hi+?-Mx(~AWc(%)W z>BEgllA@wOLQS0i%EO6h4yIrB5vQn}W7ThqxJM9+6kGH}644X#C5GTlur5{u*BXoX z>AJCKTpGa!Xe3pG$64?Nsj%LTdhvz0C}!kL@uy8A0A*c7n}8_$()wL-kUNsL&UAnU z-!dKW{)N+Do@!0Th2jVnb2Q&?Usw=ZpH@o$>QD8D3X3bhpC&72AmafY!_9}@ar!*m zs%H$Eq%;@-6gw~XXvd7NyKlJpHkT^-m~q0>%nLzK=TFovDo3p>Hq(f4uDHsjHvr}( zOi7F&u*w4|3F#R3%f3URgpK3?p-5d+(lahD$`t;@Pp`~oBxf(os5p>y z&V74U3=$O(G{QtHRF^2%Nx8=iRYiy@_?0$BR%;#$PC`sFlNmmJxudGrg_*(O^Bb@D z`B=&4GHF`U>aX0?ZkXj(bZIK`AHUIik}&^b@h8~ik-Onb2!Yx5uhtZ;F-c8WC>Qd7 zqwiH?Rs{J}t><53USDI;nDD92)1S}{T4VJQve=a1U*{%TYcrj&I5*%<{n+afeS>Ab zguM&3kGpyqsBckw!GhePomlQ4WLe`wE8u|~$nFQXBK>JU$7Q=ln~yk&nRpq;E+CpY zq!am{m)U)1ZH0thvbWuapwMN~4|AyG8IDqyZbPlfx5KJGkyH`g4G;LO zqvbAvunA`wRsN=-x0<{)_akjhtbgkanC1USW(~=1AW!UjN21TDwzYH;1`PK;~ zi&i7MEi_9WSVs(7EPTs1)0?QDOT_u9dg+(cgbVD~EiyB3th72RF*uXiPD{;Q;HL@A z4&&wa;q|x*^NTeeOKi8At?1M#8DUBvu zoC~?HbHtbEK^JlQ8ki*M5_0Yf@#I5ev8=iX9>4HHx+vp!h}?+9=Tk6)0SOAWvrAE- zd$UyPPa~J#=y1NN?hDit?WtZ@BN1!ABhR+e`2pt&*D6MFPEhAAp`4kI00UH+&XA`{ zrHc(_(zP9BUF6O)D_sE~5ThUH4u*UBA1Ij&an&ku z?7v%IsUP-QqUU{n6S;MUK5=NR&qTPdTzgRJL#Mox1Ty|1(@!ef$kJ*(2E8J zQ&XC(RdQN{fLBYaxI4%}@5_s3xB+wRC&H?h9E$if8{ZO#0?NJ&2@kg=5^laSh_9=xB!vl~ij+>RqGZ0FL zOp&A`+HI;$QQdWc`Ij>!H9iw16fQJ+hcu2iXFNzOPNorhN6cVk9ohQl;Dj<7$ND84 z1D`XblJcPqY*@q+S{7n%F91N>#iXFfmA@|Iq1W4Dc#93^A6jmER1XAnUz|69qN++7 z48SK`zqx+sPJfzvKGqUpa!q|COIjKLdPV~El)?u`ngt6|gL1SL<9f)D847I1ebs89Hf(7C=9O2Kj&X0q(_4jZ6wWIJ$*2bf6aQoM~@0MnWe*bNayNg(Qd{-eVOAfUU&QBpE-AYcFQ zKH!65%JJ`1mhFNa^U<>c$@A9cLHy1E_mdM$JWjs``oKX3YNRQDgD8D{vxcqqsXbm+ zK!Qi$FV3kc1pFXi11hNqG^%Q^HjhD;gp7CA`B z1bwP~)g{6$n!q?L9+GHG@}4U^o`$=eA$5o^4k~~`iEBUFPDQDu|2Y6NT~NogXO9j? zX^9hdn!QnZwx?T;x)13dR;2XE@d7~Bs-6=TEGvX0%>W`vFu9NOIPderLS{r64ya&K z8li%DZ{tAc2b8E{RGLQ)iBFQ8d;Y|ke|hj-rWKO-84_hRXk%`+|0r^L*Ykc3Y^n@o zIpc47CsQ;pvtPGhP*4$S>9dv_W*|;F8XV(M4N4fY+|q$t+K>ccJ@R5=omSw#v_;o8gu$anYlpd)f}XAq~- zeyAVJ9JrdK9Qa%2A%O#eBXVaL_)t zFFB(JOI4QleXVag@CN`0RiNbJ^yv?2dVSeSKd?Y`PatwE`rwR5aJmgtIrDuM{=cv2t2$7~!YCoas=K)0H zK9nVJ$fWZ<^0&%p&#H?}+D#lK-UND}7U|*gCeoHgGnb4@POGHmp~Eq35<^~S3_VuE zOJ&(sl_qFD#!+B|-gJZ~yzQ*+qOElOO#XZH!B=OhLN$t3U&hB|$?9WulVf$7pPe3} z%XOc7BrQ6PJoLTN_S@I4$d<7NQD;+{gxkf3hYO^>Ar-=hL-EeAiX&2!ex_3&N*_RJ z1vPN|!14Vz5s(e%Lqy|=g1tW4~ZpRnd z1e9D5q|4n*^@1LQb_~j-%D^<;TsCrCG0dF3?%Zvp9JgO!fXoa+S1{oHW(51Vy<9kG z77IPY5=!Y@%F*xsJm=QG}V7fcp7Klh!2i}$&UW~)f^Upr2RQ3)%YZN8el5?sR}>Xj?G(S%c6Ww%2WWJL3-_!E zE8vq62f!B(?D7wN%5zaf*>A=bGe(}F>J zkzv%{U^DShcIJ>y*6?kMA*cIBK5N5ft;7H5M#9;KpCygRtQqNC%llssyV;L8T@Trw zj_^y2JXRX5@EuKhHWI%#D)m9Zr9elDcg#Uw=Sji98-4jueTAAm{8;STSmWN{+k&wO zw=wNK`Fr-Gp8Dgj9*=fYPUx|X7U@rP)+!{1n3jJSDexQZRZ_@j8=p!Vj|q{R`!Ke+ zH}WZIIAdXCUVpMTNq$*>{GR>9H>JMM_G6nkGF=5=4#z%@*;VDzI)|u_uRzwI&ObLi+#;pdHKuDa%=b6 zFR$eW`^EOq!Nv7O{TuBoo|U`%UxFv5qRnUKCs)?kzcfwaxvxamvKBVp8LSQ|Pg!*@ zS51C_{d<^Ps1Vj7_k14*3)QVMoug(U?`q!WDOl;`LgYj;$%u?;Ut;+AS^@wbXtL9yIy4H$<&tHKl2f- z?<4oW8CB?fU*8d}`0n%jyOij6LyPbJVc%bR@5cVy$u=YQ#1N?-0AL5issN?tej-N< z5j%p6bH+d&4zTrs5GtsXF{Dan0Es3t_8A~HV~0`#zw76?8#nc-%YJoH^fTA`+>*f; zV(+z(wNXaz;kz7qn$V46x*7H8i5CVS5e$e}8~|$qOsM>5GW)?U4&Xfi2Gr7|t5FuG z5E8c`AQX^39Kh~FECpAr_x|4WW!o0I@!snTwqd2iaimA(ll;_<7W7*==uc?9(L2#! zf`h;Jq1?95L4x6c_}kiyK0w0!CZ`WjJ$+EX^oI%@ATQp@h#*_ggy(JVaIrMtqi2Bcw%%>x9{E@Kgaron7rj+B$kYk0SW9g}5)j!9m)Fn05 z6ZMTvZO&sUvE#dqCuiQq-i6CEUNh)hf57bc-HZJ%@51)V9oB!V;3T?NzA0}%G57;^ z+&JLa8%Ul8Jvjh7kv)YI>lc$eH6{wUGNt)LLRTa}C^&7O0m}jiLCpm118xZ72X~f& z)&WRYe3l=5gfBiiEc~8<9|$zM2noALce==Pnl0QoFPa{I&3Re;alPWtX4R96SB;ms zA20K#FB|_{Hj7M7%OmkoR2u%>T>2zmY)zbxCI+NPxb|$l>#J7v!*hG8zIl*J|*KuQ*=1QEB*L2Uq%SQym*spiug$99ARxv+6>YMod7g1|BM4W=G~ z-~YBMD`tu%9M|&MFCVxJ#M6u2v0v~t$xu{;Oy>D*Z{?@)JIaim?`ltJIxvLfwfN!2 zh|P=^^{E9P6x3QY4%xqQ)4{@XWI`blH86k+*>!F+(e`kI(<%c{?XNkDV6sovQ`2(r zK&`BMHN)I`r(tC1AigUM|6IoFxKglDcJ#I1W$c0EM{TDK<@3K6KQ>gSow~!W{}MNS z1mbBAumD;fcrVG1cl*63-mV5!3pm9;5;NkE`gi9+>66$M_*d|I@~w9>lGMV9_K6-Rwf*($C}Dgc@^yi{%+st2t@1KLS)?syw>k=O?amL$Y|Nf6d7>0?c8 ztQT2$d*_zf$y+^fUy9>yu|cVf2?}pGffzq!D$tgv#f@UpM zdC+7pN|sGX3uU)jXVkkhZ)QUNuydw_mf{6@f0j6XnxPc_By(sj^PZ4)oHdxZog>~3 zU4s19iJ;?o(oRH*xA*pqDBgQ792ZUhZ|>JvcZim+^}R&tzt(OU7TI$~UXds527;hg z&3T?g{V6rZ^>-+k!~Cv|_H@+ZpdLA`!4%{!*W`dZZ`OMogPSC(;V%hsdK4V-OjB`= z9Y+Z|Xn|$oobNSqB#frka`zB|9+*ThAx!&~VB%2)*d$3V2DzpvsxW-{jAaj8S8I-z z7}9JFrMsV{%_lV<_>EScpZ?K%-xl5V`+^Ss`@&LoSq79=t;N=)1RKk%1{DjWYr2aD zwn)-jgj#fG$60as{`L9KjE^zuTWxUU_#N zHw1WhNAJA&gYN_m+a2^c$b{_ndzcqI9K!!qJQyZRW!o)FOOf9#d~)mfs6_Y6d)vJ9 zeYS^X+Gn{HdC$s3{Q8+1*Z2oLjkjXyID&9w?e4iOfVjW=jDBfvZ($W`c_i-A2#iz{ zEv*&NfW5jtlm(Zz;g1;31K)`Szu4~bveUA&ovOF zCUF`(_YSCm=N~60hLv)=7JllH(WDjdB;2AcYPI~UqN3F-T|~~fw>V!ReD4tHYEDj< z#?*3m5TJpYZqimi?@xs*YQ4znYL05$_XaYwA4|LA5ep`HP+p)W#e00_$go}@bbL$oS2f<5Z`XA#`8_C(ePCJyc9?L4LRAc{N&0O47T~pU*O^rd| z{{OF;lSI|EA0pX%S*1*g{)^xhsk^6KHAQG86HzeSx`0QG%r`psCluObdZKTWDA1{4 z+(@VzT?sPt_;LRN48THKOaNn@QYBU5uEe=Z)45*K3Ojyis)G(;xP={^bDV+XFqSzr zk&buYD>A(r&M^V#IRY5_hw=tZl1P+iG5-4Itwv~?_M+_D7@xA2Nve-p{DGuGo&l?r~VMOl0Q97DJ zBsXn&XPQgI6XXmIcc)>|v)(1QiSp86=k#27Q`6L+P9y9|hnqofLU=_v&jE-iaAF@= zBsQctS~l%nYZ+7|)G|1SUn)W10?zl7Xo)w14VJO?J(47Y0!%HauKa6h&MEbSNQ7Vg z56u4-m!$zh0C4~d@V~pXT&MXS2^EX9`~TUcGUmm&NUcO^Z*ba3Gxq?O%q^dH{7LLx zFj?;)`;Oap$P>42)!4VERT#txtCU|geZ7O{`NSTFOL_(tgO)TW4_wR%3<=e(9gws zGsf^qTbcdOHBY(>4eVt4zw|uphxYi$`EK>5U0MEPY4=*6exe;1rU14eoDmN2P5qZO z?oVvxH0t@kyY%YpU~9a{=wr`+UE_`Ek00>_iB$j>4q|Y}p}~CBxCly_U0fvm4#5v6 zu*RFw|D_t)0(LiJ5itT^<9M>&zs3txR)0+pdB6KLQGDn>66>P-Rf7Bh7f<+bn-*+q=Ypyu#1)scuD%rOFDgzfHmgZ(g2< zJYN9jO)%f9yZOuyvS1{j|NDI-4WI<#PZ zJvaSm&Y{z-i^dhB@~_JhHxKvt24P?4N?r*~a804<-|4lUfl6)SomGAA4jbeuTQi8> zyH+q2ZKKg$33kwF^KPLRQHgrX_|t8p6K-X#pEFgPUMnjZa~T^wm`q4H)Zy&5G`_`Y z_ukSMbSwE5ol70V5pP-kYpKa~{Ix;X`+XvIg_&YxRNRv^0;pNM*(FCEt4W7t^1g1< zAW;oCyQOjvq_H!Ij!T;A3QE2WgO{VEsxd*n$XyDVZI$&-oxLg9w^hGcdamM+w-hzS z-*){g__w}r!$W;C{hj{1J%sC=|)LYk^Zk6`~SQILx4CC_TNkJ26$W_%Qhi; zBc&2%4z$Y%zc7^a|7cB%33e);@HFcjejSV>QhZ*Q>szLp#*H#$i#Orc&Zf60J+VIG zB|xtf3rcyk{1b(es(h4rwC>X-!Y@0wgK0fxviXXJ*na*g?u|He7ht|@delcmSRTdy E4-8=HEC2ui literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/progress.png b/cv/distiller/CWD/mmcv/docs/en/_static/progress.png new file mode 100644 index 0000000000000000000000000000000000000000..a4070e0052427373c59967ed07bb9f936ca8df59 GIT binary patch literal 20918 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 literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/version.json b/cv/distiller/CWD/mmcv/docs/en/_static/version.json new file mode 100644 index 000000000..7ee4965d3 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/_static/version.json @@ -0,0 +1,575 @@ +{ + "Linux": [ + { + "cuda": "11.7", + "torch": "1.13.x", + "mmcv": [ + "2.0.0rc3" + ] + }, + { + "cuda": "11.6", + "torch": "1.13.x", + "mmcv": [ + "2.0.0rc3" + ] + }, + { + "cuda": "11.6", + "torch": "1.12.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.5", + "torch": "1.11.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.3", + "torch": "1.12.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.3", + "torch": "1.11.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.3", + "torch": "1.10.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.1", + "torch": "1.10.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.1", + "torch": "1.9.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.1", + "torch": "1.8.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.0", + "torch": "1.7.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.2", + "torch": "1.12.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.2", + "torch": "1.11.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.2", + "torch": "1.10.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.2", + "torch": "1.9.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.2", + "torch": "1.8.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.2", + "torch": "1.7.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.2", + "torch": "1.6.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.1", + "torch": "1.8.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.1", + "torch": "1.7.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.1", + "torch": "1.6.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "9.2", + "torch": "1.7.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "9.2", + "torch": "1.6.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.13.x", + "mmcv": [ + "2.0.0rc3" + ] + }, + { + "cuda": "cpu", + "torch": "1.12.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.11.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.10.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.9.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.8.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.7.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.6.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + } + ], + "Windows": [ + { + "cuda": "11.7", + "torch": "1.13.x", + "mmcv": [ + "2.0.0rc3" + ] + }, + { + "cuda": "11.6", + "torch": "1.13.x", + "mmcv": [ + "2.0.0rc3" + ] + }, + { + "cuda": "11.6", + "torch": "1.12.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.5", + "torch": "1.11.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.3", + "torch": "1.12.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.3", + "torch": "1.11.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.3", + "torch": "1.10.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.1", + "torch": "1.10.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.1", + "torch": "1.9.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "11.1", + "torch": "1.8.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.2", + "torch": "1.10.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.2", + "torch": "1.9.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.2", + "torch": "1.8.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.2", + "torch": "1.7.x", + "mmcv": [ + "2.0.0rc3" + ] + }, + { + "cuda": "10.2", + "torch": "1.6.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.1", + "torch": "1.8.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "10.1", + "torch": "1.7.x", + "mmcv": [ + "2.0.0rc3" + ] + }, + { + "cuda": "10.1", + "torch": "1.6.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.13.x", + "mmcv": [ + "2.0.0rc3" + ] + }, + { + "cuda": "cpu", + "torch": "1.12.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.11.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.10.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.9.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.8.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.7.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + }, + { + "cuda": "cpu", + "torch": "1.6.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2", + "2.0.0rc1" + ] + } + ], + "macOS": [ + { + "cuda": "cpu", + "torch": "1.13.x", + "mmcv": [ + "2.0.0rc3" + ] + }, + { + "cuda": "mps", + "torch": "1.13.x", + "mmcv": [ + "2.0.0rc3" + ] + }, + { + "cuda": "cpu", + "torch": "1.12.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2" + ] + }, + { + "cuda": "cpu", + "torch": "1.11.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2" + ] + }, + { + "cuda": "cpu", + "torch": "1.10.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2" + ] + }, + { + "cuda": "cpu", + "torch": "1.9.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2" + ] + }, + { + "cuda": "cpu", + "torch": "1.8.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2" + ] + }, + { + "cuda": "cpu", + "torch": "1.7.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2" + ] + }, + { + "cuda": "cpu", + "torch": "1.6.x", + "mmcv": [ + "2.0.0rc3", + "2.0.0rc2" + ] + } + ] +} diff --git a/cv/distiller/CWD/mmcv/docs/en/_templates/classtemplate.rst b/cv/distiller/CWD/mmcv/docs/en/_templates/classtemplate.rst new file mode 100644 index 000000000..4f7484239 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/_templates/classtemplate.rst @@ -0,0 +1,14 @@ +.. role:: hidden + :class: hidden-section +.. currentmodule:: {{ module }} + + +{{ name | underline}} + +.. autoclass:: {{ name }} + :members: + + +.. + autogenerated from source/_templates/classtemplate.rst + note it does not have :inherited-members: diff --git a/cv/distiller/CWD/mmcv/docs/en/api/arraymisc.rst b/cv/distiller/CWD/mmcv/docs/en/api/arraymisc.rst new file mode 100644 index 000000000..28975eb76 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/api/arraymisc.rst @@ -0,0 +1,19 @@ +.. role:: hidden + :class: hidden-section + +mmcv.arraymisc +=================================== + +.. contents:: mmcv.arraymisc + :depth: 2 + :local: + :backlinks: top + +.. currentmodule:: mmcv.arraymisc + +.. autosummary:: + :toctree: generated + :nosignatures: + + quantize + dequantize diff --git a/cv/distiller/CWD/mmcv/docs/en/api/cnn.rst b/cv/distiller/CWD/mmcv/docs/en/api/cnn.rst new file mode 100644 index 000000000..5cbcb191e --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/api/cnn.rst @@ -0,0 +1,70 @@ +.. role:: hidden + :class: hidden-section + +mmcv.cnn +=================================== + +.. contents:: mmcv.cnn + :depth: 2 + :local: + :backlinks: top + +.. currentmodule:: mmcv.cnn + +Module +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: classtemplate.rst + + ContextBlock + Conv2d + Conv3d + ConvAWS2d + ConvModule + ConvTranspose2d + ConvTranspose3d + ConvWS2d + DepthwiseSeparableConvModule + GeneralizedAttention + HSigmoid + HSwish + LayerScale + Linear + MaxPool2d + MaxPool3d + NonLocal1d + NonLocal2d + NonLocal3d + Scale + Swish + +Build Function +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + + build_activation_layer + build_conv_layer + build_norm_layer + build_padding_layer + build_plugin_layer + build_upsample_layer + +Miscellaneous +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + + fuse_conv_bn + conv_ws_2d + is_norm + make_res_layer + make_vgg_layer + get_model_complexity_info diff --git a/cv/distiller/CWD/mmcv/docs/en/api/image.rst b/cv/distiller/CWD/mmcv/docs/en/api/image.rst new file mode 100644 index 000000000..3b9348495 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/api/image.rst @@ -0,0 +1,100 @@ +.. role:: hidden + :class: hidden-section + +mmcv.image +=================================== + +.. contents:: mmcv.image + :depth: 2 + :local: + :backlinks: top + +.. currentmodule:: mmcv.image + +IO +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + + imfrombytes + imread + imwrite + use_backend + +Color Space +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + + bgr2gray + bgr2hls + bgr2hsv + bgr2rgb + bgr2ycbcr + gray2bgr + gray2rgb + hls2bgr + hsv2bgr + imconvert + rgb2bgr + rgb2gray + rgb2ycbcr + ycbcr2bgr + ycbcr2rgb + +Geometric +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + + cutout + imcrop + imflip + impad + impad_to_multiple + imrescale + imresize + imresize_like + imresize_to_multiple + imrotate + imshear + imtranslate + rescale_size + +Photometric +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + + adjust_brightness + adjust_color + adjust_contrast + adjust_hue + adjust_lighting + adjust_sharpness + auto_contrast + clahe + imdenormalize + imequalize + iminvert + imnormalize + lut_transform + posterize + solarize + +Miscellaneous +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + + tensor2imgs diff --git a/cv/distiller/CWD/mmcv/docs/en/api/ops.rst b/cv/distiller/CWD/mmcv/docs/en/api/ops.rst new file mode 100644 index 000000000..b0290457b --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/api/ops.rst @@ -0,0 +1,135 @@ +.. role:: hidden + :class: hidden-section + +mmcv.ops +=================================== + +.. contents:: mmcv.ops + :depth: 2 + :local: + :backlinks: top + +.. currentmodule:: mmcv.ops + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: classtemplate.rst + + BorderAlign + CARAFE + CARAFENaive + CARAFEPack + Conv2d + ConvTranspose2d + CornerPool + Correlation + CrissCrossAttention + DeformConv2d + DeformConv2dPack + DeformRoIPool + DeformRoIPoolPack + DynamicScatter + FusedBiasLeakyReLU + GroupAll + Linear + MaskedConv2d + MaxPool2d + ModulatedDeformConv2d + ModulatedDeformConv2dPack + ModulatedDeformRoIPoolPack + MultiScaleDeformableAttention + PSAMask + PointsSampler + PrRoIPool + QueryAndGroup + RiRoIAlignRotated + RoIAlign + RoIAlignRotated + RoIAwarePool3d + RoIPointPool3d + RoIPool + SAConv2d + SigmoidFocalLoss + SimpleRoIAlign + SoftmaxFocalLoss + SparseConv2d + SparseConv3d + SparseConvTensor + SparseConvTranspose2d + SparseConvTranspose3d + SparseInverseConv2d + SparseInverseConv3d + SparseMaxPool2d + SparseMaxPool3d + SparseModule + SparseSequential + SubMConv2d + SubMConv3d + SyncBatchNorm + TINShift + Voxelization + +.. autosummary:: + :toctree: generated + :nosignatures: + + active_rotated_filter + assign_score_withk + ball_query + batched_nms + bbox_overlaps + border_align + box_iou_rotated + boxes_iou3d + boxes_iou_bev + boxes_overlap_bev + carafe + carafe_naive + chamfer_distance + contour_expand + convex_giou + convex_iou + deform_conv2d + deform_roi_pool + diff_iou_rotated_2d + diff_iou_rotated_3d + dynamic_scatter + furthest_point_sample + furthest_point_sample_with_dist + fused_bias_leakyrelu + gather_points + grouping_operation + knn + masked_conv2d + min_area_polygons + modulated_deform_conv2d + nms + nms3d + nms3d_normal + nms_bev + nms_match + nms_normal_bev + nms_rotated + pixel_group + point_sample + points_in_boxes_all + points_in_boxes_cpu + points_in_boxes_part + points_in_polygons + prroi_pool + rel_roi_point_to_rel_img_point + riroi_align_rotated + roi_align + roi_align_rotated + roi_pool + rotated_feature_align + scatter_nd + sigmoid_focal_loss + soft_nms + softmax_focal_loss + three_interpolate + three_nn + tin_shift + upfirdn2d + voxelization diff --git a/cv/distiller/CWD/mmcv/docs/en/api/transforms.rst b/cv/distiller/CWD/mmcv/docs/en/api/transforms.rst new file mode 100644 index 000000000..56463b304 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/api/transforms.rst @@ -0,0 +1,57 @@ +.. role:: hidden + :class: hidden-section + +mmcv.transforms +=================================== + +.. currentmodule:: mmcv.transforms + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: classtemplate.rst + + BaseTransform + +Loading +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: classtemplate.rst + + LoadAnnotations + LoadImageFromFile + +Processing +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: classtemplate.rst + + CenterCrop + MultiScaleFlipAug + Normalize + Pad + RandomChoiceResize + RandomFlip + RandomGrayscale + RandomResize + Resize + +Wrapper +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: classtemplate.rst + + Compose + KeyMapper + RandomApply + RandomChoice + TransformBroadcaster diff --git a/cv/distiller/CWD/mmcv/docs/en/api/utils.rst b/cv/distiller/CWD/mmcv/docs/en/api/utils.rst new file mode 100644 index 000000000..f2ff4c2a3 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/api/utils.rst @@ -0,0 +1,23 @@ +.. role:: hidden + :class: hidden-section + +mmcv.utils +=================================== + +.. contents:: mmcv.utils + :depth: 2 + :local: + :backlinks: top + +.. currentmodule:: mmcv.utils + +.. autosummary:: + :toctree: generated + :nosignatures: + + IS_CUDA_AVAILABLE + IS_MLU_AVAILABLE + IS_MPS_AVAILABLE + collect_env + jit + skip_no_elena diff --git a/cv/distiller/CWD/mmcv/docs/en/api/video.rst b/cv/distiller/CWD/mmcv/docs/en/api/video.rst new file mode 100644 index 000000000..a6ebca0eb --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/api/video.rst @@ -0,0 +1,56 @@ +.. role:: hidden + :class: hidden-section + +mmcv.video +=================================== + +.. contents:: mmcv.video + :depth: 2 + :local: + :backlinks: top + +.. currentmodule:: mmcv.video + +IO +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: classtemplate.rst + + VideoReader + Cache + +.. autosummary:: + :toctree: generated + :nosignatures: + + frames2video + +Optical Flow +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + + dequantize_flow + flow_from_bytes + flow_warp + flowread + flowwrite + quantize_flow + sparse_flow_from_bytes + +Video Processing +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + + concat_video + convert_video + cut_video + resize_video diff --git a/cv/distiller/CWD/mmcv/docs/en/api/visualization.rst b/cv/distiller/CWD/mmcv/docs/en/api/visualization.rst new file mode 100644 index 000000000..8f43ef27a --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/api/visualization.rst @@ -0,0 +1,50 @@ +.. role:: hidden + :class: hidden-section + +mmcv.visualization +=================================== + +.. contents:: mmcv.visualization + :depth: 2 + :local: + :backlinks: top + +.. currentmodule:: mmcv.visualization + +Color +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: classtemplate.rst + + Color + +.. autosummary:: + :toctree: generated + :nosignatures: + + color_val + +Image +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + + imshow + imshow_bboxes + imshow_det_bboxes + +Optical Flow +---------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + + flow2rgb + flowshow + make_color_wheel diff --git a/cv/distiller/CWD/mmcv/docs/en/community/contributing.md b/cv/distiller/CWD/mmcv/docs/en/community/contributing.md new file mode 100644 index 000000000..e33993577 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/community/contributing.md @@ -0,0 +1,267 @@ +## Contributing to OpenMMLab + +Welcome to the MMCV community, we are committed to building a cutting-edge computer vision foundational library and all kinds of contributions are welcomed, including but not limited to + +**Fix bug** + +You can directly post a Pull Request to fix typo in code or documents + +The steps to fix the bug of code implementation are as follows. + +1. If the modification involve significant changes, you should create an issue first and describe the error information and how to trigger the bug. Other developers will discuss with you and propose an proper solution. + +2. Posting a pull request after fixing the bug and adding corresponding unit test. + +**New Feature or Enhancement** + +1. If the modification involve significant changes, you should create an issue to discuss with our developers to propose an proper design. +2. Post a Pull Request after implementing the new feature or enhancement and add corresponding unit test. + +**Document** + +You can directly post a pull request to fix documents. If you want to add a document, you should first create an issue to check if it is reasonable. + +### Pull Request Workflow + +If you're not familiar with Pull Request, don't worry! The following guidance will tell you how to create a Pull Request step by step. If you want to dive into the develop mode of Pull Request, you can refer to the [official documents](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) + +#### 1. Fork and clone + +If you are posting a pull request for the first time, you should fork the OpenMMLab repositories by clicking the **Fork** button in the top right corner of the GitHub page, and the forked repositories will appear under your GitHub profile. + + + +Then, you can clone the repositories to local: + +```shell +git clone git@github.com:{username}/mmcv.git +``` + +After that, you should ddd official repository as the upstream repository + +```bash +git remote add upstream git@github.com:open-mmlab/mmcv +``` + +Check whether remote repository has been added successfully by `git remote -v` + +```bash +origin git@github.com:{username}/mmcv.git (fetch) +origin git@github.com:{username}/mmcv.git (push) +upstream git@github.com:open-mmlab/mmcv (fetch) +upstream git@github.com:open-mmlab/mmcv (push) +``` + +```{note} +Here's a brief introduction to origin and upstream. When we use "git clone", we create an "origin" remote by default, which points to the repository cloned from. As for "upstream", we add it ourselves to point to the target repository. Of course, if you don't like the name "upstream", you could name it as you wish. Usually, we'll push the code to "origin". If the pushed code conflicts with the latest code in official("upstream"), we should pull the latest code from upstream to resolve the conflicts, and then push to "origin" again. The posted Pull Request will be updated automatically. +``` + +#### 2. Configure pre-commit + +You should configure [pre-commit](https://pre-commit.com/#intro) in the local development environment to make sure the code style matches that of OpenMMLab. **Note**: The following code should be executed under the MMCV directory. + +```shell +pip install -U pre-commit +pre-commit install +``` + +Check that pre-commit is configured successfully, and install the hooks defined in `.pre-commit-config.yaml`. + +```shell +pre-commit run --all-files +``` + + + + + +```{note} +Chinese users may fail to download the pre-commit hooks due to the network issue. In this case, you could download these hooks from gitee by setting the .pre-commit-config-zh-cn.yaml + +pre-commit install -c .pre-commit-config-zh-cn.yaml +pre-commit run --all-files -c .pre-commit-config-zh-cn.yaml +``` + +If the installation process is interrupted, you can repeatedly run `pre-commit run ... ` to continue the installation. + +If the code does not conform to the code style specification, pre-commit will raise a warning and fixes some of the errors automatically. + + + +If we want to commit our code bypassing the pre-commit hook, we can use the `--no-verify` option(**only for temporarily commit**. + +```shell +git commit -m "xxx" --no-verify +``` + +#### 3. Create a development branch + +After configuring the pre-commit, we should create a branch based on the master branch to develop the new feature or fix the bug. The proposed branch name is `username/pr_name` + +```shell +git checkout -b yhc/refactor_contributing_doc +``` + +In subsequent development, if the master branch of the local repository is behind the master branch of "upstream", we need to pull the upstream for synchronization, and then execute the above command: + +```shell +git pull upstream master +``` + +#### 4. Commit the code and pass the unit test + +- MMCV introduces mypy to do static type checking to increase the robustness of the code. Therefore, we need to add Type Hints to our code and pass the mypy check. If you are not familiar with Type Hints, you can refer to [this tutorial](https://docs.python.org/3/library/typing.html). + +- The committed code should pass through the unit test + + ```shell + # Pass all unit tests + pytest tests + + # Pass the unit test of runner + pytest tests/test_runner/test_runner.py + ``` + + If the unit test fails for lack of dependencies, you can install the dependencies referring to the [guidance](#unit-test) + +- If the documents are modified/added, we should check the rendering result referring to [guidance](#document-rendering) + +#### 5. Push the code to remote + +We could push the local commits to remote after passing through the check of unit test and pre-commit. You can associate the local branch with remote branch by adding `-u` option. + +```shell +git push -u origin {branch_name} +``` + +This will allow you to use the `git push` command to push code directly next time, without having to specify a branch or the remote repository. + +#### 6. Create a Pull Request + +(1) Create a pull request in GitHub's Pull request interface + + + +(2) Modify the PR description according to the guidelines so that other developers can better understand your changes + + + +Find more details about Pull Request description in [pull request guidelines](#pr-specs). + +**note** + +(a) The Pull Request description should contain the reason for the change, the content of the change, and the impact of the change, and be associated with the relevant Issue (see [documentation](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) + +(b) If it is your first contribution, please sign the CLA + + + +(c) Check whether the Pull Request pass through the CI + + + +MMCV will run unit test for the posted Pull Request on different platforms (Linux, Window, Mac), based on different versions of Python, PyTorch, CUDA to make sure the code is correct. We can see the specific test information by clicking `Details` in the above image so that we can modify the code. + +(3) If the Pull Request passes the CI, then you can wait for the review from other developers. You'll modify the code based on the reviewer's comments, and repeat the steps [4](#4-commit-the-code-and-pass-the-unit-test)-[5](#5-push-the-code-to-remote) until all reviewers approve it. Then, we will merge it ASAP. + + + +#### 7. Resolve conflicts + +If your local branch conflicts with the latest master branch of "upstream", you'll need to resolove them. There are two ways to do this: + +```shell +git fetch --all --prune +git rebase upstream/master +``` + +or + +```shell +git fetch --all --prune +git merge upstream/master +``` + +If you are very good at handling conflicts, then you can use rebase to resolve conflicts, as this will keep your commit logs tidy. If you are not familiar with `rebase`, then you can use `merge` to resolve conflicts. + +### Guidance + +#### Unit test + +If you cannot run the unit test of some modules for lacking of some dependencies, such as [video](https://github.com/open-mmlab/mmcv/tree/master/mmcv/video) module, you can try to install the following dependencies: + +```shell +# Linux +sudo apt-get update -y +sudo apt-get install -y libturbojpeg +sudo apt-get install -y ffmpeg + +# Windows +conda install ffmpeg +``` + +We should also make sure the committed code will not decrease the coverage of unit test, we could run the following command to check the coverage of unit test: + +```shell +python -m coverage run -m pytest /path/to/test_file +python -m coverage html +# check file in htmlcov/index.html +``` + +#### Document rendering + +If the documents are modified/added, we should check the rendering result. We could install the dependencies and run the following command to render the documents and check the results: + +```shell +pip install -r requirements/docs.txt +cd docs/zh_cn/ +# or docs/en +make html +# check file in ./docs/zh_cn/_build/html/index.html +``` + +### Code style + +#### Python + +We adopt [PEP8](https://www.python.org/dev/peps/pep-0008/) as the preferred code style. + +We use the following tools for linting and formatting: + +- [flake8](https://github.com/PyCQA/flake8): A wrapper around some linter tools. +- [isort](https://github.com/timothycrosley/isort): A Python utility to sort imports. +- [yapf](https://github.com/google/yapf): A formatter for Python files. +- [codespell](https://github.com/codespell-project/codespell): A Python utility to fix common misspellings in text files. +- [mdformat](https://github.com/executablebooks/mdformat): Mdformat is an opinionated Markdown formatter that can be used to enforce a consistent style in Markdown files. +- [docformatter](https://github.com/myint/docformatter): A formatter to format docstring. + +Style configurations of yapf and isort can be found in [setup.cfg](./setup.cfg). + +We use [pre-commit hook](https://pre-commit.com/) that checks and formats for `flake8`, `yapf`, `isort`, `trailing whitespaces`, `markdown files`, +fixes `end-of-files`, `double-quoted-strings`, `python-encoding-pragma`, `mixed-line-ending`, sorts `requirments.txt` automatically on every commit. +The config for a pre-commit hook is stored in [.pre-commit-config](./.pre-commit-config.yaml). + +#### C++ and CUDA + +We follow the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). + +### PR Specs + +1. Use [pre-commit](https://pre-commit.com) hook to avoid issues of code style + +2. One short-time branch should be matched with only one PR + +3. Accomplish a detailed change in one PR. Avoid large PR + + - Bad: Support Faster R-CNN + - Acceptable: Add a box head to Faster R-CNN + - Good: Add a parameter to box head to support custom conv-layer number + +4. Provide clear and significant commit message + +5. Provide clear and meaningful PR description + + - Task name should be clarified in title. The general format is: \[Prefix\] Short description of the PR (Suffix) + - Prefix: add new feature \[Feature\], fix bug \[Fix\], related to documents \[Docs\], in developing \[WIP\] (which will not be reviewed temporarily) + - Introduce main changes, results and influences on other modules in short description + - Associate related issues and pull requests with a milestone diff --git a/cv/distiller/CWD/mmcv/docs/en/community/pr.md b/cv/distiller/CWD/mmcv/docs/en/community/pr.md new file mode 100644 index 000000000..1bdd90f2b --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/community/pr.md @@ -0,0 +1,3 @@ +## Pull Request (PR) + +Content has been migrated to [contributing guidance](contributing.md). diff --git a/cv/distiller/CWD/mmcv/docs/en/compatibility.md b/cv/distiller/CWD/mmcv/docs/en/compatibility.md new file mode 100644 index 000000000..c8618388f --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/compatibility.md @@ -0,0 +1,176 @@ +### v1.3.18 + +Some ops have different implementations on different devices. Lots of macros and type checks are scattered in several files, which makes the code hard to maintain. For example: + +```c++ + if (input.device().is_cuda()) { +#ifdef MMCV_WITH_CUDA + CHECK_CUDA_INPUT(input); + CHECK_CUDA_INPUT(rois); + CHECK_CUDA_INPUT(output); + CHECK_CUDA_INPUT(argmax_y); + CHECK_CUDA_INPUT(argmax_x); + + roi_align_forward_cuda(input, rois, output, argmax_y, argmax_x, + aligned_height, aligned_width, spatial_scale, + sampling_ratio, pool_mode, aligned); +#else + AT_ERROR("RoIAlign is not compiled with GPU support"); +#endif + } else { + CHECK_CPU_INPUT(input); + CHECK_CPU_INPUT(rois); + CHECK_CPU_INPUT(output); + CHECK_CPU_INPUT(argmax_y); + CHECK_CPU_INPUT(argmax_x); + roi_align_forward_cpu(input, rois, output, argmax_y, argmax_x, + aligned_height, aligned_width, spatial_scale, + sampling_ratio, pool_mode, aligned); + } +``` + +Registry and dispatcher are added to manage these implementations. + +```c++ + +void ROIAlignForwardCUDAKernelLauncher(Tensor input, Tensor rois, Tensor output, + Tensor argmax_y, Tensor argmax_x, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned); + +void roi_align_forward_cuda(Tensor input, Tensor rois, Tensor output, + Tensor argmax_y, Tensor argmax_x, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned) { + ROIAlignForwardCUDAKernelLauncher( + input, rois, output, argmax_y, argmax_x, aligned_height, aligned_width, + spatial_scale, sampling_ratio, pool_mode, aligned); +} + +// register cuda implementation +void roi_align_forward_impl(Tensor input, Tensor rois, Tensor output, + Tensor argmax_y, Tensor argmax_x, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned); +REGISTER_DEVICE_IMPL(roi_align_forward_impl, CUDA, roi_align_forward_cuda); + +// roi_align.cpp +// use the dispatcher to invoke different implementation depending on device type of input tensors. +void roi_align_forward_impl(Tensor input, Tensor rois, Tensor output, + Tensor argmax_y, Tensor argmax_x, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned) { + DISPATCH_DEVICE_IMPL(roi_align_forward_impl, input, rois, output, argmax_y, + argmax_x, aligned_height, aligned_width, spatial_scale, + sampling_ratio, pool_mode, aligned); +} + +``` + +### v1.3.11 + +In order to flexibly support more backends and hardwares like `NVIDIA GPUs` and `AMD GPUs`, the directory of `mmcv/ops/csrc` is refactored. Note that this refactoring will not affect the usage in API. For related information, please refer to [PR1206](https://github.com/open-mmlab/mmcv/pull/1206). + +The original directory was organized as follows. + +``` +. +├── common_cuda_helper.hpp +├── ops_cuda_kernel.cuh +├── pytorch_cpp_helper.hpp +├── pytorch_cuda_helper.hpp +├── parrots_cpp_helper.hpp +├── parrots_cuda_helper.hpp +├── parrots_cudawarpfunction.cuh +├── onnxruntime +│   ├── onnxruntime_register.h +│   ├── onnxruntime_session_options_config_keys.h +│   ├── ort_mmcv_utils.h +│   ├── ... +│   ├── onnx_ops.h +│   └── cpu +│ ├── onnxruntime_register.cpp +│      ├── ... +│      └── onnx_ops_impl.cpp +├── parrots +│   ├── ... +│   ├── ops.cpp +│   ├── ops_cuda.cu +│   ├── ops_parrots.cpp +│   └── ops_pytorch.h +├── pytorch +│   ├── ... +│   ├── ops.cpp +│   ├── ops_cuda.cu +│   ├── pybind.cpp +└── tensorrt + ├── trt_cuda_helper.cuh + ├── trt_plugin_helper.hpp + ├── trt_plugin.hpp + ├── trt_serialize.hpp + ├── ... + ├── trt_ops.hpp + └── plugins +    ├── trt_cuda_helper.cu +    ├── trt_plugin.cpp +    ├── ... +    ├── trt_ops.cpp +    └── trt_ops_kernel.cu +``` + +After refactored, it is organized as follows. + +``` +. +├── common +│ ├── box_iou_rotated_utils.hpp +│ ├── parrots_cpp_helper.hpp +│ ├── parrots_cuda_helper.hpp +│ ├── pytorch_cpp_helper.hpp +│ ├── pytorch_cuda_helper.hpp +│   └── cuda +│   ├── common_cuda_helper.hpp +│   ├── parrots_cudawarpfunction.cuh +│   ├── ... +│   └── ops_cuda_kernel.cuh +├── onnxruntime +│   ├── onnxruntime_register.h +│   ├── onnxruntime_session_options_config_keys.h +│   ├── ort_mmcv_utils.h +│   ├── ... +│   ├── onnx_ops.h +│   └── cpu +│ ├── onnxruntime_register.cpp +│      ├── ... +│      └── onnx_ops_impl.cpp +├── parrots +│   ├── ... +│   ├── ops.cpp +│   ├── ops_parrots.cpp +│   └── ops_pytorch.h +├── pytorch +│   ├── info.cpp +│   ├── pybind.cpp +│   ├── ... +│   ├── ops.cpp +│   └── cuda +│      ├── ... +│      └── ops_cuda.cu +└── tensorrt + ├── trt_cuda_helper.cuh + ├── trt_plugin_helper.hpp + ├── trt_plugin.hpp + ├── trt_serialize.hpp + ├── ... + ├── trt_ops.hpp + └── plugins +    ├── trt_cuda_helper.cu +    ├── trt_plugin.cpp +    ├── ... +    ├── trt_ops.cpp +    └── trt_ops_kernel.cu +``` diff --git a/cv/distiller/CWD/mmcv/docs/en/conf.py b/cv/distiller/CWD/mmcv/docs/en/conf.py new file mode 100644 index 000000000..471bd225a --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/conf.py @@ -0,0 +1,215 @@ +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys + +import pytorch_sphinx_theme +from sphinx.builders.html import StandaloneHTMLBuilder + +sys.path.insert(0, os.path.abspath('../..')) + +version_file = '../../mmcv/version.py' +with open(version_file) as f: + exec(compile(f.read(), version_file, 'exec')) +__version__ = locals()['__version__'] + +# -- Project information ----------------------------------------------------- + +project = 'mmcv' +copyright = '2018-2022, OpenMMLab' +author = 'MMCV Authors' + +# The short X.Y version +version = __version__ +# The full version, including alpha/beta/rc tags +release = __version__ + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. + +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.intersphinx', + 'sphinx.ext.napoleon', + 'sphinx.ext.viewcode', + 'sphinx_markdown_tables', + 'myst_parser', + 'sphinx_copybutton', +] # yapf: disable + +myst_heading_anchors = 4 + +myst_enable_extensions = ['colon_fence'] + +# Configuration for intersphinx +intersphinx_mapping = { + 'python': ('https://docs.python.org/3', None), + 'numpy': ('https://numpy.org/doc/stable', None), + 'torch': ('https://pytorch.org/docs/stable/', None), + 'mmengine': ('https://mmengine.readthedocs.io/en/latest', None), +} + +autodoc_mock_imports = ['mmcv._ext', 'mmcv.utils.ext_loader', 'torchvision'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +source_suffix = { + '.rst': 'restructuredtext', + '.md': 'markdown', +} + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +# html_theme = 'sphinx_rtd_theme' +html_theme = 'pytorch_sphinx_theme' +html_theme_path = [pytorch_sphinx_theme.get_html_theme_path()] + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +html_theme_options = { + 'menu': [ + { + 'name': 'GitHub', + 'url': 'https://github.com/open-mmlab/mmcv' + }, + ], + # Specify the language of shared menu + 'menu_lang': 'en', +} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] +html_css_files = ['css/readthedocs.css'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'mmcvdoc' + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'mmcv.tex', 'mmcv Documentation', 'MMCV Contributors', + 'manual'), +] + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [(master_doc, 'mmcv', 'mmcv Documentation', [author], 1)] + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'mmcv', 'mmcv Documentation', author, 'mmcv', + 'One line description of project.', 'Miscellaneous'), +] + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + +# set priority when building html +StandaloneHTMLBuilder.supported_image_types = [ + 'image/svg+xml', 'image/gif', 'image/png', 'image/jpeg' +] +# -- Extension configuration ------------------------------------------------- +# Ignore >>> when copying code +copybutton_prompt_text = r'>>> |\.\.\. ' +copybutton_prompt_is_regexp = True diff --git a/cv/distiller/CWD/mmcv/docs/en/deployment/mmcv_ops_definition.md b/cv/distiller/CWD/mmcv/docs/en/deployment/mmcv_ops_definition.md new file mode 100644 index 000000000..d7eabb33f --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/deployment/mmcv_ops_definition.md @@ -0,0 +1,686 @@ +# MMCV Operators + +To make custom operators in MMCV more standard, precise definitions of each operator are listed in this document. + + + +- [MMCV Operators](#mmcv-operators) + - [MMCVBorderAlign](#mmcvborderalign) + - [Description](#description) + - [Parameters](#parameters) + - [Inputs](#inputs) + - [Outputs](#outputs) + - [Type Constraints](#type-constraints) + - [MMCVCARAFE](#mmcvcarafe) + - [Description](#description-1) + - [Parameters](#parameters-1) + - [Inputs](#inputs-1) + - [Outputs](#outputs-1) + - [Type Constraints](#type-constraints-1) + - [MMCVCAWeight](#mmcvcaweight) + - [Description](#description-2) + - [Parameters](#parameters-2) + - [Inputs](#inputs-2) + - [Outputs](#outputs-2) + - [Type Constraints](#type-constraints-2) + - [MMCVCAMap](#mmcvcamap) + - [Description](#description-3) + - [Parameters](#parameters-3) + - [Inputs](#inputs-3) + - [Outputs](#outputs-3) + - [Type Constraints](#type-constraints-3) + - [MMCVCornerPool](#mmcvcornerpool) + - [Description](#description-4) + - [Parameters](#parameters-4) + - [Inputs](#inputs-4) + - [Outputs](#outputs-4) + - [Type Constraints](#type-constraints-4) + - [MMCVDeformConv2d](#mmcvdeformconv2d) + - [Description](#description-5) + - [Parameters](#parameters-5) + - [Inputs](#inputs-5) + - [Outputs](#outputs-5) + - [Type Constraints](#type-constraints-5) + - [MMCVModulatedDeformConv2d](#mmcvmodulateddeformconv2d) + - [Description](#description-6) + - [Parameters](#parameters-6) + - [Inputs](#inputs-6) + - [Outputs](#outputs-6) + - [Type Constraints](#type-constraints-6) + - [MMCVDeformRoIPool](#mmcvdeformroipool) + - [Description](#description-7) + - [Parameters](#parameters-7) + - [Inputs](#inputs-7) + - [Outputs](#outputs-7) + - [Type Constraints](#type-constraints-7) + - [MMCVMaskedConv2d](#mmcvmaskedconv2d) + - [Description](#description-8) + - [Parameters](#parameters-8) + - [Inputs](#inputs-8) + - [Outputs](#outputs-8) + - [Type Constraints](#type-constraints-8) + - [MMCVPSAMask](#mmcvpsamask) + - [Description](#description-9) + - [Parameters](#parameters-9) + - [Inputs](#inputs-9) + - [Outputs](#outputs-9) + - [Type Constraints](#type-constraints-9) + - [NonMaxSuppression](#nonmaxsuppression) + - [Description](#description-10) + - [Parameters](#parameters-10) + - [Inputs](#inputs-10) + - [Outputs](#outputs-10) + - [Type Constraints](#type-constraints-10) + - [MMCVRoIAlign](#mmcvroialign) + - [Description](#description-11) + - [Parameters](#parameters-11) + - [Inputs](#inputs-11) + - [Outputs](#outputs-11) + - [Type Constraints](#type-constraints-11) + - [MMCVRoIAlignRotated](#mmcvroialignrotated) + - [Description](#description-12) + - [Parameters](#parameters-12) + - [Inputs](#inputs-12) + - [Outputs](#outputs-12) + - [Type Constraints](#type-constraints-12) + - [grid_sampler\*](#grid_sampler) + - [Description](#description-13) + - [Parameters](#parameters-13) + - [Inputs](#inputs-13) + - [Outputs](#outputs-13) + - [Type Constraints](#type-constraints-13) + - [cummax\*](#cummax) + - [Description](#description-14) + - [Parameters](#parameters-14) + - [Inputs](#inputs-14) + - [Outputs](#outputs-14) + - [Type Constraints](#type-constraints-14) + - [cummin\*](#cummin) + - [Description](#description-15) + - [Parameters](#parameters-15) + - [Inputs](#inputs-15) + - [Outputs](#outputs-15) + - [Type Constraints](#type-constraints-15) + - [Reminders](#reminders) + + + +## MMCVBorderAlign + +### Description + +Applies `border_align` over the input feature based on predicted bboxes. + +For each border line (e.g. top, left, bottom or right) of each box, +border_align does the following: + +- uniformly samples `pool_size`+1 positions on this line, involving the start and end points. +- the corresponding features on these points are computed by bilinear interpolation. +- max pooling over all the `pool_size`+1 positions are used for computing pooled feature. + +Read [BorderDet: Border Feature for Dense Object Detection](ttps://arxiv.org/abs/2007.11056) for more detailed information. + +### Parameters + +| Type | Parameter | Description | +| ----- | ----------- | ----------------------------------------------------------------------------------- | +| `int` | `pool_size` | number of positions sampled over the boxes' borders(e.g. top, bottom, left, right). | + +### Inputs + +
    +
    input: T
    +
    Features with shape [N,4C,H,W]. Channels ranged in [0,C), [C,2C), [2C,3C), [3C,4C) represent the top, left, bottom, right features respectively
    +
    boxes: T
    +
    Boxes with shape [N,H*W,4]. Coordinate format (x1,y1,x2,y2).
    +
    + +### Outputs + +
    +
    output: T
    +
    Pooled features with shape [N,C,H*W,4]. The order is(top,left,bottom,right) for the last dimension.
    +
    + +### Type Constraints + +- T:tensor(float32) + +## MMCVCARAFE + +### Description + +CARAFE operator performs feature upsampling. + +Read [CARAFE: Content-Aware ReAssembly of FEatures](https://arxiv.org/abs/1905.02188) for more detailed information. + +### Parameters + +| Type | Parameter | Description | +| ------- | -------------- | --------------------------------------------- | +| `int` | `kernel_size` | reassemble kernel size, should be odd integer | +| `int` | `group_size` | reassemble group size | +| `float` | `scale_factor` | upsample ratio(>=1) | + +### Inputs + +
    +
    features: T
    +
    Input features. 4-D tensor of shape (N, C, H, W). N is the batch size.
    +
    masks: T
    +
    The input mask
    +
    + +### Outputs + +
    +
    output: T
    +
    The upsampled features. 4-D tensor of shape (N, C, H * scale_factor, W * scale_factor). N is the batch size.
    +
    + +### Type Constraints + +- T:tensor(float32) + +## MMCVCAWeight + +### Description + +Operator for Criss-Cross Attention +Read [CCNet: Criss-Cross Attention for SemanticSegmentation](https://arxiv.org/pdf/1811.11721.pdf) for more detailed information. + +### Parameters + +None + +### Inputs + +
    +
    t: T
    +
    The query matrix of shape (N, C', H, W).
    +
    f: T
    +
    The key matrix of shape (N, C', H, W).
    +
    + +### Outputs + +
    +
    weight: T
    +
    The attention map of shape (N, H+W-1, H, W).
    +
    + +### Type Constraints + +- T:tensor(float32) + +## MMCVCAMap + +### Description + +Operator for Criss-Cross Attention +Read [CCNet: Criss-Cross Attention for SemanticSegmentation](https://arxiv.org/pdf/1811.11721.pdf) for more detailed information. + +### Parameters + +None + +### Inputs + +
    +
    weight: T
    +
    Output from the operator MMCVCAWeight.
    +
    value: T
    +
    The value matrix of shape (N, C, H, W).
    +
    + +### Outputs + +
    +
    output: T
    +
    Output tensor of aggregated contextual information
    +
    + +### Type Constraints + +- T:tensor(float32) + +## MMCVCornerPool + +### Description + +Perform CornerPool on `input` features. Read [CornerNet -- Detecting Objects as Paired Keypoints](https://arxiv.org/abs/1808.01244) for more details. + +### Parameters + +| Type | Parameter | Description | +| ----- | --------- | ---------------------------------------------------------------- | +| `int` | `mode` | corner pool mode, (0: `top`, 1: `bottom`, 2: `left`, 3: `right`) | + +### Inputs + +
    +
    input: T
    +
    Input features. 4-D tensor of shape (N, C, H, W). N is the batch size.
    +
    + +### Outputs + +
    +
    output: T
    +
    The pooled features. 4-D tensor of shape (N, C, H, W).
    +
    + +### Type Constraints + +- T:tensor(float32) + +## MMCVDeformConv2d + +### Description + +Applies a deformable 2D convolution over an input signal composed of several input planes. + +Read [Deformable Convolutional Networks](https://arxiv.org/pdf/1703.06211.pdf) for detail. + +### Parameters + +| Type | Parameter | Description | +| -------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------- | +| `list of ints` | `stride` | The stride of the convolving kernel, (sH, sW). Defaults to `(1, 1)`. | +| `list of ints` | `padding` | Paddings on both sides of the input, (padH, padW). Defaults to `(0, 0)`. | +| `list of ints` | `dilation` | The spacing between kernel elements (dH, dW). Defaults to `(1, 1)`. | +| `int` | `groups` | Split input into groups. `input_channel` should be divisible by the number of groups. Defaults to `1`. | +| `int` | `deformable_groups` | Groups of deformable offset. Defaults to `1`. | +| `int` | `bias` | Whether to add a learnable bias to the output. `0` stands for `False` and `1` stands for `True`. Defaults to `0`. | +| `int` | `im2col_step` | Groups of deformable offset. Defaults to `32`. | + +### Inputs + +
    +
    input: T
    +
    Input feature; 4-D tensor of shape (N, C, inH, inW), where N is the batch size, C is the number of channels, inH and inW are the height and width of the data.
    +
    offset: T
    +
    Input offset; 4-D tensor of shape (N, deformable_group* 2* kH* kW, outH, outW), where kH and kW are the height and width of weight, outH and outW is the height and width of offset and output.
    +
    weight: T
    +
    Input weight; 4-D tensor of shape (output_channel, input_channel, kH, kW).
    +
    + +### Outputs + +
    +
    output: T
    +
    Output feature; 4-D tensor of shape (N, output_channel, outH, outW).
    +
    + +### Type Constraints + +- T:tensor(float32, Linear) + +## MMCVModulatedDeformConv2d + +### Description + +Perform Modulated Deformable Convolution on input feature, read [Deformable ConvNets v2: More Deformable, Better Results](https://arxiv.org/abs/1811.11168?from=timeline) for detail. + +### Parameters + +| Type | Parameter | Description | +| -------------- | ------------------- | ------------------------------------------------------------------------------------- | +| `list of ints` | `stride` | The stride of the convolving kernel. (sH, sW) | +| `list of ints` | `padding` | Paddings on both sides of the input. (padH, padW) | +| `list of ints` | `dilation` | The spacing between kernel elements. (dH, dW) | +| `int` | `deformable_groups` | Groups of deformable offset. | +| `int` | `groups` | Split input into groups. `input_channel` should be divisible by the number of groups. | + +### Inputs + +
    +
    feature: T
    +
    Input feature; 4-D tensor of shape (N, C, inH, inW), where N is the batch size, C is the number of channels, inH and inW are the height and width of the data.
    +
    offset: T
    +
    Input offset; 4-D tensor of shape (N, deformable_group* 2* kH* kW, outH, outW), where kH and kW are the height and width of weight, outH and outW are the height and width of offset and output.
    +
    mask: T
    +
    Input mask; 4-D tensor of shape (N, deformable_group* kH* kW, outH, outW), where kH and kW are the height and width of weight, outH and outW are the height and width of offset and output.
    +
    weight]: T
    +
    Input weight; 4-D tensor of shape (output_channel, input_channel, kH, kW).
    +
    bias: T, optional
    +
    Input bias; 1-D tensor of shape (output_channel).
    +
    + +### Outputs + +
    +
    output: T
    +
    Output feature; 4-D tensor of shape (N, output_channel, outH, outW).
    +
    + +### Type Constraints + +- T:tensor(float32, Linear) + +## MMCVDeformRoIPool + +### Description + +Deformable roi pooling layer + +### Parameters + +| Type | Parameter | Description | +| ------- | ---------------- | ------------------------------------------------------------------------------------------------------------- | +| `int` | `output_height` | height of output roi | +| `int` | `output_width` | width of output roi | +| `float` | `spatial_scale` | used to scale the input boxes | +| `int` | `sampling_ratio` | number of input samples to take for each output sample. `0` means to take samples densely for current models. | +| `float` | `gamma` | gamma | + +### Inputs + +
    +
    input: T
    +
    Input feature map; 4D tensor of shape (N, C, H, W), where N is the batch size, C is the numbers of channels, H and W are the height and width of the data.
    +
    rois: T
    +
    RoIs (Regions of Interest) to pool over; 2-D tensor of shape (num_rois, 5) given as [[batch_index, x1, y1, x2, y2], ...]. The RoIs' coordinates are the coordinate system of input.
    +
    offset: T
    +
    offset of height and width. Defaults to a tensor of zero
    +
    + +### Outputs + +
    +
    feat: T
    +
    RoI pooled output, 4-D tensor of shape (num_rois, C, output_height, output_width). The r-th batch element feat[r-1] is a pooled feature map corresponding to the r-th RoI RoIs[r-1].
    +
    + +### Type Constraints + +- T:tensor(float32) + +## MMCVMaskedConv2d + +### Description + +Performs a masked 2D convolution from PixelRNN +Read [Pixel Recurrent Neural Networks](https://arxiv.org/abs/1601.06759) for more detailed information. + +### Parameters + +| Type | Parameter | Description | +| -------------- | --------- | -------------------------------------------------------------------------------- | +| `list of ints` | `stride` | The stride of the convolving kernel. (sH, sW). **Only support stride=1 in mmcv** | +| `list of ints` | `padding` | Paddings on both sides of the input. (padH, padW). Defaults to `(0, 0)`. | + +### Inputs + +
    +
    features: T
    +
    Input features; 4D tensor of shape (N, C, H, W), where N is the batch size, C is the numbers of channels, H and W are the height and width of the data.
    +
    mask: T
    +
    Input mask; 3D tensor of shape (N, H, W)
    +
    weight: T
    +
    The learnable weights of the module
    +
    bias: T
    +
    The learnable bias of the module
    +
    + +### Outputs + +
    +
    output: T
    +
    The output convolved feature
    +
    + +### Type Constraints + +- T:tensor(float32) + +## MMCVPSAMask + +### Description + +An operator from PSANet. + +Read [PSANet: Point-wise Spatial Attention Network for Scene Parsing](https://hszhao.github.io/papers/eccv18_psanet.pdf) for more detailed information. + +### Parameters + +| Type | Parameter | Description | +| -------------- | ----------- | -------------------------------------------- | +| `int` | `psa_type` | `0` means collect and `1` means `distribute` | +| `list of ints` | `mask_size` | The size of mask | + +### Inputs + +
    +
    input: T
    +
    Input feature; 4D tensor of shape (N, C, H, W), where N is the batch size, C is the numbers of channels, H and W are the height and width of the data.
    +
    + +### Outputs + +
    +
    output: T
    +
    Output tensor of shape (N, H * W, H, W)
    +
    + +### Type Constraints + +- T:tensor(float32) + +## NonMaxSuppression + +### Description + +Filter out boxes has high IoU overlap with previously selected boxes or low score. Output the indices of valid boxes. + +Note this definition is slightly different with [onnx: NonMaxSuppression](https://github.com/onnx/onnx/blob/master/docs/Operators.md#nonmaxsuppression) + +### Parameters + +| Type | Parameter | Description | +| ------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| `int` | `center_point_box` | 0 - the box data is supplied as \[y1, x1, y2, x2\], 1-the box data is supplied as \[x_center, y_center, width, height\]. | +| `int` | `max_output_boxes_per_class` | The maximum number of boxes to be selected per batch per class. Default to 0, number of output boxes equal to number of input boxes. | +| `float` | `iou_threshold` | The threshold for deciding whether boxes overlap too much with respect to IoU. Value range \[0, 1\]. Default to 0. | +| `float` | `score_threshold` | The threshold for deciding when to remove boxes based on score. | +| `int` | `offset` | 0 or 1, boxes' width or height is (x2 - x1 + offset). | + +### Inputs + +
    +
    boxes: T
    +
    Input boxes. 3-D tensor of shape (num_batches, spatial_dimension, 4).
    +
    scores: T
    +
    Input scores. 3-D tensor of shape (num_batches, num_classes, spatial_dimension).
    +
    + +### Outputs + +
    +
    indices: tensor(int32, Linear)
    +
    Selected indices. 2-D tensor of shape (num_selected_indices, 3) as [[batch_index, class_index, box_index], ...].
    +
    num_selected_indices=num_batches* num_classes* min(max_output_boxes_per_class, spatial_dimension).
    +
    All invalid indices will be filled with -1.
    +
    + +### Type Constraints + +- T:tensor(float32, Linear) + +## MMCVRoIAlign + +### Description + +Perform RoIAlign on output feature, used in bbox_head of most two-stage detectors. + +### Parameters + +| Type | Parameter | Description | +| ------- | ---------------- | ------------------------------------------------------------------------------------------------------------- | +| `int` | `output_height` | height of output roi | +| `int` | `output_width` | width of output roi | +| `float` | `spatial_scale` | used to scale the input boxes | +| `int` | `sampling_ratio` | number of input samples to take for each output sample. `0` means to take samples densely for current models. | +| `str` | `mode` | pooling mode in each bin. `avg` or `max` | +| `int` | `aligned` | If `aligned=0`, use the legacy implementation in MMDetection. Else, align the results more perfectly. | + +### Inputs + +
    +
    input: T
    +
    Input feature map; 4D tensor of shape (N, C, H, W), where N is the batch size, C is the numbers of channels, H and W are the height and width of the data.
    +
    rois: T
    +
    RoIs (Regions of Interest) to pool over; 2-D tensor of shape (num_rois, 5) given as [[batch_index, x1, y1, x2, y2], ...]. The RoIs' coordinates are the coordinate system of input.
    +
    + +### Outputs + +
    +
    feat: T
    +
    RoI pooled output, 4-D tensor of shape (num_rois, C, output_height, output_width). The r-th batch element feat[r-1] is a pooled feature map corresponding to the r-th RoI RoIs[r-1].
    +
    + +### Type Constraints + +- T:tensor(float32) + +## MMCVRoIAlignRotated + +### Description + +Perform RoI align pooling for rotated proposals + +### Parameters + +| Type | Parameter | Description | +| ------- | ---------------- | ------------------------------------------------------------------------------------------------------------- | +| `int` | `output_height` | height of output roi | +| `int` | `output_width` | width of output roi | +| `float` | `spatial_scale` | used to scale the input boxes | +| `int` | `sampling_ratio` | number of input samples to take for each output sample. `0` means to take samples densely for current models. | +| `str` | `mode` | pooling mode in each bin. `avg` or `max` | +| `int` | `aligned` | If `aligned=0`, use the legacy implementation in MMDetection. Else, align the results more perfectly. | +| `int` | `clockwise` | If `aligned=0`, use the legacy implementation in MMDetection. Else, align the results more perfectly. | + +### Inputs + +
    +
    features: T
    +
    Input feature map; 4D tensor of shape (N, C, H, W)
    +
    rois: T
    +
    RoIs (Regions of Interest) to pool over; 2-D tensor of shape (num_rois, 5) given as [[batch_index, x1, y1, x2, y2], ...]. The RoIs' coordinates are the coordinate system of input.
    +
    + +### Outputs + +
    +
    RoI pooled output, 4-D tensor of shape (num_rois, C, output_height, output_width). The r-th batch element feat[r-1] is a pooled feature map corresponding to the r-th RoI RoIs[r-1].
    +
    + +### Type Constraints + +- T:tensor(float32) + +## grid_sampler\* + +### Description + +Perform sample from `input` with pixel locations from `grid`. + +Check [torch.nn.functional.grid_sample](https://pytorch.org/docs/stable/generated/torch.nn.functional.grid_sample.html?highlight=grid_sample#torch.nn.functional.grid_sample) for more information. + +### Parameters + +| Type | Parameter | Description | +| ----- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `int` | `interpolation_mode` | Interpolation mode to calculate output values. (0: `bilinear` , 1: `nearest`) | +| `int` | `padding_mode` | Padding mode for outside grid values. (0: `zeros`, 1: `border`, 2: `reflection`) | +| `int` | `align_corners` | If `align_corners=1`, the extrema (`-1` and `1`) are considered as referring to the center points of the input's corner pixels. If `align_corners=0`, they are instead considered as referring to the corner points of the input's corner pixels, making the sampling more resolution agnostic. | + +### Inputs + +
    +
    input: T
    +
    Input feature; 4-D tensor of shape (N, C, inH, inW), where N is the batch size, C is the numbers of channels, inH and inW are the height and width of the data.
    +
    grid: T
    +
    Input offset; 4-D tensor of shape (N, outH, outW, 2), where outH and outW are the height and width of offset and output.
    +
    + +### Outputs + +
    +
    output: T
    +
    Output feature; 4-D tensor of shape (N, C, outH, outW).
    +
    + +### Type Constraints + +- T:tensor(float32, Linear) + +## cummax\* + +### Description + +Returns a tuple (`values`, `indices`) where `values` is the cumulative maximum elements of `input` in the dimension `dim`. And `indices` is the index location of each maximum value found in the dimension `dim`. Read [torch.cummax](https://pytorch.org/docs/stable/generated/torch.cummax.html) for more details. + +### Parameters + +| Type | Parameter | Description | +| ----- | --------- | -------------------------------------- | +| `int` | `dim` | the dimension to do the operation over | + +### Inputs + +
    +
    input: T
    +
    The input tensor with various shapes. Tensor with empty element is also supported.
    +
    + +### Outputs + +
    +
    output: T
    +
    Output the cumulative maximum elements of `input` in the dimension `dim`, with the same shape and dtype as `input`.
    +
    indices: tensor(int64)
    +
    Output the index location of each cumulative maximum value found in the dimension `dim`, with the same shape as `input`.
    +
    + +### Type Constraints + +- T:tensor(float32) + +## cummin\* + +### Description + +Returns a tuple (`values`, `indices`) where `values` is the cumulative minimum elements of `input` in the dimension `dim`. And `indices` is the index location of each minimum value found in the dimension `dim`. Read [torch.cummin](https://pytorch.org/docs/stable/generated/torch.cummin.html) for more details. + +### Parameters + +| Type | Parameter | Description | +| ----- | --------- | -------------------------------------- | +| `int` | `dim` | the dimension to do the operation over | + +### Inputs + +
    +
    input: T
    +
    The input tensor with various shapes. Tensor with empty element is also supported.
    +
    + +### Outputs + +
    +
    output: T
    +
    Output the cumulative minimum elements of `input` in the dimension `dim`, with the same shape and dtype as `input`.
    +
    indices: tensor(int64)
    +
    Output the index location of each cumulative minimum value found in the dimension `dim`, with the same shape as `input`.
    +
    + +### Type Constraints + +- T:tensor(float32) + +## Reminders + +- Operators endwith `*` are defined in Torch and are included here for the conversion to ONNX. diff --git a/cv/distiller/CWD/mmcv/docs/en/docutils.conf b/cv/distiller/CWD/mmcv/docs/en/docutils.conf new file mode 100644 index 000000000..0c00c8468 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/docutils.conf @@ -0,0 +1,2 @@ +[html writers] +table_style: colwidths-auto diff --git a/cv/distiller/CWD/mmcv/docs/en/faq.md b/cv/distiller/CWD/mmcv/docs/en/faq.md new file mode 100644 index 000000000..02d31c233 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/faq.md @@ -0,0 +1,93 @@ +## Frequently Asked Questions + +We list some common troubles faced by many users and their corresponding solutions here. +Feel free to enrich the list if you find any frequent issues and have ways to help others to solve them. + +### Installation + +- KeyError: "xxx: 'yyy is not in the zzz registry'" + + The registry mechanism will be triggered only when the file of the module is imported. + So you need to import that file somewhere. More details can be found at [KeyError: "MaskRCNN: 'RefineRoIHead is not in the models registry'"](https://github.com/open-mmlab/mmdetection/issues/5974). + +- "No module named 'mmcv.ops'"; "No module named 'mmcv.\_ext'" + + 1. Uninstall existing mmcv in the environment using `pip uninstall mmcv` + 2. Install mmcv-full following the [installation instruction](https://mmcv.readthedocs.io/en/latest/get_started/installation.html) or [Build MMCV from source](https://mmcv.readthedocs.io/en/latest/get_started/build.html) + +- "invalid device function" or "no kernel image is available for execution" + + 1. Check the CUDA compute capability of you GPU + 2. Run `python mmdet/utils/collect_env.py` to check whether PyTorch, torchvision, and MMCV are built for the correct GPU architecture. You may need to set `TORCH_CUDA_ARCH_LIST` to reinstall MMCV. The compatibility issue could happen when using old GPUS, e.g., Tesla K80 (3.7) on colab. + 3. Check whether the running environment is the same as that when mmcv/mmdet is compiled. For example, you may compile mmcv using CUDA 10.0 bug run it on CUDA9.0 environments + +- "undefined symbol" or "cannot open xxx.so" + + 1. If those symbols are CUDA/C++ symbols (e.g., libcudart.so or GLIBCXX), check + whether the CUDA/GCC runtimes are the same as those used for compiling mmcv + 2. If those symbols are Pytorch symbols (e.g., symbols containing caffe, aten, and TH), check whether the Pytorch version is the same as that used for compiling mmcv + 3. Run `python mmdet/utils/collect_env.py` to check whether PyTorch, torchvision, and MMCV are built by and running on the same environment + +- "RuntimeError: CUDA error: invalid configuration argument" + + This error may be caused by the poor performance of GPU. Try to decrease the value of [THREADS_PER_BLOCK](https://github.com/open-mmlab/mmcv/blob/cac22f8cf5a904477e3b5461b1cc36856c2793da/mmcv/ops/csrc/common_cuda_helper.hpp#L10) + and recompile mmcv. + +- "RuntimeError: nms is not compiled with GPU support" + + This error is because your CUDA environment is not installed correctly. + You may try to re-install your CUDA environment and then delete the build/ folder before re-compile mmcv. + +- "Segmentation fault" + + 1. Check your GCC version and use GCC >= 5.4. This usually caused by the incompatibility between PyTorch and the environment (e.g., GCC \< 4.9 for PyTorch). We also recommend the users to avoid using GCC 5.5 because many feedbacks report that GCC 5.5 will cause "segmentation fault" and simply changing it to GCC 5.4 could solve the problem + 2. Check whether PyTorch is correctly installed and could use CUDA op, e.g. type the following command in your terminal and see whether they could correctly output results + ```shell + python -c 'import torch; print(torch.cuda.is_available())' + ``` + 3. If PyTorch is correctly installed, check whether MMCV is correctly installed. If MMCV is correctly installed, then there will be no issue of the command + ```shell + python -c 'import mmcv; import mmcv.ops' + ``` + 4. If MMCV and PyTorch are correctly installed, you can use `ipdb` to set breakpoints or directly add `print` to debug and see which part leads the `segmentation fault` + +- "libtorch_cuda_cu.so: cannot open shared object file" + + `mmcv-full` depends on the share object but it can not be found. We can check whether the object exists in `~/miniconda3/envs/{environment-name}/lib/python3.7/site-packages/torch/lib` or try to re-install the PyTorch. + +- "fatal error C1189: #error: -- unsupported Microsoft Visual Studio version!" + + If you are building mmcv-full on Windows and the version of CUDA is 9.2, you will probably encounter the error `"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.2\include\crt/host_config.h(133): fatal error C1189: #error: -- unsupported Microsoft Visual Studio version! Only the versions 2012, 2013, 2015 and 2017 are supported!"`, in which case you can use a lower version of Microsoft Visual Studio like vs2017. + +- "error: member "torch::jit::detail::ModulePolicy::all_slots" may not be initialized" + + If your version of PyTorch is 1.5.0 and you are building mmcv-full on Windows, you will probably encounter the error `- torch/csrc/jit/api/module.h(474): error: member "torch::jit::detail::ModulePolicy::all_slots" may not be initialized`. The way to solve the error is to replace all the `static constexpr bool all_slots = false;` with `static bool all_slots = false;` at this file `https://github.com/pytorch/pytorch/blob/v1.5.0/torch/csrc/jit/api/module.h`. More details can be found at [member "torch::jit::detail::AttributePolicy::all_slots" may not be initialized](https://github.com/pytorch/pytorch/issues/39394). + +- "error: a member with an in-class initializer must be const" + + If your version of PyTorch is 1.6.0 and you are building mmcv-full on Windows, you will probably encounter the error `"- torch/include\torch/csrc/jit/api/module.h(483): error: a member with an in-class initializer must be const"`. The way to solve the error is to replace all the `CONSTEXPR_EXCEPT_WIN_CUDA ` with `const` at `torch/include\torch/csrc/jit/api/module.h`. More details can be found at [Ninja: build stopped: subcommand failed](https://github.com/open-mmlab/mmcv/issues/575). + +- "error: member "torch::jit::ProfileOptionalOp::Kind" may not be initialized" + + If your version of PyTorch is 1.7.0 and you are building mmcv-full on Windows, you will probably encounter the error `torch/include\torch/csrc/jit/ir/ir.h(1347): error: member "torch::jit::ProfileOptionalOp::Kind" may not be initialized`. The way to solve the error needs to modify several local files of PyTorch: + + - delete `static constexpr Symbol Kind = ::c10::prim::profile;` and `tatic constexpr Symbol Kind = ::c10::prim::profile_optional;` at `torch/include\torch/csrc/jit/ir/ir.h` + - replace `explicit operator type&() { return *(this->value); }` with `explicit operator type&() { return *((type*)this->value); }` at `torch\include\pybind11\cast.h` + - replace all the `CONSTEXPR_EXCEPT_WIN_CUDA` with `const` at `torch/include\torch/csrc/jit/api/module.h` + + More details can be found at [Ensure default extra_compile_args](https://github.com/pytorch/pytorch/pull/45956). + +- Compatibility issue between MMCV and MMDetection; "ConvWS is already registered in conv layer" + + Please install the correct version of MMCV for the version of your MMDetection following the [installation instruction](https://mmdetection.readthedocs.io/en/latest/get_started.html#installation). + +### Usage + +- "RuntimeError: Expected to have finished reduction in the prior iteration before starting a new one" + + 1. This error indicates that your module has parameters that were not used in producing loss. This phenomenon may be caused by running different branches in your code in DDP mode. More datails at [Expected to have finished reduction in the prior iteration before starting a new one](https://github.com/pytorch/pytorch/issues/55582). + 2. You can set ` find_unused_parameters = True` in the config to solve the above problems or find those unused parameters manually + +- "RuntimeError: Trying to backward through the graph a second time" + + `GradientCumulativeOptimizerHook` and `OptimizerHook` are both set which causes the `loss.backward()` to be called twice so `RuntimeError` was raised. We can only use one of these. More datails at [Trying to backward through the graph a second time](https://github.com/open-mmlab/mmcv/issues/1379). diff --git a/cv/distiller/CWD/mmcv/docs/en/get_started/build.md b/cv/distiller/CWD/mmcv/docs/en/get_started/build.md new file mode 100644 index 000000000..e3d48ec7c --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/get_started/build.md @@ -0,0 +1,292 @@ +## Build MMCV from source + +### Build mmcv + +Before installing mmcv, make sure that PyTorch has been successfully installed following the [PyTorch official installation guide](https://pytorch.org/get-started/locally/#start-locally). This can be verified using the following command + +```bash +python -c 'import torch;print(torch.__version__)' +``` + +If version information is output, then PyTorch is installed. + +```{note} +If you would like to use `opencv-python-headless` instead of `opencv-python`, +e.g., in a minimum container environment or servers without GUI, +you can first install it before installing MMCV to skip the installation of `opencv-python`. +``` + +#### Build on Linux + +1. Clone the repo + + ```bash + git clone https://github.com/open-mmlab/mmcv.git + cd mmcv + ``` + +2. Install `ninja` and `psutil` to speed up the compilation + + ```bash + pip install -r requirements/optional.txt + ``` + +3. Check the nvcc version (requires 9.2+. Skip if no GPU available.) + + ```bash + nvcc --version + ``` + + If the above command outputs the following message, it means that the nvcc setting is OK, otherwise you need to set CUDA_HOME. + + ``` + nvcc: NVIDIA (R) Cuda compiler driver + Copyright (c) 2005-2020 NVIDIA Corporation + Built on Mon_Nov_30_19:08:53_PST_2020 + Cuda compilation tools, release 11.2, V11.2.67 + Build cuda_11.2.r11.2/compiler.29373293_0 + ``` + + :::{note} + If you want to support ROCm, you can refer to [AMD ROCm](https://rocmdocs.amd.com/en/latest/Installation_Guide/Installation-Guide.html) to install ROCm. + ::: + +4. Check the gcc version (requires 5.4+) + + ```bash + gcc --version + ``` + +5. Start building (takes 10+ min) + + ```bash + pip install -e . -v + ``` + +6. Validate the installation + + ```bash + python .dev_scripts/check_installation.py + ``` + + If no error is reported by the above command, the installation is successful. If there is an error reported, please check [Frequently Asked Questions](../faq.md) to see if there is already a solution. + + If no solution is found, please feel free to open an [issue](https://github.com/open-mmlab/mmcv/issues). + +#### Build on macOS + +```{note} +If you are using a mac with apple silicon chip, install the PyTorch 1.13+, otherwise you will encounter the problem in [issues#2218](https://github.com/open-mmlab/mmcv/issues/2218). +``` + +1. Clone the repo + + ```bash + git clone https://github.com/open-mmlab/mmcv.git + cd mmcv + ``` + +2. Install `ninja` and `psutil` to speed up the compilation + + ```bash + pip install -r requirements/optional.txt + ``` + +3. Start building + + ```bash + MMCV_WITH_OPS=1 pip install -e . + ``` + +4. Validate the installation + + ```bash + python .dev_scripts/check_installation.py + ``` + + If no error is reported by the above command, the installation is successful. If there is an error reported, please check [Frequently Asked Questions](../faq.md) to see if there is already a solution. + + If no solution is found, please feel free to open an [issue](https://github.com/open-mmlab/mmcv/issues). + +#### Build on Windows + +Building MMCV on Windows is a bit more complicated than that on Linux. +The following instructions show how to get this accomplished. + +##### Prerequisite + +The following software is required for building MMCV on windows. +Install them first. + +- [Git](https://git-scm.com/download/win) + - During installation, tick **add git to Path**. +- [Visual Studio Community 2019](https://visualstudio.microsoft.com) + - A compiler for C++ and CUDA codes. +- [Miniconda](https://docs.conda.io/en/latest/miniconda.html) + - Official distributions of Python should work too. +- [CUDA 10.2](https://developer.nvidia.com/cuda-10.2-download-archive) + - Not required for building CPU version. + - Customize the installation if necessary. As a recommendation, skip the driver installation if a newer version is already installed. + +```{note} +You should know how to set up environment variables, especially `Path`, on Windows. The following instruction relies heavily on this skill. +``` + +##### Common steps + +1. Launch Anaconda prompt from Windows Start menu + + Do not use raw `cmd.exe` s instruction is based on PowerShell syntax. + +2. Create a new conda environment + + ```powershell + (base) PS C:\Users\xxx> conda create --name mmcv python=3.7 + (base) PS C:\Users\xxx> conda activate mmcv # make sure to activate environment before any operation + ``` + +3. Install PyTorch. Choose a version based on your need. + + ```powershell + # CUDA version + (mmcv) PS C:\Users\xxx> conda install pytorch torchvision cudatoolkit=10.2 -c pytorch + # CPU version + (mmcv) PS C:\Users\xxx> conda install install pytorch torchvision cpuonly -c pytorch + ``` + +4. Clone the repo + + ```powershell + (mmcv) PS C:\Users\xxx> git clone https://github.com/open-mmlab/mmcv.git + (mmcv) PS C:\Users\xxx\mmcv> cd mmcv + ``` + +5. Install `ninja` and `psutil` to speed up the compilation + + ```powershell + (mmcv) PS C:\Users\xxx\mmcv> pip install -r requirements/optional.txt + ``` + +6. Set up MSVC compiler + + Set Environment variable, add `C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\bin\Hostx86\x64` to `PATH`, so that `cl.exe` will be available in prompt, as shown below. + + ```powershell + (mmcv) PS C:\Users\xxx\mmcv> cl + Microsoft (R) C/C++ Optimizing Compiler Version 19.27.29111 for x64 + Copyright (C) Microsoft Corporation. All rights reserved. + + usage: cl [ option... ] filename... [ / link linkoption... ] + ``` + + For compatibility, we use the x86-hosted and x64-targeted compiler. note `Hostx86\x64` in the path. + + You may want to change the system language to English because pytorch will parse text output from `cl.exe` to check its version. However only utf-8 is recognized. Navigate to Control Panel -> Region -> Administrative -> Language for Non-Unicode programs and change it to English. + +##### Build and install MMCV + +mmcv can be built in two ways: + +1. Full version (CPU ops) + + Module `ops` will be compiled as a pytorch extension, but only x86 code will be compiled. The compiled ops can be executed on CPU only. + +2. Full version (CUDA ops) + + Both x86 and CUDA codes of `ops` module will be compiled. The compiled version can be run on both CPU and CUDA-enabled GPU (if implemented). + +###### CPU version + +Build and install + +```powershell +(mmcv) PS C:\Users\xxx\mmcv> python setup.py build_ext +(mmcv) PS C:\Users\xxx\mmcv> python setup.py develop +``` + +###### GPU version + +1. Make sure `CUDA_PATH` or `CUDA_HOME` is already set in `envs` via `ls env:`, desired output is shown as below: + + ```powershell + (mmcv) PS C:\Users\xxx\mmcv> ls env: + + Name Value + ---- ----- + CUDA_PATH C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2 + CUDA_PATH_V10_1 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1 + CUDA_PATH_V10_2 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2 + ``` + + This should already be done by CUDA installer. If not, or you have multiple version of CUDA toolkit installed, set it with + + ```powershell + (mmcv) PS C:\Users\xxx\mmcv> $env:CUDA_HOME = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2" + # OR + (mmcv) PS C:\Users\xxx\mmcv> $env:CUDA_HOME = $env:CUDA_PATH_V10_2 # if CUDA_PATH_V10_2 is in envs: + ``` + +2. Set CUDA target arch + + ```shell + # Here you need to change to the target architecture corresponding to your GPU + (mmcv) PS C:\Users\xxx\mmcv> $env:TORCH_CUDA_ARCH_LIST="7.5" + ``` + + :::{note} + Check your the compute capability of your GPU from [here](https://developer.nvidia.com/cuda-gpus). + + ```powershell + (mmcv) PS C:\Users\xxx\mmcv> &"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\extras\demo_suite\deviceQuery.exe" + Device 0: "NVIDIA GeForce GTX 1660 SUPER" + CUDA Driver Version / Runtime Version 11.7 / 11.1 + CUDA Capability Major/Minor version number: 7.5 + ``` + + The 7.5 above indicates the target architecture. Note: You need to replace v10.2 with your CUDA version in the above command. + ::: + +3. Build and install + + ```powershell + # build + python setup.py build_ext # if success, cl will be launched to compile ops + # install + python setup.py develop + ``` + + ```{note} + If you are compiling against PyTorch 1.6.0, you might meet some errors from PyTorch as described in [this issue](https://github.com/pytorch/pytorch/issues/42467). Follow [this pull request](https://github.com/pytorch/pytorch/pull/43380/files) to modify the source code in your local PyTorch installation. + ``` + +##### Validate installation + +```powershell +(mmcv) PS C:\Users\xxx\mmcv> python .dev_scripts/check_installation.py +``` + +If no error is reported by the above command, the installation is successful. If there is an error reported, please check [Frequently Asked Questions](../faq.md) to see if there is already a solution. +If no solution is found, please feel free to open an [issue](https://github.com/open-mmlab/mmcv/issues). + +### Build mmcv-lite + +If you need to use PyTorch-related modules, make sure PyTorch has been successfully installed in your environment by referring to the [PyTorch official installation guide](https://github.com/pytorch/pytorch#installation). + +1. Clone the repo + + ```bash + git clone https://github.com/open-mmlab/mmcv.git + cd mmcv + ``` + +2. Start building + + ```bash + MMCV_WITH_OPS=0 pip install -e . -v + ``` + +3. Validate installation + + ```bash + python -c 'import mmcv;print(mmcv.__version__)' + ``` diff --git a/cv/distiller/CWD/mmcv/docs/en/get_started/installation.md b/cv/distiller/CWD/mmcv/docs/en/get_started/installation.md new file mode 100644 index 000000000..12bad000a --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/get_started/installation.md @@ -0,0 +1,348 @@ +## Installation + +There are two versions of MMCV: + +- **mmcv**: comprehensive, with full features and various CUDA ops out of box. It takes longer time to build. +- **mmcv-lite**: lite, without CUDA ops but all other features, similar to mmcv\<1.0.0. It is useful when you do not need those CUDA ops. + +```{warning} +Do not install both versions in the same environment, otherwise you may encounter errors like `ModuleNotFound`. You need to uninstall one before installing the other. `Installing the full version is highly recommended if CUDA is avaliable`. +``` + +### Install mmcv + +Before installing mmcv, make sure that PyTorch has been successfully installed following the [PyTorch official installation guide](https://pytorch.org/get-started/locally/#start-locally). This can be verified using the following command + +```bash +python -c 'import torch;print(torch.__version__)' +``` + +If version information is output, then PyTorch is installed. + +#### Install with mim (recommended) + +[mim](https://github.com/open-mmlab/mim) is the package management tool for the OpenMMLab projects, which makes it easy to install mmcv + +```bash +pip install -U openmim +mim install "mmcv>=2.0.0rc1" +``` + +If you find that the above installation command does not use a pre-built package ending with `.whl` but a source package ending with `.tar.gz`, you may not have a pre-build package corresponding to the PyTorch or CUDA or mmcv version, in which case you can [build mmcv from source](build.md). + +
    +Installation log using pre-built packages + +Looking in links: https://download.openmmlab.com/mmcv/dist/cu102/torch1.8.0/index.html
    +Collecting mmcv
    +Downloading https://download.openmmlab.com/mmcv/dist/cu102/torch1.8.0/mmcv-2.0.0rc3-cp38-cp38-manylinux1_x86_64.whl + +
    + +
    +Installation log using source packages + +Looking in links: https://download.openmmlab.com/mmcv/dist/cu102/torch1.8.0/index.html
    +Collecting mmcv==2.0.0rc3
    +Downloading mmcv-2.0.0rc3.tar.gz + +
    + +To install a specific version of mmcv, for example, mmcv version 2.0.0rc3, you can use the following command + +```bash +mim install mmcv==2.0.0rc3 +``` + +:::{note} +If you would like to use `opencv-python-headless` instead of `opencv-python`, +e.g., in a minimum container environment or servers without GUI, +you can first install it before installing MMCV to skip the installation of `opencv-python`. + +Alternatively, if it takes too long to install a dependency library, you can specify the pypi source + +```bash +mim install "mmcv>=2.0.0rc3" -i https://pypi.tuna.tsinghua.edu.cn/simple +``` + +::: + +You can run [check_installation.py](https://github.com/open-mmlab/mmcv/blob/2.x/.dev_scripts/check_installation.py) to check the installation of mmcv-full after running the installation commands. + +#### Install with pip + +Use the following command to check the version of CUDA and PyTorch + +```bash +python -c 'import torch;print(torch.__version__);print(torch.version.cuda)' +``` + +Select the appropriate installation command depending on the type of system, CUDA version, PyTorch version, and MMCV version + + + + +
    + + + + +
    +
    
    +
    +
    +
    +
    +If you do not find a corresponding version in the dropdown box above, you probably do not have a pre-built package corresponding to the PyTorch or CUDA or mmcv version, at which point you can [build mmcv from source](build.md).
    +
    +:::{note}
    +mmcv is only compiled on PyTorch 1.x.0 because the compatibility
    +usually holds between 1.x.0 and 1.x.1. If your PyTorch version is 1.x.1, you
    +can install mmcv compiled with PyTorch 1.x.0 and it usually works well.
    +For example, if your PyTorch version is 1.8.1, you can feel free to choose 1.8.x.
    +:::
    +
    +:::{note}
    +If you would like to use `opencv-python-headless` instead of `opencv-python`,
    +e.g., in a minimum container environment or servers without GUI,
    +you can first install it before installing MMCV to skip the installation of `opencv-python`.
    +
    +Alternatively, if it takes too long to install a dependency library, you can specify the pypi source
    +
    +```bash
    +mim install "mmcv>=2.0.0rc1" -i https://pypi.tuna.tsinghua.edu.cn/simple
    +```
    +
    +:::
    +
    +You can run [check_installation.py](https://github.com/open-mmlab/mmcv/blob/2.x/.dev_scripts/check_installation.py) to check the installation of mmcv after running the installation commands.
    +
    +#### Using mmcv with Docker
    +
    +Build with local repository
    +
    +```bash
    +git clone https://github.com/open-mmlab/mmcv.git && cd mmcv
    +docker build -t mmcv -f docker/release/Dockerfile .
    +```
    +
    +Or build with remote repository
    +
    +```bash
    +docker build -t mmcv https://github.com/open-mmlab/mmcv.git#2.x:docker/release
    +```
    +
    +The [Dockerfile](release/Dockerfile) installs latest released version of mmcv-full by default, but you can specify mmcv versions to install expected versions.
    +
    +```bash
    +docker image build -t mmcv -f docker/release/Dockerfile --build-arg MMCV=2.0.0rc1 .
    +```
    +
    +If you also want to use other versions of PyTorch and CUDA, you can also pass them when building docker images.
    +
    +An example to build an image with PyTorch 1.11 and CUDA 11.3.
    +
    +```bash
    +docker build -t mmcv -f docker/release/Dockerfile \
    +    --build-arg PYTORCH=1.11.0 \
    +    --build-arg CUDA=11.3 \
    +    --build-arg CUDNN=8 \
    +    --build-arg MMCV=2.0.0rc1 .
    +```
    +
    +More available versions of PyTorch and CUDA can be found at [dockerhub/pytorch](https://hub.docker.com/r/pytorch/pytorch/tags).
    +
    +### Install mmcv-lite
    +
    +If you need to use PyTorch-related modules, make sure PyTorch has been successfully installed in your environment by referring to the [PyTorch official installation guide](https://github.com/pytorch/pytorch#installation).
    +
    +```python
    +pip install mmcv-lite
    +```
    diff --git a/cv/distiller/CWD/mmcv/docs/en/get_started/introduction.md b/cv/distiller/CWD/mmcv/docs/en/get_started/introduction.md
    new file mode 100644
    index 000000000..461fcc725
    --- /dev/null
    +++ b/cv/distiller/CWD/mmcv/docs/en/get_started/introduction.md
    @@ -0,0 +1,36 @@
    +## Introduction
    +
    +MMCV is a foundational library for computer vision research and provides the following functionalities.
    +
    +- [Image/Video processing](../understand_mmcv/data_process.md)
    +- [Image and annotation visualization](../understand_mmcv/visualization.md)
    +- [Image transformation](../understand_mmcv/data_transform.md)
    +- [Various CNN architectures](../understand_mmcv/cnn.md)
    +- [High-quality implementation of common CUDA ops](../understand_mmcv/ops.md)
    +
    +It supports the following systems:
    +
    +- Linux
    +- Windows
    +- macOS
    +
    +It supports many research projects as below:
    +
    +- [MMClassification](https://github.com/open-mmlab/mmclassification): OpenMMLab image classification toolbox and benchmark.
    +- [MMDetection](https://github.com/open-mmlab/mmdetection): OpenMMLab detection toolbox and benchmark.
    +- [MMDetection3D](https://github.com/open-mmlab/mmdetection3d): OpenMMLab's next-generation platform for general 3D object detection.
    +- [MMRotate](https://github.com/open-mmlab/mmrotate): OpenMMLab rotated object detection toolbox and benchmark.
    +- [MMYOLO](https://github.com/open-mmlab/mmyolo): OpenMMLab YOLO series toolbox and benchmark.
    +- [MMSegmentation](https://github.com/open-mmlab/mmsegmentation): OpenMMLab semantic segmentation toolbox and benchmark.
    +- [MMOCR](https://github.com/open-mmlab/mmocr): OpenMMLab text detection, recognition, and understanding toolbox.
    +- [MMPose](https://github.com/open-mmlab/mmpose): OpenMMLab pose estimation toolbox and benchmark.
    +- [MMHuman3D](https://github.com/open-mmlab/mmhuman3d): OpenMMLab 3D human parametric model toolbox and benchmark.
    +- [MMSelfSup](https://github.com/open-mmlab/mmselfsup): OpenMMLab self-supervised learning toolbox and benchmark.
    +- [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab model compression toolbox and benchmark.
    +- [MMFewShot](https://github.com/open-mmlab/mmfewshot): OpenMMLab fewshot learning toolbox and benchmark.
    +- [MMAction2](https://github.com/open-mmlab/mmaction2): OpenMMLab's next-generation action understanding toolbox and benchmark.
    +- [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab video perception toolbox and benchmark.
    +- [MMFlow](https://github.com/open-mmlab/mmflow): OpenMMLab optical flow toolbox and benchmark.
    +- [MMEditing](https://github.com/open-mmlab/mmediting): OpenMMLab image and video editing toolbox.
    +- [MMGeneration](https://github.com/open-mmlab/mmgeneration): OpenMMLab image and video generative models toolbox.
    +- [MMDeploy](https://github.com/open-mmlab/mmdeploy): OpenMMLab model deployment framework.
    diff --git a/cv/distiller/CWD/mmcv/docs/en/get_started/previous_versions.md b/cv/distiller/CWD/mmcv/docs/en/get_started/previous_versions.md
    new file mode 100644
    index 000000000..a9c371766
    --- /dev/null
    +++ b/cv/distiller/CWD/mmcv/docs/en/get_started/previous_versions.md
    @@ -0,0 +1,47 @@
    +## OTHER VERSIONS OF PYTORCH BUILT FOR MMCV-FULL
    +
    +We no longer provide `mmcv-full` packages compiled under lower versions of `PyTorch`, but for your convenience, you can find them below.
    +
    +### PyTorch 1.4
    +
    +| 1.0.0 \<= mmcv_version \<= 1.2.1
    +
    +#### CUDA 10.1
    +
    +```bash
    +pip install mmcv-full=={mmcv_version} -f https://download.openmmlab.com/mmcv/dist/cu101/torch1.4.0/index.html
    +```
    +
    +#### CUDA 9.2
    +
    +```bash
    +pip install mmcv-full=={mmcv_version} -f https://download.openmmlab.com/mmcv/dist/cu101/torch1.4.0/index.html
    +```
    +
    +#### CPU
    +
    +```bash
    +pip install mmcv-full=={mmcv_version} -f https://download.openmmlab.com/mmcv/dist/cpu/torch1.4.0/index.html
    +```
    +
    +### PyTorch v1.3
    +
    +| 1.0.0 \<= mmcv_version \<= 1.3.16
    +
    +#### CUDA 10.1
    +
    +```bash
    +pip install mmcv-full=={mmcv_version} -f https://download.openmmlab.com/mmcv/dist/cu101/torch1.3.0/index.html
    +```
    +
    +#### CUDA 9.2
    +
    +```bash
    +pip install mmcv-full=={mmcv_version} -f https://download.openmmlab.com/mmcv/dist/cu101/torch1.3.0/index.html
    +```
    +
    +#### CPU
    +
    +```bash
    +pip install mmcv-full=={mmcv_version} -f https://download.openmmlab.com/mmcv/dist/cpu/torch1.3.0/index.html
    +```
    diff --git a/cv/distiller/CWD/mmcv/docs/en/index.rst b/cv/distiller/CWD/mmcv/docs/en/index.rst
    new file mode 100644
    index 000000000..dee2c3750
    --- /dev/null
    +++ b/cv/distiller/CWD/mmcv/docs/en/index.rst
    @@ -0,0 +1,69 @@
    +Welcome to MMCV's documentation!
    +================================
    +
    +You can switch between Chinese and English documents in the lower-left corner of the layout.
    +
    +.. toctree::
    +   :maxdepth: 2
    +   :caption: Get Started
    +
    +   get_started/introduction.md
    +   get_started/installation.md
    +   get_started/build.md
    +
    +.. toctree::
    +   :maxdepth: 2
    +   :caption: Understand MMCV
    +
    +   understand_mmcv/data_process.md
    +   understand_mmcv/data_transform.md
    +   understand_mmcv/visualization.md
    +   understand_mmcv/cnn.md
    +   understand_mmcv/ops.md
    +
    +.. toctree::
    +   :maxdepth: 2
    +   :caption: Deployment
    +
    +   deployment/mmcv_ops_definition.md
    +
    +.. toctree::
    +   :caption: Switch Language
    +
    +   switch_language.md
    +
    +.. toctree::
    +   :maxdepth: 2
    +   :caption: Compatibility
    +
    +   compatibility.md
    +
    +.. toctree::
    +
    +   faq.md
    +
    +.. toctree::
    +   :maxdepth: 2
    +   :caption: Community
    +
    +   community/contributing.md
    +   community/pr.md
    +
    +.. toctree::
    +   :maxdepth: 1
    +   :caption: API Reference
    +
    +   mmcv.image 
    +   mmcv.video 
    +   mmcv.visualization 
    +   mmcv.cnn 
    +   mmcv.ops 
    +   mmcv.transforms 
    +   mmcv.arraymisc 
    +   mmcv.utils 
    +
    +Indices and tables
    +==================
    +
    +* :ref:`genindex`
    +* :ref:`search`
    diff --git a/cv/distiller/CWD/mmcv/docs/en/make.bat b/cv/distiller/CWD/mmcv/docs/en/make.bat
    new file mode 100644
    index 000000000..7893348a1
    --- /dev/null
    +++ b/cv/distiller/CWD/mmcv/docs/en/make.bat
    @@ -0,0 +1,35 @@
    +@ECHO OFF
    +
    +pushd %~dp0
    +
    +REM Command file for Sphinx documentation
    +
    +if "%SPHINXBUILD%" == "" (
    +	set SPHINXBUILD=sphinx-build
    +)
    +set SOURCEDIR=.
    +set BUILDDIR=_build
    +
    +if "%1" == "" goto help
    +
    +%SPHINXBUILD% >NUL 2>NUL
    +if errorlevel 9009 (
    +	echo.
    +	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
    +	echo.installed, then set the SPHINXBUILD environment variable to point
    +	echo.to the full path of the 'sphinx-build' executable. Alternatively you
    +	echo.may add the Sphinx directory to PATH.
    +	echo.
    +	echo.If you don't have Sphinx installed, grab it from
    +	echo.http://sphinx-doc.org/
    +	exit /b 1
    +)
    +
    +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
    +goto end
    +
    +:help
    +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
    +
    +:end
    +popd
    diff --git a/cv/distiller/CWD/mmcv/docs/en/mmcv-logo.png b/cv/distiller/CWD/mmcv/docs/en/mmcv-logo.png
    new file mode 100644
    index 0000000000000000000000000000000000000000..bcc5759f8fe3bc7d191d411c38a9e1d3c1c27a84
    GIT binary patch
    literal 27173
    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%0AQ*iFD0(!vwq&^
    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%0ArY%0TZ=nd2Ec8
    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
    + +## 简体中文 diff --git a/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/cnn.md b/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/cnn.md new file mode 100644 index 000000000..2c42f25d9 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/cnn.md @@ -0,0 +1,120 @@ +## CNN + +We provide some building bricks for CNNs, including layer building, module bundles and weight initialization. + +### Layer building + +We may need to try different layers of the same type when running experiments, +but do not want to modify the code from time to time. +Here we provide some layer building methods to construct layers from a dict, +which can be written in configs or specified via command line arguments. + +#### Usage + +A simplest example is + +```python +from mmcv.cnn import build_conv_layer + +cfg = dict(type='Conv3d') +layer = build_conv_layer(cfg, in_channels=3, out_channels=8, kernel_size=3) +``` + +- `build_conv_layer`: Supported types are Conv1d, Conv2d, Conv3d, Conv (alias for Conv2d). +- `build_norm_layer`: Supported types are BN1d, BN2d, BN3d, BN (alias for BN2d), SyncBN, GN, LN, IN1d, IN2d, IN3d, IN (alias for IN2d). +- `build_activation_layer`: Supported types are ReLU, LeakyReLU, PReLU, RReLU, ReLU6, ELU, Sigmoid, Tanh, GELU. +- `build_upsample_layer`: Supported types are nearest, bilinear, deconv, pixel_shuffle. +- `build_padding_layer`: Supported types are zero, reflect, replicate. + +#### Extension + +We also allow extending the building methods with custom layers and operators. + +1. Write and register your own module. + + ```python + from mmengine.registry import MODELS + + @MODELS.register_module() + class MyUpsample: + + def __init__(self, scale_factor): + pass + + def forward(self, x): + pass + ``` + +2. Import `MyUpsample` somewhere (e.g., in `__init__.py`) and then use it. + + ```python + from mmcv.cnn import build_upsample_layer + + cfg = dict(type='MyUpsample', scale_factor=2) + layer = build_upsample_layer(cfg) + ``` + +### Module bundles + +We also provide common module bundles to facilitate the network construction. +`ConvModule` is a bundle of convolution, normalization and activation layers, +please refer to the [api](api.html#mmcv.cnn.ConvModule) for details. + +```python +from mmcv.cnn import ConvModule + +# conv + bn + relu +conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN')) +# conv + gn + relu +conv = ConvModule(3, 8, 2, norm_cfg=dict(type='GN', num_groups=2)) +# conv + relu +conv = ConvModule(3, 8, 2) +# conv +conv = ConvModule(3, 8, 2, act_cfg=None) +# conv + leaky relu +conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='LeakyReLU')) +# bn + conv + relu +conv = ConvModule( + 3, 8, 2, norm_cfg=dict(type='BN'), order=('norm', 'conv', 'act')) +``` + +### Model Zoo + +Besides torchvision pre-trained models, we also provide pre-trained models of following CNN: + +- VGG Caffe +- ResNet Caffe +- ResNeXt +- ResNet with Group Normalization +- ResNet with Group Normalization and Weight Standardization +- HRNetV2 +- Res2Net +- RegNet + +#### Model URLs in JSON + +The model zoo links in MMCV are managed by JSON files. +The json file consists of key-value pair of model name and its url or path. +An example json file could be like: + +```json +{ + "model_a": "https://example.com/models/model_a_9e5bac.pth", + "model_b": "pretrain/model_b_ab3ef2c.pth" +} +``` + +The default links of the pre-trained models hosted on OpenMMLab AWS could be found [here](https://github.com/open-mmlab/mmcv/blob/master/mmcv/model_zoo/open_mmlab.json). + +You may override default links by putting `open-mmlab.json` under `MMCV_HOME`. If `MMCV_HOME` is not found in your environment, `~/.cache/mmcv` will be used by default. You may use your own path with `export MMCV_HOME=/your/path`. + +The external json files will be merged into default one. If the same key presents in both external json and default json, the external one will be used. + +#### Load Checkpoint + +The following types are supported for `filename` of `mmcv.load_checkpoint()`. + +- filepath: The filepath of the checkpoint. +- `http://xxx` and `https://xxx`: The link to download the checkpoint. The `SHA256` postfix should be contained in the filename. +- `torchvision://xxx`: The model links in `torchvision.models`. Please refer to [torchvision](https://pytorch.org/docs/stable/torchvision/models.html) for details. +- `open-mmlab://xxx`: The model links or filepath provided in default and additional json files. diff --git a/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_process.md b/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_process.md new file mode 100644 index 000000000..167928f88 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_process.md @@ -0,0 +1,286 @@ +## Data Process + +### Image + +This module provides some image processing methods, which requires `opencv` to be installed first. + +#### Read/Write/Show + +To read or write images files, use `imread` or `imwrite`. + +```python +import mmcv + +img = mmcv.imread('test.jpg') +img = mmcv.imread('test.jpg', flag='grayscale') +img_ = mmcv.imread(img) # nothing will happen, img_ = img +mmcv.imwrite(img, 'out.jpg') +``` + +To read images from bytes + +```python +with open('test.jpg', 'rb') as f: + data = f.read() +img = mmcv.imfrombytes(data) +``` + +To show an image file or a loaded image + +```python +mmcv.imshow('tests/data/color.jpg') +# this is equivalent to + +for i in range(10): + img = np.random.randint(256, size=(100, 100, 3), dtype=np.uint8) + mmcv.imshow(img, win_name='test image', wait_time=200) +``` + +#### Color space conversion + +Supported conversion methods: + +- bgr2gray +- gray2bgr +- bgr2rgb +- rgb2bgr +- bgr2hsv +- hsv2bgr + +```python +img = mmcv.imread('tests/data/color.jpg') +img1 = mmcv.bgr2rgb(img) +img2 = mmcv.rgb2gray(img1) +img3 = mmcv.bgr2hsv(img) +``` + +#### Resize + +There are three resize methods. All `imresize_*` methods have an argument `return_scale`, +if this argument is `False`, then the return value is merely the resized image, otherwise +is a tuple `(resized_img, scale)`. + +```python +# resize to a given size +mmcv.imresize(img, (1000, 600), return_scale=True) + +# resize to the same size of another image +mmcv.imresize_like(img, dst_img, return_scale=False) + +# resize by a ratio +mmcv.imrescale(img, 0.5) + +# resize so that the max edge no longer than 1000, short edge no longer than 800 +# without changing the aspect ratio +mmcv.imrescale(img, (1000, 800)) +``` + +#### Rotate + +To rotate an image by some angle, use `imrotate`. The center can be specified, +which is the center of original image by default. There are two modes of rotating, +one is to keep the image size unchanged so that some parts of the image will be +cropped after rotating, the other is to extend the image size to fit the rotated +image. + +```python +img = mmcv.imread('tests/data/color.jpg') + +# rotate the image clockwise by 30 degrees. +img_ = mmcv.imrotate(img, 30) + +# rotate the image counterclockwise by 90 degrees. +img_ = mmcv.imrotate(img, -90) + +# rotate the image clockwise by 30 degrees, and rescale it by 1.5x at the same time. +img_ = mmcv.imrotate(img, 30, scale=1.5) + +# rotate the image clockwise by 30 degrees, with (100, 100) as the center. +img_ = mmcv.imrotate(img, 30, center=(100, 100)) + +# rotate the image clockwise by 30 degrees, and extend the image size. +img_ = mmcv.imrotate(img, 30, auto_bound=True) +``` + +#### Flip + +To flip an image, use `imflip`. + +```python +img = mmcv.imread('tests/data/color.jpg') + +# flip the image horizontally +mmcv.imflip(img) + +# flip the image vertically +mmcv.imflip(img, direction='vertical') +``` + +#### Crop + +`imcrop` can crop the image with one or more regions. Each region is represented by the upper left and lower right coordinates as (x1, y1, x2, y2). + +```python +import mmcv +import numpy as np + +img = mmcv.imread('tests/data/color.jpg') + +# crop the region (10, 10, 100, 120) +bboxes = np.array([10, 10, 100, 120]) +patch = mmcv.imcrop(img, bboxes) + +# crop two regions (10, 10, 100, 120) and (0, 0, 50, 50) +bboxes = np.array([[10, 10, 100, 120], [0, 0, 50, 50]]) +patches = mmcv.imcrop(img, bboxes) + +# crop two regions, and rescale the patches by 1.2x +patches = mmcv.imcrop(img, bboxes, scale=1.2) +``` + +#### Padding + +There are two methods, `impad` and `impad_to_multiple`, to pad an image to the +specific size with given values. + +```python +img = mmcv.imread('tests/data/color.jpg') + +# pad the image to (1000, 1200) with all zeros +img_ = mmcv.impad(img, shape=(1000, 1200), pad_val=0) + +# pad the image to (1000, 1200) with different values for three channels. +img_ = mmcv.impad(img, shape=(1000, 1200), pad_val=(100, 50, 200)) + +# pad the image on left, right, top, bottom borders with all zeros +img_ = mmcv.impad(img, padding=(10, 20, 30, 40), pad_val=0) + +# pad the image on left, right, top, bottom borders with different values +# for three channels. +img_ = mmcv.impad(img, padding=(10, 20, 30, 40), pad_val=(100, 50, 200)) + +# pad an image so that each edge is a multiple of some value. +img_ = mmcv.impad_to_multiple(img, 32) +``` + +### Video + +This module provides the following functionalities: + +- A `VideoReader` class with friendly apis to read and convert videos. +- Some methods for editing (cut, concat, resize) videos. +- Optical flow read/write/warp. + +#### VideoReader + +The `VideoReader` class provides sequence like apis to access video frames. +It will internally cache the frames which have been visited. + +```python +video = mmcv.VideoReader('test.mp4') + +# obtain basic information +print(len(video)) +print(video.width, video.height, video.resolution, video.fps) + +# iterate over all frames +for frame in video: + print(frame.shape) + +# read the next frame +img = video.read() + +# read a frame by index +img = video[100] + +# read some frames +img = video[5:10] +``` + +To convert a video to images or generate a video from a image directory. + +```python +# split a video into frames and save to a folder +video = mmcv.VideoReader('test.mp4') +video.cvt2frames('out_dir') + +# generate video from frames +mmcv.frames2video('out_dir', 'test.avi') +``` + +#### Editing utils + +There are also some methods for editing videos, which wraps the commands of ffmpeg. + +```python +# cut a video clip +mmcv.cut_video('test.mp4', 'clip1.mp4', start=3, end=10, vcodec='h264') + +# join a list of video clips +mmcv.concat_video(['clip1.mp4', 'clip2.mp4'], 'joined.mp4', log_level='quiet') + +# resize a video with the specified size +mmcv.resize_video('test.mp4', 'resized1.mp4', (360, 240)) + +# resize a video with a scaling ratio of 2 +mmcv.resize_video('test.mp4', 'resized2.mp4', ratio=2) +``` + +#### Optical flow + +`mmcv` provides the following methods to operate on optical flows. + +- IO +- Visualization +- Flow warping + +We provide two options to dump optical flow files: uncompressed and compressed. +The uncompressed way just dumps the floating numbers to a binary file. It is +lossless but the dumped file has a larger size. +The compressed way quantizes the optical flow to 0-255 and dumps it as a +jpeg image. The flow of x-dim and y-dim will be concatenated into a single image. + +1. IO + +```python +flow = np.random.rand(800, 600, 2).astype(np.float32) +# dump the flow to a flo file (~3.7M) +mmcv.flowwrite(flow, 'uncompressed.flo') +# dump the flow to a jpeg file (~230K) +# the shape of the dumped image is (800, 1200) +mmcv.flowwrite(flow, 'compressed.jpg', quantize=True, concat_axis=1) + +# read the flow file, the shape of loaded flow is (800, 600, 2) for both ways +flow = mmcv.flowread('uncompressed.flo') +flow = mmcv.flowread('compressed.jpg', quantize=True, concat_axis=1) +``` + +2. Visualization + +It is possible to visualize optical flows with `mmcv.flowshow()`. + +```python +mmcv.flowshow(flow) +``` + +![progress](../_static/flow_visualization.png) + +3. Flow warping + +```python +img1 = mmcv.imread('img1.jpg') +flow = mmcv.flowread('flow.flo') +warped_img2 = mmcv.flow_warp(img1, flow) +``` + +img1 (left) and img2 (right) + +![raw images](../_static/flow_raw_images.png) + +optical flow (img2 -> img1) + +![optical flow](../_static/flow_img2toimg1.png) + +warped image and difference with ground truth + +![warped image](../_static/flow_warp_diff.png) diff --git a/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_transform.md b/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_transform.md new file mode 100644 index 000000000..64c3af980 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_transform.md @@ -0,0 +1,341 @@ +# Data Transformation + +In the OpenMMLab algorithm library, dataset construction and data preparation are decoupled. Usually, the construction of the dataset only parses the dataset and records the basic information of each sample, while the data preparation is a series of data transformations including data loading, preprocessing, formatting, and other operations performed according to the basic information of the sample. + +## Design of data transformation + +In MMCV, we use various callable data transformation classes to manipulate data. These data transformation classes can accept several configuration parameters for the instantiation and then process the input data dictionary by `__call__` method. All data transformation methods accept a dictionary as the input and produce the output as a dictionary as well. A simple example is as follows: + +```python +>>> import numpy as np +>>> from mmcv.transforms import Resize +>>> +>>> transform = Resize(scale=(224, 224)) +>>> data_dict = {'img': np.random.rand(256, 256, 3)} +>>> data_dict = transform(data_dict) +>>> print(data_dict['img'].shape) +(224, 224, 3) +``` + +The data transformation class reads some fields of the input dictionary and may add or update some fields. The keys of these fields are mostly fixed. For example, `Resize` will always read fields such as `"img"` in the input dictionary. More information about the conventions for input and output fields could be found in the documentation of the corresponding class. + +```{note} +By convention, the order of image shape which is used as **initialization parameters** in data transformation (such as Resize, Pad) is (width, height). In the dictionary returned by the data transformation, the image related shape, such as `img_shape`, `ori_shape`, `pad_shape`, etc., is (height, width). +``` + +MMCV provides a unified base class called `BaseTransform` for all data transformation classes: + +```python +class BaseTransform(metaclass=ABCMeta): + + def __call__(self, results: dict) -> dict: + + return self.transform(results) + + @abstractmethod + def transform(self, results: dict) -> dict: + pass +``` + +All data transformation classes must inherit `BaseTransform` and implement the `transform` method. Both the input and output of the `transform` method are a dictionary. In the **Custom data transformation class** section, we will describe how to implement a data transformation class in more detail. + +## Data pipeline + +As mentioned above, the inputs and outputs of all data transformations are dictionaries. Moreover, according to the \[Convention on Datasets\] (TODO) in OpenMMLab, the basic information of each sample in the dataset is also a dictionary. This way, we can connect all data transformation operations end to end and combine them into a data pipeline. This pipeline inputs the information dictionary of the samples in the dataset and outputs the information dictionary after a series of processing. + +Taking the classification task as an example, we show a typical data pipeline in the figure below. For each sample, the information stored in the dataset is a dictionary, as shown on the far left in the figure. After each data transformation operation represented by the blue block, a new field (marked in green) will be added to the data dictionary or an existing field (marked in orange) will be updated. + +
    + +
    + +The data pipeline is a list of several data transformation configuration dictionaries in the configuration file. Each dataset needs to set the parameter `pipeline` to define the data preparation operations the dataset needs to perform. The configuration of the above data pipeline in the configuration file is as follows: + +```python +pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='Resize', size=256, keep_ratio=True), + dict(type='CenterCrop', crop_size=224), + dict(type='Normalize', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375]), + dict(type='ClsFormatBundle') +] + +dataset = dict( + ... + pipeline=pipeline, + ... +) +``` + +## Common data transformation classes + +The commonly used data transformation classes can be roughly divided into data loading, data preprocessing and augmentation, and data formatting. In MMCV, we provide some commonly used classes as follows: + +### Data loading + +To support the loading of large-scale datasets, data is usually not loaded when `Dataset` is initialized. Only the corresponding path is loaded. Therefore, it is necessary to load specific data in the data pipeline. + +| Class | Feature | +| :-------------------------: | :--------------------------------------------: | +| [`LoadImageFromFile`](TODO) | Load from file path | +| [`LoadAnnotations`](TODO) | Load and organize the annotations (bbox, etc.) | + +### Data preprocessing and enhancement + +Data preprocessing and augmentation usually involve transforming the image itself, such as cropping, padding, scaling, etc. + +| Class | Feature | +| :------------------------------: | :----------------------------------------------------: | +| [`Pad`](TODO) | Padding | +| [`CenterCrop`](TODO) | Center crop | +| [`Normalize`](TODO) | Image normalization | +| [`Resize`](TODO) | Resize to the specified size or ratio | +| [`RandomResize`](TODO) | Scale the image randomly within the specified range | +| [`RandomMultiscaleResize`](TODO) | Scale the image to a random size from multiple options | +| [`RandomGrayscale`](TODO) | Random grayscale | +| [`RandomFlip`](TODO) | Random flip | +| [`MultiScaleFlipAug`](TODO) | Support scaling and flipping during the testing | + +### Data formatting + +Data formatting operations are type conversions performed on the data. + +| Class | Feature | +| :---------------------: | :------------------------------------------: | +| [`ToTensor`](TODO) | Convert the specified data to `torch.Tensor` | +| [`ImageToTensor`](TODO) | Convert the image to `torch.Tensor` | + +## Customize data transformation classes + +To implement a new data transformation class, you must inherit `BaseTransform` and implement the `transform` method. Here, we use a simple flip transform (`MyFlip`) as an example: + +```python +import random +import mmcv +from mmcv.transforms import BaseTransform, TRANSFORMS + +@TRANSFORMS.register_module() +class MyFlip(BaseTransform): + def __init__(self, direction: str): + super().__init__() + self.direction = direction + + def transform(self, results: dict) -> dict: + img = results['img'] + results['img'] = mmcv.imflip(img, direction=self.direction) + return results +``` + +Now, we can instantiate `MyFlip` as a callable object to handle our data dictionary. + +```python +import numpy as np + +transform = MyFlip(direction='horizontal') +data_dict = {'img': np.random.rand(224, 224, 3)} +data_dict = transform(data_dict) +processed_img = data_dict['img'] +``` + +Alternatively, use `MyFlip` transform in the `pipeline` of the config file. + +```python +pipeline = [ + ... + dict(type='MyFlip', direction='horizontal'), + ... +] +``` + +It should be noted that if you want to use it in the configuration file, you must ensure that the file where the `MyFlip` class is located can be imported at the runtime. + +## Transform wrapper + +Transform wrappers are a special class of data transformations. They do not operate on images, labels or other information in the data dictionary by themselves. Instead, they enhance the behavior of data transformations defined in them. + +### KeyMapper + +`KeyMapper` is used to map fields in the data dictionary. For example, image processing transforms usually get their values from the `"img"` field in the data dictionary. But sometimes we want these transforms to handle images in other fields in the data dictionary, such as the `"gt_img"` field. + +When used with registry and configuration file, the field map wrapper should be used as follows: + +```python +pipeline = [ + ... + dict(type='KeyMapper', + mapping={ + 'img': 'gt_img', # map "gt_img" to "img" + 'mask': ..., # The "mask" field in the raw data is not used. That is, for wrapped data transformations, the "mask" field is not included in the data + }, + auto_remap=True, # remap "img" back to "gt_img" after the transformation + transforms=[ + # only need to specify "img" in `RandomFlip` + dict(type='RandomFlip'), + ]) + ... +] +``` + +With `KeyMapper`, we don't need to consider various possible input field names in the `transform` method when we implement the data transformation class. We only need to deal with the default fields. + +### RandomChoice and RandomApply + +`RandomChoice` is used to randomly select a data transformation pipeline from the given choices. With this wrapper, we can easily implement some data augmentation functions, such as AutoAugment. + +In configuration file, you can use `RandomChoice` as follows: + +```python +pipeline = [ + ... + dict(type='RandomChoice', + transforms=[ + [ + dict(type='Posterize', bits=4), + dict(type='Rotate', angle=30.) + ], # the first combo option + [ + dict(type='Equalize'), + dict(type='Rotate', angle=30) + ], # the second combo option + ], + prob=[0.4, 0.6] # the prob of each combo + ) + ... +] +``` + +`RandomApply` is used to randomly perform a combination of data transformations with a specified probability. For example: + +```python +pipeline = [ + ... + dict(type='RandomApply', + transforms=[dict(type='Rotate', angle=30.)], + prob=0.3) # perform the transformation with prob as 0.3 + ... +] +``` + +### TransformBroadcaster + +Usually, a data transformation class only reads the target of an operation from one field. While we can also use `KeyMapper` to change the fields read, there is no way to apply transformations to the data of multiple fields at once. To achieve this, we need to use the multi-target extension wrapper `TransformBroadcaster`. + +`TransformBroadcaster` has two uses, one is to apply data transformation to multiple specified fields, and the other is to apply data transformation to a group of targets under a field. + +1. Apply to multiple fields + + Suppose we need to apply a data transformation to images in two fields `"lq"` (low-quality) and `"gt"` (ground-truth). + + ```python + pipeline = [ + dict(type='TransformBroadcaster', + # apply to the "lq" and "gt" fields respectively, and set the "img" field to both + mapping={'img': ['lq', 'gt']}, + # remap the "img" field back to the original field after the transformation + auto_remap=True, + # whether to share random variables in the transformation of each target + # more introduction will be referred in the following chapters (random variable sharing) + share_random_params=True, + transforms=[ + # only need to manipulate the "img" field in the `RandomFlip` class + dict(type='RandomFlip'), + ]) + ] + ``` + + In the `mapping` setting of the multi-target extension, we can also use `...` to ignore the specified original field. As shown in the following example, the wrapped `RandomCrop` will crop the image in the field `"img"` and update the size of the cropped image if the field `"img_shape"` exists. If we want to do the same random cropping for both image fields `"lq"` and `"gt"` at the same time but update the `"img_shape"` field only once, we can do it as in the example: + + ```python + pipeline = [ + dict(type='TransformBroadcaster', + mapping={ + 'img': ['lq', 'gt'], + 'img_shape': ['img_shape', ...], + }, + # remap the "img" and "img_shape" fields back to their original fields after the transformation + auto_remap=True, + # whether to share random variables in the transformation of each target + # more introduction will be referred in the following chapters (random variable sharing) + share_random_params=True, + transforms=[ + # "img" and "img_shape" fields are manipulated in the `RandomCrop` class + # if "img_shape" is missing, only operate on "img" + dict(type='RandomCrop'), + ]) + ] + ``` + +2. A set of targets applied to a field + + Suppose we need to apply a data transformation to the `"images"` field, which is a list of images. + + ```python + pipeline = [ + dict(type='TransformBroadcaster', + # map each image under the "images" field to the "img" field + mapping={'img': 'images'}, + # remap the images under the "img" field back to the list in the "images" field after the transformation + auto_remap=True, + # whether to share random variables in the transformation of each target + share_random_params=True, + transforms=[ + # in the `RandomFlip` transformation class, we only need to manipulate the "img" field + dict(type='RandomFlip'), + ]) + ] + ``` + +#### Decorator `cache_randomness` + +In `TransformBroadcaster`, we provide the `share_random_params` option to support sharing random states across multiple data transformations. For example, in a super-resolution task, we want to apply **the same** random transformations **simultaneously** to the low-resolution image and the original image. If we use this function in a custom data transformation class, we need to mark which random variables support sharing in the class. This can be achieved with the decorator `cache_randomness`. + +Taking `MyFlip` from the above example, we want to perform flipping randomly with a certain probability: + +```python +from mmcv.transforms.utils import cache_randomness + +@TRANSFORMS.register_module() +class MyRandomFlip(BaseTransform): + def __init__(self, prob: float, direction: str): + super().__init__() + self.prob = prob + self.direction = direction + + @cache_randomness # label the output of the method as a shareable random variable + def do_flip(self): + flip = True if random.random() > self.prob else False + return flip + + def transform(self, results: dict) -> dict: + img = results['img'] + if self.do_flip(): + results['img'] = mmcv.imflip(img, direction=self.direction) + return results +``` + +In the above example, we decorate the `do_flip` method with `cache_randomness`, marking the method return value `flip` as a random variable that supports sharing. Therefore, in the transformation of `TransformBroadcaster` to multiple targets, the value of this variable will remain the same. + +#### Decorator `avoid_cache_randomness` + +In some cases, we cannot separate the process of generating random variables in data transformation into a class method. For example, modules from third-party libraries used in data transformation encapsulate the relevant parts of random variables inside, making them impossible to be extracted as class methods for data transformation. Such data transformations cannot support shared random variables through the decorator `cache_randomness` annotation, and thus cannot share random variables during multi-objective expansion. + +To avoid misuse of such data transformations in multi-object extensions, we provide another decorator, `avoid_cache_randomness`, to mark such data transformations: + +```python +from mmcv.transforms.utils import avoid_cache_randomness + +@TRANSFORMS.register_module() +@avoid_cache_randomness +class MyRandomTransform(BaseTransform): + + def transform(self, results: dict) -> dict: + ... +``` + +Data transformation classes marked with `avoid_cache_randomness` will throw an exception when their instance is wrapped by `TransformBroadcaster` and the parameter `share_random_params` is set to True. This reminds the user not to use it in this way. + +There are a few things to keep in mind when using `avoid_cache_randomness`: + +1. `avoid_cache_randomness` is only used to decorate data transformation classes (subclasses of `BaseTransfrom`) and cannot be used to decorate other general classes, class methods, or functions +2. When a data transformation decorated with `avoid_cache_randomness` is used as a base class, its subclasses **will not inherit** its feature. If the subclass is still unable to share random variables, `avoid_cache_randomness` should be used again. +3. A data transformation needs to be modified with `avoid_cache_randomness` only when a data transformation is random and cannot share its random parameters. Data transformations without randomness require no decoration diff --git a/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/ops.md b/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/ops.md new file mode 100644 index 000000000..5579cd775 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/ops.md @@ -0,0 +1,63 @@ +## ops + +We implement common ops used in detection, segmentation, etc. + +| Device | CPU | CUDA | MLU | MPS | Ascend | +| ---------------------------- | --- | ---- | --- | --- | ------ | +| ActiveRotatedFilter | √ | √ | | | | +| AssignScoreWithK | | √ | | | | +| BallQuery | | √ | | | | +| BBoxOverlaps | | √ | √ | √ | | +| BorderAlign | | √ | | | | +| BoxIouRotated | √ | √ | | | | +| BoxIouQuadri | √ | √ | | | | +| CARAFE | | √ | √ | | | +| ChamferDistance | | √ | | | | +| CrissCrossAttention | | √ | | | | +| ContourExpand | √ | | | | | +| ConvexIoU | | √ | | | | +| CornerPool | | √ | | | | +| Correlation | | √ | | | | +| Deformable Convolution v1/v2 | √ | √ | | | √ | +| Deformable RoIPool | | √ | √ | | √ | +| DiffIoURotated | | √ | | | | +| DynamicScatter | | √ | | | | +| FurthestPointSample | | √ | | | | +| FurthestPointSampleWithDist | | √ | | | | +| FusedBiasLeakyrelu | | √ | | | √ | +| GatherPoints | | √ | | | | +| GroupPoints | | √ | | | | +| Iou3d | | √ | √ | | | +| KNN | | √ | | | | +| MaskedConv | | √ | √ | | √ | +| MergeCells | | √ | | | | +| MinAreaPolygon | | √ | | | | +| ModulatedDeformConv2d | √ | √ | | | √ | +| MultiScaleDeformableAttn | | √ | √ | | | +| NMS | √ | √ | √ | | √ | +| NMSRotated | √ | √ | | | | +| NMSQuadri | √ | √ | | | | +| PixelGroup | √ | | | | | +| PointsInBoxes | √ | √ | | | | +| PointsInPolygons | | √ | | | | +| PSAMask | √ | √ | √ | | √ | +| RotatedFeatureAlign | √ | √ | | | | +| RoIPointPool3d | | √ | √ | | | +| RoIPool | | √ | √ | | √ | +| RoIAlignRotated | √ | √ | √ | | | +| RiRoIAlignRotated | | √ | | | | +| RoIAlign | √ | √ | √ | | | +| RoIAwarePool3d | | √ | √ | | | +| SAConv2d | | √ | | | | +| SigmoidFocalLoss | | √ | √ | | √ | +| SoftmaxFocalLoss | | √ | | | √ | +| SoftNMS | | √ | | | | +| Sparse Convolution | | √ | | | | +| Synchronized BatchNorm | | √ | | | | +| ThreeInterpolate | | √ | | | | +| ThreeNN | | √ | √ | | | +| TINShift | | √ | √ | | | +| UpFirDn2d | | √ | | | | +| Voxelization | √ | √ | | | | +| PrRoIPool | | √ | | | | +| BezierAlign | √ | √ | | | | diff --git a/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/visualization.md b/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/visualization.md new file mode 100644 index 000000000..968e35058 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/visualization.md @@ -0,0 +1,24 @@ +## Visualization + +`mmcv` can show images and annotations (currently supported types include bounding boxes). + +```python +# show an image file +mmcv.imshow('a.jpg') + +# show a loaded image +img = np.random.rand(100, 100, 3) +mmcv.imshow(img) + +# show image with bounding boxes +img = np.random.rand(100, 100, 3) +bboxes = np.array([[0, 0, 50, 50], [20, 20, 60, 60]]) +mmcv.imshow_bboxes(img, bboxes) +``` + +`mmcv` can also visualize special images such as optical flows. + +```python +flow = mmcv.flowread('test.flo') +mmcv.flowshow(flow) +``` diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/Makefile b/cv/distiller/CWD/mmcv/docs/zh_cn/Makefile new file mode 100644 index 000000000..51285967a --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/zh_cn/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/_static/css/readthedocs.css b/cv/distiller/CWD/mmcv/docs/zh_cn/_static/css/readthedocs.css new file mode 100644 index 000000000..9e3a567d5 --- /dev/null +++ b/cv/distiller/CWD/mmcv/docs/zh_cn/_static/css/readthedocs.css @@ -0,0 +1,10 @@ +.header-logo { + background-image: url("../image/mmcv-logo.png"); + background-size: 85px 40px; + height: 40px; + width: 85px; +} + +table.colwidths-auto td { + width: 50% +} diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/_static/image/mmcv-logo.png b/cv/distiller/CWD/mmcv/docs/zh_cn/_static/image/mmcv-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bcc5759f8fe3bc7d191d411c38a9e1d3c1c27a84 GIT binary patch literal 27173 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%0AQ*iFD0(!vwq&^ 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%0ArY%0TZ=nd2Ec8 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
  • +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 literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/pad_4.npy b/cv/distiller/CWD/mmcv/tests/data/patches/pad_4.npy new file mode 100644 index 0000000000000000000000000000000000000000..f41c7d0079d8bffa100361ec1b600855ee012fd4 GIT binary patch literal 193940 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 NaF!R8wr1<^{{|OF162S3 literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/scale_1.npy b/cv/distiller/CWD/mmcv/tests/data/patches/scale_1.npy new file mode 100644 index 0000000000000000000000000000000000000000..721fddcf0623857818cd1ce11a594ade4da74222 GIT binary patch literal 55358 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

    &u@*_+qEUys|$?E7Et3wh@cYkeN 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 literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/scale_2.npy b/cv/distiller/CWD/mmcv/tests/data/patches/scale_2.npy new file mode 100644 index 0000000000000000000000000000000000000000..fb24241dc75ac64b8a7d37fda05831a019d363f6 GIT binary patch literal 54530 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 X*73RfgqFcc^A9=!f*BW{0Al|id1fog literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/scale_4.npy b/cv/distiller/CWD/mmcv/tests/data/patches/scale_4.npy new file mode 100644 index 0000000000000000000000000000000000000000..e9488e025df775fb19949266fed8ba0b55c6ac8f GIT binary patch literal 162080 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 literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/tests/data/scripts/hello.py b/cv/distiller/CWD/mmcv/tests/data/scripts/hello.py new file mode 100644 index 000000000..2ed1a1e31 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/data/scripts/hello.py @@ -0,0 +1,25 @@ +# Copyright (c) OpenMMLab. All rights reserved. +#!/usr/bin/env python + +import argparse +import warnings + + +def parse_args(): + parser = argparse.ArgumentParser(description='Say hello.') + parser.add_argument('name', help='To whom.') + + args = parser.parse_args() + + return args + + +def main(): + args = parse_args() + print(f'hello {args.name}!') + if args.name == 'agent': + warnings.warn('I have a secret!') + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmcv/tests/data/sparse_flow.png b/cv/distiller/CWD/mmcv/tests/data/sparse_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..6d529602745b4a8d48ebadd4fee86630ac59906c GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^k{~R=1SF-U&y@qIKu;IP5D(t72N`*Rye5Me_h&{P xzTaW*_Q&v1zhHgOkK`lr%Ks!j9w%0a`Nbx~Z9+djdjgGP@O1TaS?83{1OS-LGjjj{ literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/tests/data/test.mp4 b/cv/distiller/CWD/mmcv/tests/data/test.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..50db28101cba4b56d2478d03e3e6de71c23f1f24 GIT binary patch literal 300601 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≦XY)6E<8>_6e5ol2)0+Fe^tfO^h7$|(zn77*`>U^ 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

    0SRTF9 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

    t-umljtt1Tx$xf|tn?%hy))lv5n|sv$oe(2D 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 literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/tests/data/uint16-5channel.tif b/cv/distiller/CWD/mmcv/tests/data/uint16-5channel.tif new file mode 100644 index 0000000000000000000000000000000000000000..71362de2a962b605906aa795aab4ca4b42804142 GIT binary patch literal 212483 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

    ~zH#b|wN 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 e+$$LJ@WV literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/tests/test_arraymisc.py b/cv/distiller/CWD/mmcv/tests/test_arraymisc.py new file mode 100644 index 000000000..b29e5f670 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_arraymisc.py @@ -0,0 +1,70 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +import numpy as np +import pytest + +import mmcv + + +def test_quantize(): + arr = np.random.randn(10, 10) + levels = 20 + + qarr = mmcv.quantize(arr, -1, 1, levels) + assert qarr.shape == arr.shape + assert qarr.dtype == np.dtype('int64') + for i in range(arr.shape[0]): + for j in range(arr.shape[1]): + ref = min(levels - 1, + int(np.floor(10 * (1 + max(min(arr[i, j], 1), -1))))) + assert qarr[i, j] == ref + + qarr = mmcv.quantize(arr, -1, 1, 20, dtype=np.uint8) + assert qarr.shape == arr.shape + assert qarr.dtype == np.dtype('uint8') + + with pytest.raises(ValueError): + mmcv.quantize(arr, -1, 1, levels=0) + with pytest.raises(ValueError): + mmcv.quantize(arr, -1, 1, levels=10.0) + with pytest.raises(ValueError): + mmcv.quantize(arr, 2, 1, levels) + + +def test_dequantize(): + levels = 20 + qarr = np.random.randint(levels, size=(10, 10)) + + arr = mmcv.dequantize(qarr, -1, 1, levels) + assert arr.shape == qarr.shape + assert arr.dtype == np.dtype('float64') + for i in range(qarr.shape[0]): + for j in range(qarr.shape[1]): + assert arr[i, j] == (qarr[i, j] + 0.5) / 10 - 1 + + arr = mmcv.dequantize(qarr, -1, 1, levels, dtype=np.float32) + assert arr.shape == qarr.shape + assert arr.dtype == np.dtype('float32') + + with pytest.raises(ValueError): + mmcv.dequantize(arr, -1, 1, levels=0) + with pytest.raises(ValueError): + mmcv.dequantize(arr, -1, 1, levels=10.0) + with pytest.raises(ValueError): + mmcv.dequantize(arr, 2, 1, levels) + + +def test_joint(): + arr = np.random.randn(100, 100) + levels = 1000 + qarr = mmcv.quantize(arr, -1, 1, levels) + recover = mmcv.dequantize(qarr, -1, 1, levels) + assert np.abs(recover[arr < -1] + 0.999).max() < 1e-6 + assert np.abs(recover[arr > 1] - 0.999).max() < 1e-6 + assert np.abs((recover - arr)[(arr >= -1) & (arr <= 1)]).max() <= 1e-3 + + arr = np.clip(np.random.randn(100) / 1000, -0.01, 0.01) + levels = 99 + qarr = mmcv.quantize(arr, -1, 1, levels) + recover = mmcv.dequantize(qarr, -1, 1, levels) + assert np.all(recover == 0) diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_build_layers.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_build_layers.py new file mode 100644 index 000000000..c8903ac40 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_build_layers.py @@ -0,0 +1,430 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from importlib import import_module + +import numpy as np +import pytest +import torch +import torch.nn as nn +from mmengine.registry import MODELS +from mmengine.utils.dl_utils.parrots_wrapper import _BatchNorm + +from mmcv.cnn.bricks import (build_activation_layer, build_conv_layer, + build_norm_layer, build_padding_layer, + build_plugin_layer, build_upsample_layer, is_norm) +from mmcv.cnn.bricks.norm import infer_abbr as infer_norm_abbr +from mmcv.cnn.bricks.plugin import infer_abbr as infer_plugin_abbr +from mmcv.cnn.bricks.upsample import PixelShufflePack + + +def test_build_conv_layer(): + with pytest.raises(TypeError): + # cfg must be a dict + cfg = 'Conv2d' + build_conv_layer(cfg) + + with pytest.raises(KeyError): + # `type` must be in cfg + cfg = dict(kernel_size=3) + build_conv_layer(cfg) + + with pytest.raises(KeyError): + # unsupported conv type + cfg = dict(type='FancyConv') + build_conv_layer(cfg) + + kwargs = dict( + in_channels=4, out_channels=8, kernel_size=3, groups=2, dilation=2) + cfg = None + layer = build_conv_layer(cfg, **kwargs) + assert isinstance(layer, nn.Conv2d) + assert layer.in_channels == kwargs['in_channels'] + assert layer.out_channels == kwargs['out_channels'] + assert layer.kernel_size == (kwargs['kernel_size'], kwargs['kernel_size']) + assert layer.groups == kwargs['groups'] + assert layer.dilation == (kwargs['dilation'], kwargs['dilation']) + + cfg = dict(type='Conv') + layer = build_conv_layer(cfg, **kwargs) + assert isinstance(layer, nn.Conv2d) + assert layer.in_channels == kwargs['in_channels'] + assert layer.out_channels == kwargs['out_channels'] + assert layer.kernel_size == (kwargs['kernel_size'], kwargs['kernel_size']) + assert layer.groups == kwargs['groups'] + assert layer.dilation == (kwargs['dilation'], kwargs['dilation']) + + cfg = dict(type='deconv') + layer = build_conv_layer(cfg, **kwargs) + assert isinstance(layer, nn.ConvTranspose2d) + assert layer.in_channels == kwargs['in_channels'] + assert layer.out_channels == kwargs['out_channels'] + assert layer.kernel_size == (kwargs['kernel_size'], kwargs['kernel_size']) + assert layer.groups == kwargs['groups'] + assert layer.dilation == (kwargs['dilation'], kwargs['dilation']) + + # sparse convs cannot support the case when groups>1 + kwargs.pop('groups') + + for type_name, module in MODELS.module_dict.items(): + cfg = dict(type=type_name) + # SparseInverseConv2d and SparseInverseConv3d do not have the argument + # 'dilation' + if type_name == 'SparseInverseConv2d' or type_name == \ + 'SparseInverseConv3d': + kwargs.pop('dilation') + if 'conv' in type_name.lower(): + layer = build_conv_layer(cfg, **kwargs) + assert isinstance(layer, module) + assert layer.in_channels == kwargs['in_channels'] + assert layer.out_channels == kwargs['out_channels'] + kwargs['dilation'] = 2 # recover the key + + +def test_infer_norm_abbr(): + with pytest.raises(TypeError): + # class_type must be a class + infer_norm_abbr(0) + + class MyNorm: + + _abbr_ = 'mn' + + assert infer_norm_abbr(MyNorm) == 'mn' + + class FancyBatchNorm: + pass + + assert infer_norm_abbr(FancyBatchNorm) == 'bn' + + class FancyInstanceNorm: + pass + + assert infer_norm_abbr(FancyInstanceNorm) == 'in' + + class FancyLayerNorm: + pass + + assert infer_norm_abbr(FancyLayerNorm) == 'ln' + + class FancyGroupNorm: + pass + + assert infer_norm_abbr(FancyGroupNorm) == 'gn' + + class FancyNorm: + pass + + assert infer_norm_abbr(FancyNorm) == 'norm_layer' + + +def test_build_norm_layer(): + with pytest.raises(TypeError): + # cfg must be a dict + cfg = 'BN' + build_norm_layer(cfg, 3) + + with pytest.raises(KeyError): + # `type` must be in cfg + cfg = dict() + build_norm_layer(cfg, 3) + + with pytest.raises(KeyError): + # unsupported norm type + cfg = dict(type='FancyNorm') + build_norm_layer(cfg, 3) + + with pytest.raises(AssertionError): + # postfix must be int or str + cfg = dict(type='BN') + build_norm_layer(cfg, 3, postfix=[1, 2]) + + with pytest.raises(AssertionError): + # `num_groups` must be in cfg when using 'GN' + cfg = dict(type='GN') + build_norm_layer(cfg, 3) + + # test each type of norm layer in norm_cfg + abbr_mapping = { + 'BN': 'bn', + 'BN1d': 'bn', + 'BN2d': 'bn', + 'BN3d': 'bn', + 'SyncBN': 'bn', + 'GN': 'gn', + 'LN': 'ln', + 'IN': 'in', + 'IN1d': 'in', + 'IN2d': 'in', + 'IN3d': 'in', + } + for type_name, module in MODELS.module_dict.items(): + if type_name not in abbr_mapping: + continue + if type_name == 'MMSyncBN': # skip MMSyncBN + continue + for postfix in ['_test', 1]: + cfg = dict(type=type_name) + if type_name == 'GN': + cfg['num_groups'] = 3 + name, layer = build_norm_layer(cfg, 3, postfix=postfix) + assert name == abbr_mapping[type_name] + str(postfix) + assert isinstance(layer, module) + if type_name == 'GN': + assert layer.num_channels == 3 + assert layer.num_groups == cfg['num_groups'] + elif type_name != 'LN': + assert layer.num_features == 3 + + +def test_build_activation_layer(): + act_names = [ + 'ReLU', 'LeakyReLU', 'PReLU', 'RReLU', 'ReLU6', 'ELU', 'Sigmoid', + 'Tanh' + ] + + for module_name in ['activation', 'hsigmoid', 'hswish', 'swish']: + act_module = import_module(f'mmcv.cnn.bricks.{module_name}') + for key, value in act_module.__dict__.items(): + if isinstance(value, type) and issubclass(value, nn.Module): + act_names.append(key) + + with pytest.raises(TypeError): + # cfg must be a dict + cfg = 'ReLU' + build_activation_layer(cfg) + + with pytest.raises(KeyError): + # `type` must be in cfg + cfg = dict() + build_activation_layer(cfg) + + with pytest.raises(KeyError): + # unsupported activation type + cfg = dict(type='FancyReLU') + build_activation_layer(cfg) + + # test each type of activation layer in activation_cfg + for type_name, module in MODELS.module_dict.items(): + if type_name in act_names: + cfg['type'] = type_name + layer = build_activation_layer(cfg) + assert isinstance(layer, module) + + # sanity check for Clamp + act = build_activation_layer(dict(type='Clamp')) + x = torch.randn(10) * 1000 + y = act(x) + assert np.logical_and((y >= -1).numpy(), (y <= 1).numpy()).all() + act = build_activation_layer(dict(type='Clip', min=0)) + y = act(x) + assert np.logical_and((y >= 0).numpy(), (y <= 1).numpy()).all() + act = build_activation_layer(dict(type='Clamp', max=0)) + y = act(x) + assert np.logical_and((y >= -1).numpy(), (y <= 0).numpy()).all() + + +def test_build_padding_layer(): + pad_names = ['zero', 'reflect', 'replicate'] + for module_name in ['padding']: + pad_module = import_module(f'mmcv.cnn.bricks.{module_name}') + for key, value in pad_module.__dict__.items(): + if isinstance(value, type) and issubclass(value, nn.Module): + pad_names.append(key) + + with pytest.raises(TypeError): + # cfg must be a dict + cfg = 'reflect' + build_padding_layer(cfg) + + with pytest.raises(KeyError): + # `type` must be in cfg + cfg = dict() + build_padding_layer(cfg) + + with pytest.raises(KeyError): + # unsupported activation type + cfg = dict(type='FancyPad') + build_padding_layer(cfg) + + for type_name, module in MODELS.module_dict.items(): + if type_name in pad_names: + cfg['type'] = type_name + layer = build_padding_layer(cfg, 2) + assert isinstance(layer, module) + + input_x = torch.randn(1, 2, 5, 5) + cfg = dict(type='reflect') + padding_layer = build_padding_layer(cfg, 2) + res = padding_layer(input_x) + assert res.shape == (1, 2, 9, 9) + + +def test_upsample_layer(): + with pytest.raises(TypeError): + # cfg must be a dict + cfg = 'bilinear' + build_upsample_layer(cfg) + + with pytest.raises(KeyError): + # `type` must be in cfg + cfg = dict() + build_upsample_layer(cfg) + + with pytest.raises(KeyError): + # unsupported activation type + cfg = dict(type='FancyUpsample') + build_upsample_layer(cfg) + + for type_name in ['nearest', 'bilinear']: + cfg['type'] = type_name + layer = build_upsample_layer(cfg) + assert isinstance(layer, nn.Upsample) + assert layer.mode == type_name + + cfg = dict( + type='deconv', in_channels=3, out_channels=3, kernel_size=3, stride=2) + layer = build_upsample_layer(cfg) + assert isinstance(layer, nn.ConvTranspose2d) + + cfg = dict(type='deconv') + kwargs = dict(in_channels=3, out_channels=3, kernel_size=3, stride=2) + layer = build_upsample_layer(cfg, **kwargs) + assert isinstance(layer, nn.ConvTranspose2d) + assert layer.in_channels == kwargs['in_channels'] + assert layer.out_channels == kwargs['out_channels'] + assert layer.kernel_size == (kwargs['kernel_size'], kwargs['kernel_size']) + assert layer.stride == (kwargs['stride'], kwargs['stride']) + + layer = build_upsample_layer(cfg, 3, 3, 3, 2) + assert isinstance(layer, nn.ConvTranspose2d) + assert layer.in_channels == kwargs['in_channels'] + assert layer.out_channels == kwargs['out_channels'] + assert layer.kernel_size == (kwargs['kernel_size'], kwargs['kernel_size']) + assert layer.stride == (kwargs['stride'], kwargs['stride']) + + cfg = dict( + type='pixel_shuffle', + in_channels=3, + out_channels=3, + scale_factor=2, + upsample_kernel=3) + layer = build_upsample_layer(cfg) + + assert isinstance(layer, PixelShufflePack) + assert layer.scale_factor == 2 + assert layer.upsample_kernel == 3 + + +def test_pixel_shuffle_pack(): + x_in = torch.rand(2, 3, 10, 10) + pixel_shuffle = PixelShufflePack(3, 3, scale_factor=2, upsample_kernel=3) + assert pixel_shuffle.upsample_conv.kernel_size == (3, 3) + x_out = pixel_shuffle(x_in) + assert x_out.shape == (2, 3, 20, 20) + + +def test_is_norm(): + norm_set1 = [ + nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d, nn.InstanceNorm1d, + nn.InstanceNorm2d, nn.InstanceNorm3d, nn.LayerNorm + ] + norm_set2 = [nn.GroupNorm] + for norm_type in norm_set1: + layer = norm_type(3) + assert is_norm(layer) + assert not is_norm(layer, exclude=(norm_type, )) + for norm_type in norm_set2: + layer = norm_type(3, 6) + assert is_norm(layer) + assert not is_norm(layer, exclude=(norm_type, )) + + class MyNorm(nn.BatchNorm2d): + pass + + layer = MyNorm(3) + assert is_norm(layer) + assert not is_norm(layer, exclude=_BatchNorm) + assert not is_norm(layer, exclude=(_BatchNorm, )) + + layer = nn.Conv2d(3, 8, 1) + assert not is_norm(layer) + + with pytest.raises(TypeError): + layer = nn.BatchNorm1d(3) + is_norm(layer, exclude='BN') + + with pytest.raises(TypeError): + layer = nn.BatchNorm1d(3) + is_norm(layer, exclude=('BN', )) + + +def test_infer_plugin_abbr(): + with pytest.raises(TypeError): + # class_type must be a class + infer_plugin_abbr(0) + + class MyPlugin: + + _abbr_ = 'mp' + + assert infer_plugin_abbr(MyPlugin) == 'mp' + + class FancyPlugin: + pass + + assert infer_plugin_abbr(FancyPlugin) == 'fancy_plugin' + + +def test_build_plugin_layer(): + with pytest.raises(TypeError): + # cfg must be a dict + cfg = 'Plugin' + build_plugin_layer(cfg) + + with pytest.raises(KeyError): + # `type` must be in cfg + cfg = dict() + build_plugin_layer(cfg) + + with pytest.raises(KeyError): + # unsupported plugin type + cfg = dict(type='FancyPlugin') + build_plugin_layer(cfg) + + with pytest.raises(AssertionError): + # postfix must be int or str + cfg = dict(type='ConvModule') + build_plugin_layer(cfg, postfix=[1, 2]) + + # test ContextBlock + for postfix in ['', '_test', 1]: + cfg = dict(type='ContextBlock') + name, layer = build_plugin_layer( + cfg, postfix=postfix, in_channels=16, ratio=1. / 4) + assert name == 'context_block' + str(postfix) + assert isinstance(layer, MODELS.module_dict['ContextBlock']) + + # test GeneralizedAttention + for postfix in ['', '_test', 1]: + cfg = dict(type='GeneralizedAttention') + name, layer = build_plugin_layer(cfg, postfix=postfix, in_channels=16) + assert name == 'gen_attention_block' + str(postfix) + assert isinstance(layer, MODELS.module_dict['GeneralizedAttention']) + + # test NonLocal2d + for postfix in ['', '_test', 1]: + cfg = dict(type='NonLocal2d') + name, layer = build_plugin_layer(cfg, postfix=postfix, in_channels=16) + assert name == 'nonlocal_block' + str(postfix) + assert isinstance(layer, MODELS.module_dict['NonLocal2d']) + + # test ConvModule + for postfix in ['', '_test', 1]: + cfg = dict(type='ConvModule') + name, layer = build_plugin_layer( + cfg, + postfix=postfix, + in_channels=16, + out_channels=4, + kernel_size=3) + assert name == 'conv_block' + str(postfix) + assert isinstance(layer, MODELS.module_dict['ConvModule']) diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_context_block.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_context_block.py new file mode 100644 index 000000000..864cb4179 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_context_block.py @@ -0,0 +1,59 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.cnn.bricks import ContextBlock + + +def test_context_block(): + with pytest.raises(AssertionError): + # pooling_type should be in ['att', 'avg'] + ContextBlock(16, 1. / 4, pooling_type='unsupport_type') + + with pytest.raises(AssertionError): + # fusion_types should be of type list or tuple + ContextBlock(16, 1. / 4, fusion_types='unsupport_type') + + with pytest.raises(AssertionError): + # fusion_types should be in ['channel_add', 'channel_mul'] + ContextBlock(16, 1. / 4, fusion_types=('unsupport_type', )) + + # test pooling_type='att' + imgs = torch.randn(2, 16, 20, 20) + context_block = ContextBlock(16, 1. / 4, pooling_type='att') + out = context_block(imgs) + assert context_block.conv_mask.in_channels == 16 + assert context_block.conv_mask.out_channels == 1 + assert out.shape == imgs.shape + + # test pooling_type='avg' + imgs = torch.randn(2, 16, 20, 20) + context_block = ContextBlock(16, 1. / 4, pooling_type='avg') + out = context_block(imgs) + assert hasattr(context_block, 'avg_pool') + assert out.shape == imgs.shape + + # test fusion_types=('channel_add',) + imgs = torch.randn(2, 16, 20, 20) + context_block = ContextBlock(16, 1. / 4, fusion_types=('channel_add', )) + out = context_block(imgs) + assert context_block.channel_add_conv is not None + assert context_block.channel_mul_conv is None + assert out.shape == imgs.shape + + # test fusion_types=('channel_mul',) + imgs = torch.randn(2, 16, 20, 20) + context_block = ContextBlock(16, 1. / 4, fusion_types=('channel_mul', )) + out = context_block(imgs) + assert context_block.channel_add_conv is None + assert context_block.channel_mul_conv is not None + assert out.shape == imgs.shape + + # test fusion_types=('channel_add', 'channel_mul') + imgs = torch.randn(2, 16, 20, 20) + context_block = ContextBlock( + 16, 1. / 4, fusion_types=('channel_add', 'channel_mul')) + out = context_block(imgs) + assert context_block.channel_add_conv is not None + assert context_block.channel_mul_conv is not None + assert out.shape == imgs.shape diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_conv2d_adaptive_padding.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_conv2d_adaptive_padding.py new file mode 100644 index 000000000..83114bd5b --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_conv2d_adaptive_padding.py @@ -0,0 +1,28 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +from mmcv.cnn.bricks import Conv2dAdaptivePadding + + +def test_conv2d_samepadding(): + # test Conv2dAdaptivePadding with stride=1 + inputs = torch.rand((1, 3, 28, 28)) + conv = Conv2dAdaptivePadding(3, 3, kernel_size=3, stride=1) + output = conv(inputs) + assert output.shape == inputs.shape + + inputs = torch.rand((1, 3, 13, 13)) + conv = Conv2dAdaptivePadding(3, 3, kernel_size=3, stride=1) + output = conv(inputs) + assert output.shape == inputs.shape + + # test Conv2dAdaptivePadding with stride=2 + inputs = torch.rand((1, 3, 28, 28)) + conv = Conv2dAdaptivePadding(3, 3, kernel_size=3, stride=2) + output = conv(inputs) + assert output.shape == torch.Size([1, 3, 14, 14]) + + inputs = torch.rand((1, 3, 13, 13)) + conv = Conv2dAdaptivePadding(3, 3, kernel_size=3, stride=2) + output = conv(inputs) + assert output.shape == torch.Size([1, 3, 7, 7]) diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_conv_module.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_conv_module.py new file mode 100644 index 000000000..d31167a74 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_conv_module.py @@ -0,0 +1,253 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import warnings +from unittest.mock import patch + +import pytest +import torch +import torch.nn as nn +from mmengine.registry import MODELS +from mmengine.utils import digit_version +from mmengine.utils.dl_utils import TORCH_VERSION + +from mmcv.cnn.bricks import ConvModule, HSigmoid, HSwish + + +@MODELS.register_module() +class ExampleConv(nn.Module): + + def __init__(self, + in_channels, + out_channels, + kernel_size, + stride=1, + padding=0, + dilation=1, + groups=1, + bias=True, + norm_cfg=None): + super().__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.kernel_size = kernel_size + self.stride = stride + self.padding = padding + self.dilation = dilation + self.groups = groups + self.bias = bias + self.norm_cfg = norm_cfg + self.output_padding = (0, 0, 0) + self.transposed = False + + self.conv0 = nn.Conv2d(in_channels, out_channels, kernel_size) + self.init_weights() + + def forward(self, x): + x = self.conv0(x) + return x + + def init_weights(self): + nn.init.constant_(self.conv0.weight, 0) + + +def test_conv_module(): + with pytest.raises(AssertionError): + # conv_cfg must be a dict or None + conv_cfg = 'conv' + ConvModule(3, 8, 2, conv_cfg=conv_cfg) + + with pytest.raises(AssertionError): + # norm_cfg must be a dict or None + norm_cfg = 'norm' + ConvModule(3, 8, 2, norm_cfg=norm_cfg) + + with pytest.raises(KeyError): + # softmax is not supported + act_cfg = dict(type='softmax') + ConvModule(3, 8, 2, act_cfg=act_cfg) + + # conv + norm + act + conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN')) + assert conv.with_activation + assert hasattr(conv, 'activate') + assert conv.with_norm + assert hasattr(conv, 'norm') + x = torch.rand(1, 3, 256, 256) + output = conv(x) + assert output.shape == (1, 8, 255, 255) + + # conv + act + conv = ConvModule(3, 8, 2) + assert conv.with_activation + assert hasattr(conv, 'activate') + assert not conv.with_norm + assert conv.norm is None + x = torch.rand(1, 3, 256, 256) + output = conv(x) + assert output.shape == (1, 8, 255, 255) + + # conv + conv = ConvModule(3, 8, 2, act_cfg=None) + assert not conv.with_norm + assert conv.norm is None + assert not conv.with_activation + assert not hasattr(conv, 'activate') + x = torch.rand(1, 3, 256, 256) + output = conv(x) + assert output.shape == (1, 8, 255, 255) + + # conv with its own `init_weights` method + conv_module = ConvModule( + 3, 8, 2, conv_cfg=dict(type='ExampleConv'), act_cfg=None) + assert torch.equal(conv_module.conv.conv0.weight, torch.zeros(8, 3, 2, 2)) + + # with_spectral_norm=True + conv = ConvModule(3, 8, 3, padding=1, with_spectral_norm=True) + assert hasattr(conv.conv, 'weight_orig') + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + # padding_mode='reflect' + conv = ConvModule(3, 8, 3, padding=1, padding_mode='reflect') + assert isinstance(conv.padding_layer, nn.ReflectionPad2d) + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + # non-existing padding mode + with pytest.raises(KeyError): + conv = ConvModule(3, 8, 3, padding=1, padding_mode='non_exists') + + # leaky relu + conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='LeakyReLU')) + assert isinstance(conv.activate, nn.LeakyReLU) + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + # tanh + conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='Tanh')) + assert isinstance(conv.activate, nn.Tanh) + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + # Sigmoid + conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='Sigmoid')) + assert isinstance(conv.activate, nn.Sigmoid) + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + # PReLU + conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='PReLU')) + assert isinstance(conv.activate, nn.PReLU) + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + # HSwish + conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='HSwish')) + if (TORCH_VERSION == 'parrots' + or digit_version(TORCH_VERSION) < digit_version('1.7')): + assert isinstance(conv.activate, HSwish) + else: + assert isinstance(conv.activate, nn.Hardswish) + + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + # HSigmoid + conv = ConvModule(3, 8, 3, padding=1, act_cfg=dict(type='HSigmoid')) + assert isinstance(conv.activate, HSigmoid) + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + +def test_bias(): + # bias: auto, without norm + conv = ConvModule(3, 8, 2) + assert conv.conv.bias is not None + + # bias: auto, with norm + conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN')) + assert conv.conv.bias is None + + # bias: False, without norm + conv = ConvModule(3, 8, 2, bias=False) + assert conv.conv.bias is None + + # bias: True, with batch norm + with pytest.warns(UserWarning) as record: + ConvModule(3, 8, 2, bias=True, norm_cfg=dict(type='BN')) + assert len(record) == 1 + assert record[0].message.args[ + 0] == 'Unnecessary conv bias before batch/instance norm' + + # bias: True, with instance norm + with pytest.warns(UserWarning) as record: + ConvModule(3, 8, 2, bias=True, norm_cfg=dict(type='IN')) + assert len(record) == 1 + assert record[0].message.args[ + 0] == 'Unnecessary conv bias before batch/instance norm' + + # bias: True, with other norm + with pytest.warns(UserWarning) as record: + norm_cfg = dict(type='GN', num_groups=1) + ConvModule(3, 8, 2, bias=True, norm_cfg=norm_cfg) + warnings.warn('No warnings') + assert len(record) == 1 + assert record[0].message.args[0] == 'No warnings' + + +def conv_forward(self, x): + return x + '_conv' + + +def bn_forward(self, x): + return x + '_bn' + + +def relu_forward(self, x): + return x + '_relu' + + +@patch('torch.nn.ReLU.forward', relu_forward) +@patch('torch.nn.BatchNorm2d.forward', bn_forward) +@patch('torch.nn.Conv2d.forward', conv_forward) +def test_order(): + + with pytest.raises(AssertionError): + # order must be a tuple + order = ['conv', 'norm', 'act'] + ConvModule(3, 8, 2, order=order) + + with pytest.raises(AssertionError): + # length of order must be 3 + order = ('conv', 'norm') + ConvModule(3, 8, 2, order=order) + + with pytest.raises(AssertionError): + # order must be an order of 'conv', 'norm', 'act' + order = ('conv', 'norm', 'norm') + ConvModule(3, 8, 2, order=order) + + with pytest.raises(AssertionError): + # order must be an order of 'conv', 'norm', 'act' + order = ('conv', 'norm', 'something') + ConvModule(3, 8, 2, order=order) + + # ('conv', 'norm', 'act') + conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN')) + out = conv('input') + assert out == 'input_conv_bn_relu' + + # ('norm', 'conv', 'act') + conv = ConvModule( + 3, 8, 2, norm_cfg=dict(type='BN'), order=('norm', 'conv', 'act')) + out = conv('input') + assert out == 'input_bn_conv_relu' + + # ('conv', 'norm', 'act'), activate=False + conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN')) + out = conv('input', activate=False) + assert out == 'input_conv_bn' + + # ('conv', 'norm', 'act'), activate=False + conv = ConvModule(3, 8, 2, norm_cfg=dict(type='BN')) + out = conv('input', norm=False) + assert out == 'input_conv_relu' diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_depthwise_seperable_conv_module.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_depthwise_seperable_conv_module.py new file mode 100644 index 000000000..748fc1bf8 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_depthwise_seperable_conv_module.py @@ -0,0 +1,91 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch +import torch.nn as nn + +from mmcv.cnn.bricks import DepthwiseSeparableConvModule + + +def test_depthwise_separable_conv(): + with pytest.raises(AssertionError): + # conv_cfg must be a dict or None + DepthwiseSeparableConvModule(4, 8, 2, groups=2) + + # test default config + conv = DepthwiseSeparableConvModule(3, 8, 2) + assert conv.depthwise_conv.conv.groups == 3 + assert conv.pointwise_conv.conv.kernel_size == (1, 1) + assert not conv.depthwise_conv.with_norm + assert not conv.pointwise_conv.with_norm + assert conv.depthwise_conv.activate.__class__.__name__ == 'ReLU' + assert conv.pointwise_conv.activate.__class__.__name__ == 'ReLU' + x = torch.rand(1, 3, 256, 256) + output = conv(x) + assert output.shape == (1, 8, 255, 255) + + # test dw_norm_cfg + conv = DepthwiseSeparableConvModule(3, 8, 2, dw_norm_cfg=dict(type='BN')) + assert conv.depthwise_conv.norm_name == 'bn' + assert not conv.pointwise_conv.with_norm + x = torch.rand(1, 3, 256, 256) + output = conv(x) + assert output.shape == (1, 8, 255, 255) + + # test pw_norm_cfg + conv = DepthwiseSeparableConvModule(3, 8, 2, pw_norm_cfg=dict(type='BN')) + assert not conv.depthwise_conv.with_norm + assert conv.pointwise_conv.norm_name == 'bn' + x = torch.rand(1, 3, 256, 256) + output = conv(x) + assert output.shape == (1, 8, 255, 255) + + # test norm_cfg + conv = DepthwiseSeparableConvModule(3, 8, 2, norm_cfg=dict(type='BN')) + assert conv.depthwise_conv.norm_name == 'bn' + assert conv.pointwise_conv.norm_name == 'bn' + x = torch.rand(1, 3, 256, 256) + output = conv(x) + assert output.shape == (1, 8, 255, 255) + + # add test for ['norm', 'conv', 'act'] + conv = DepthwiseSeparableConvModule(3, 8, 2, order=('norm', 'conv', 'act')) + x = torch.rand(1, 3, 256, 256) + output = conv(x) + assert output.shape == (1, 8, 255, 255) + + conv = DepthwiseSeparableConvModule( + 3, 8, 3, padding=1, with_spectral_norm=True) + assert hasattr(conv.depthwise_conv.conv, 'weight_orig') + assert hasattr(conv.pointwise_conv.conv, 'weight_orig') + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + conv = DepthwiseSeparableConvModule( + 3, 8, 3, padding=1, padding_mode='reflect') + assert isinstance(conv.depthwise_conv.padding_layer, nn.ReflectionPad2d) + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + # test dw_act_cfg + conv = DepthwiseSeparableConvModule( + 3, 8, 3, padding=1, dw_act_cfg=dict(type='LeakyReLU')) + assert conv.depthwise_conv.activate.__class__.__name__ == 'LeakyReLU' + assert conv.pointwise_conv.activate.__class__.__name__ == 'ReLU' + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + # test pw_act_cfg + conv = DepthwiseSeparableConvModule( + 3, 8, 3, padding=1, pw_act_cfg=dict(type='LeakyReLU')) + assert conv.depthwise_conv.activate.__class__.__name__ == 'ReLU' + assert conv.pointwise_conv.activate.__class__.__name__ == 'LeakyReLU' + output = conv(x) + assert output.shape == (1, 8, 256, 256) + + # test act_cfg + conv = DepthwiseSeparableConvModule( + 3, 8, 3, padding=1, act_cfg=dict(type='LeakyReLU')) + assert conv.depthwise_conv.activate.__class__.__name__ == 'LeakyReLU' + assert conv.pointwise_conv.activate.__class__.__name__ == 'LeakyReLU' + output = conv(x) + assert output.shape == (1, 8, 256, 256) diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_flops_counter.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_flops_counter.py new file mode 100644 index 000000000..e2ba6e242 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_flops_counter.py @@ -0,0 +1,152 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch +import torch.nn as nn + +from mmcv.cnn import get_model_complexity_info +from mmcv.cnn.utils.flops_counter import flops_to_string, params_to_string + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +# yapf: disable +gt_results = [ + {'model': nn.Conv1d(3, 8, 3), 'input': (3, 16), 'flops': 1120.0, 'params': 80.0}, # noqa: E501 + {'model': nn.Conv2d(3, 8, 3), 'input': (3, 16, 16), 'flops': 43904.0, 'params': 224.0}, # noqa: E501 + {'model': nn.Conv3d(3, 8, 3), 'input': (3, 3, 16, 16), 'flops': 128576.0, 'params': 656.0}, # noqa: E501 + {'model': nn.ReLU(), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501 + {'model': nn.PReLU(), 'input': (3, 16, 16), 'flops': 768.0, 'params': 1}, # noqa: E501 + {'model': nn.ELU(), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501 + {'model': nn.LeakyReLU(), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501 + {'model': nn.ReLU6(), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501 + {'model': nn.MaxPool1d(2), 'input': (3, 16), 'flops': 48.0, 'params': 0}, # noqa: E501 + {'model': nn.MaxPool2d(2), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501 + {'model': nn.MaxPool3d(2), 'input': (3, 3, 16, 16), 'flops': 2304.0, 'params': 0}, # noqa: E501 + {'model': nn.AvgPool1d(2), 'input': (3, 16), 'flops': 48.0, 'params': 0}, # noqa: E501 + {'model': nn.AvgPool2d(2), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501 + {'model': nn.AvgPool3d(2), 'input': (3, 3, 16, 16), 'flops': 2304.0, 'params': 0}, # noqa: E501 + {'model': nn.AdaptiveMaxPool1d(2), 'input': (3, 16), 'flops': 48.0, 'params': 0}, # noqa: E501 + {'model': nn.AdaptiveMaxPool2d(2), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501 + {'model': nn.AdaptiveMaxPool3d(2), 'input': (3, 3, 16, 16), 'flops': 2304.0, 'params': 0}, # noqa: E501 + {'model': nn.AdaptiveAvgPool1d(2), 'input': (3, 16), 'flops': 48.0, 'params': 0}, # noqa: E501 + {'model': nn.AdaptiveAvgPool2d(2), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501 + {'model': nn.AdaptiveAvgPool3d(2), 'input': (3, 3, 16, 16), 'flops': 2304.0, 'params': 0}, # noqa: E501 + {'model': nn.BatchNorm1d(3), 'input': (3, 16), 'flops': 96.0, 'params': 6.0}, # noqa: E501 + {'model': nn.BatchNorm2d(3), 'input': (3, 16, 16), 'flops': 1536.0, 'params': 6.0}, # noqa: E501 + {'model': nn.BatchNorm3d(3), 'input': (3, 3, 16, 16), 'flops': 4608.0, 'params': 6.0}, # noqa: E501 + {'model': nn.GroupNorm(2, 6), 'input': (6, 16, 16), 'flops': 3072.0, 'params': 12.0}, # noqa: E501 + {'model': nn.InstanceNorm1d(3, affine=True), 'input': (3, 16), 'flops': 96.0, 'params': 6.0}, # noqa: E501 + {'model': nn.InstanceNorm2d(3, affine=True), 'input': (3, 16, 16), 'flops': 1536.0, 'params': 6.0}, # noqa: E501 + {'model': nn.InstanceNorm3d(3, affine=True), 'input': (3, 3, 16, 16), 'flops': 4608.0, 'params': 6.0}, # noqa: E501 + {'model': nn.LayerNorm((3, 16, 16)), 'input': (3, 16, 16), 'flops': 1536.0, 'params': 1536.0}, # noqa: E501 + {'model': nn.LayerNorm((3, 16, 16), elementwise_affine=False), 'input': (3, 16, 16), 'flops': 768.0, 'params': 0}, # noqa: E501 + {'model': nn.Linear(1024, 2), 'input': (1024, ), 'flops': 2048.0, 'params': 2050.0}, # noqa: E501 + {'model': nn.ConvTranspose2d(3, 8, 3), 'input': (3, 16, 16), 'flops': 57888, 'params': 224.0}, # noqa: E501 + {'model': nn.Upsample((32, 32)), 'input': (3, 16, 16), 'flops': 3072.0, 'params': 0} # noqa: E501 +] +# yapf: enable + + +class ExampleModel(nn.Module): + + def __init__(self): + super().__init__() + self.conv2d = nn.Conv2d(3, 8, 3) + + def forward(self, imgs): + x = torch.randn((1, *imgs)) + return self.conv2d(x) + + +def input_constructor(x): + return dict(imgs=x) + + +def test_flops_counter(): + with pytest.raises(AssertionError): + # input_res should be a tuple + model = nn.Conv2d(3, 8, 3) + input_res = [1, 3, 16, 16] + get_model_complexity_info(model, input_res) + + with pytest.raises(AssertionError): + # len(input_res) >= 2 + model = nn.Conv2d(3, 8, 3) + input_res = tuple() + get_model_complexity_info(model, input_res) + + # test common layers + for item in gt_results: + model = item['model'] + input = item['input'] + flops, params = get_model_complexity_info( + model, input, as_strings=False, print_per_layer_stat=False) + assert flops == item['flops'] and params == item['params'] + + # test input constructor + model = ExampleModel() + x = (3, 16, 16) + flops, params = get_model_complexity_info( + model, + x, + as_strings=False, + print_per_layer_stat=False, + input_constructor=input_constructor) + assert flops == 43904.0 and params == 224.0 + + # test output string + model = nn.Conv3d(3, 8, 3) + x = (3, 3, 512, 512) + flops, params = get_model_complexity_info( + model, x, print_per_layer_stat=False) + assert flops == '0.17 GFLOPs' and params == str(656) + + # test print per layer status + model = nn.Conv1d(3, 8, 3) + x = (3, 16) + out = StringIO() + get_model_complexity_info(model, x, ost=out) + assert out.getvalue() == \ + 'Conv1d(0.0 M, 100.000% Params, 0.0 GFLOPs, 100.000% FLOPs, 3, 8, kernel_size=(3,), stride=(1,))\n' # noqa: E501 + + # test when model is not a common instance + model = nn.Sequential(nn.Conv2d(3, 8, 3), nn.Flatten(), nn.Linear(1568, 2)) + x = (3, 16, 16) + flops, params = get_model_complexity_info( + model, x, as_strings=False, print_per_layer_stat=True) + assert flops == 47040.0 and params == 3362 + + +def test_flops_to_string(): + flops = 6.54321 * 10.**9 + assert flops_to_string(flops) == '6.54 GFLOPs' + assert flops_to_string(flops, 'MFLOPs') == '6543.21 MFLOPs' + assert flops_to_string(flops, 'KFLOPs') == '6543210.0 KFLOPs' + assert flops_to_string(flops, 'FLOPs') == '6543210000.0 FLOPs' + assert flops_to_string(flops, precision=4) == '6.5432 GFLOPs' + + flops = 6.54321 * 10.**9 + assert flops_to_string(flops, None) == '6.54 GFLOPs' + flops = 3.21 * 10.**7 + assert flops_to_string(flops, None) == '32.1 MFLOPs' + flops = 5.4 * 10.**3 + assert flops_to_string(flops, None) == '5.4 KFLOPs' + flops = 987 + assert flops_to_string(flops, None) == '987 FLOPs' + + +def test_params_to_string(): + num_params = 3.21 * 10.**7 + assert params_to_string(num_params) == '32.1 M' + num_params = 4.56 * 10.**5 + assert params_to_string(num_params) == '456.0 k' + num_params = 7.89 * 10.**2 + assert params_to_string(num_params) == '789.0' + + num_params = 6.54321 * 10.**7 + assert params_to_string(num_params, 'M') == '65.43 M' + assert params_to_string(num_params, 'K') == '65432.1 K' + assert params_to_string(num_params, '') == '65432100.0' + assert params_to_string(num_params, precision=4) == '65.4321 M' diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_fuse_conv_bn.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_fuse_conv_bn.py new file mode 100644 index 000000000..e60be5386 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_fuse_conv_bn.py @@ -0,0 +1,16 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn + +from mmcv.cnn import ConvModule, fuse_conv_bn + + +def test_fuse_conv_bn(): + inputs = torch.rand((1, 3, 5, 5)) + modules = nn.ModuleList() + modules.append(nn.BatchNorm2d(3)) + modules.append(ConvModule(3, 5, 3, norm_cfg=dict(type='BN'))) + modules.append(ConvModule(5, 5, 3, norm_cfg=dict(type='BN'))) + modules = nn.Sequential(*modules) + fused_modules = fuse_conv_bn(modules) + assert torch.equal(modules(inputs), fused_modules(inputs)) diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_generalized_attention.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_generalized_attention.py new file mode 100644 index 000000000..6b844f0ad --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_generalized_attention.py @@ -0,0 +1,76 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +from mmcv.cnn.bricks import GeneralizedAttention + + +def test_context_block(): + + # test attention_type='1000' + imgs = torch.randn(2, 16, 20, 20) + gen_attention_block = GeneralizedAttention(16, attention_type='1000') + assert gen_attention_block.query_conv.in_channels == 16 + assert gen_attention_block.key_conv.in_channels == 16 + assert gen_attention_block.key_conv.in_channels == 16 + out = gen_attention_block(imgs) + assert out.shape == imgs.shape + + # test attention_type='0100' + imgs = torch.randn(2, 16, 20, 20) + gen_attention_block = GeneralizedAttention(16, attention_type='0100') + assert gen_attention_block.query_conv.in_channels == 16 + assert gen_attention_block.appr_geom_fc_x.in_features == 8 + assert gen_attention_block.appr_geom_fc_y.in_features == 8 + out = gen_attention_block(imgs) + assert out.shape == imgs.shape + + # test attention_type='0010' + imgs = torch.randn(2, 16, 20, 20) + gen_attention_block = GeneralizedAttention(16, attention_type='0010') + assert gen_attention_block.key_conv.in_channels == 16 + assert hasattr(gen_attention_block, 'appr_bias') + out = gen_attention_block(imgs) + assert out.shape == imgs.shape + + # test attention_type='0001' + imgs = torch.randn(2, 16, 20, 20) + gen_attention_block = GeneralizedAttention(16, attention_type='0001') + assert gen_attention_block.appr_geom_fc_x.in_features == 8 + assert gen_attention_block.appr_geom_fc_y.in_features == 8 + assert hasattr(gen_attention_block, 'geom_bias') + out = gen_attention_block(imgs) + assert out.shape == imgs.shape + + # test spatial_range >= 0 + imgs = torch.randn(2, 256, 20, 20) + gen_attention_block = GeneralizedAttention(256, spatial_range=10) + assert hasattr(gen_attention_block, 'local_constraint_map') + out = gen_attention_block(imgs) + assert out.shape == imgs.shape + + # test q_stride > 1 + imgs = torch.randn(2, 16, 20, 20) + gen_attention_block = GeneralizedAttention(16, q_stride=2) + assert gen_attention_block.q_downsample is not None + out = gen_attention_block(imgs) + assert out.shape == imgs.shape + + # test kv_stride > 1 + imgs = torch.randn(2, 16, 20, 20) + gen_attention_block = GeneralizedAttention(16, kv_stride=2) + assert gen_attention_block.kv_downsample is not None + out = gen_attention_block(imgs) + assert out.shape == imgs.shape + + # test fp16 with attention_type='1111' + if torch.cuda.is_available(): + imgs = torch.randn(2, 16, 20, 20).cuda().to(torch.half) + gen_attention_block = GeneralizedAttention( + 16, + spatial_range=-1, + num_heads=8, + attention_type='1111', + kv_stride=2) + gen_attention_block.cuda().type(torch.half) + out = gen_attention_block(imgs) + assert out.shape == imgs.shape diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_hsigmoid.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_hsigmoid.py new file mode 100644 index 000000000..43e9f624a --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_hsigmoid.py @@ -0,0 +1,37 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.cnn.bricks import HSigmoid + + +def test_hsigmoid(): + # test assertion divisor can not be zero + with pytest.raises(AssertionError): + HSigmoid(divisor=0) + + # test with default parameters + act = HSigmoid() + input_shape = torch.Size([1, 3, 64, 64]) + input = torch.randn(input_shape) + output = act(input) + expected_output = torch.min( + torch.max((input + 3) / 6, torch.zeros(input_shape)), + torch.ones(input_shape)) + # test output shape + assert output.shape == expected_output.shape + # test output value + assert torch.equal(output, expected_output) + + # test with designated parameters + act = HSigmoid(1, 2, 0, 1) + input_shape = torch.Size([1, 3, 64, 64]) + input = torch.randn(input_shape) + output = act(input) + expected_output = torch.min( + torch.max((input + 1) / 2, torch.zeros(input_shape)), + torch.ones(input_shape)) + # test output shape + assert output.shape == expected_output.shape + # test output value + assert torch.equal(output, expected_output) diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_hswish.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_hswish.py new file mode 100644 index 000000000..5cd1bcf31 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_hswish.py @@ -0,0 +1,21 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +from torch.nn.functional import relu6 + +from mmcv.cnn.bricks import HSwish + + +def test_hswish(): + # test inplace + act = HSwish(inplace=True) + assert act.act.inplace + act = HSwish() + assert not act.act.inplace + + input = torch.randn(1, 3, 64, 64) + expected_output = input * relu6(input + 3) / 6 + output = act(input) + # test output shape + assert output.shape == expected_output.shape + # test output value + assert torch.equal(output, expected_output) diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_non_local.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_non_local.py new file mode 100644 index 000000000..25d788339 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_non_local.py @@ -0,0 +1,220 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch +import torch.nn as nn + +from mmcv.cnn import NonLocal1d, NonLocal2d, NonLocal3d +from mmcv.cnn.bricks.non_local import _NonLocalNd + + +def test_nonlocal(): + with pytest.raises(ValueError): + # mode should be in ['embedded_gaussian', 'dot_product'] + _NonLocalNd(3, mode='unsupport_mode') + + # _NonLocalNd with zero initialization + _NonLocalNd(3) + _NonLocalNd(3, norm_cfg=dict(type='BN')) + + # _NonLocalNd without zero initialization + _NonLocalNd(3, zeros_init=False) + _NonLocalNd(3, norm_cfg=dict(type='BN'), zeros_init=False) + + +def test_nonlocal3d(): + # NonLocal3d with 'embedded_gaussian' mode + imgs = torch.randn(2, 3, 10, 20, 20) + nonlocal_3d = NonLocal3d(3) + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + # NonLocal is only implemented on gpu in parrots + imgs = imgs.cuda() + nonlocal_3d.cuda() + out = nonlocal_3d(imgs) + assert out.shape == imgs.shape + + # NonLocal3d with 'dot_product' mode + nonlocal_3d = NonLocal3d(3, mode='dot_product') + assert nonlocal_3d.mode == 'dot_product' + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + nonlocal_3d.cuda() + out = nonlocal_3d(imgs) + assert out.shape == imgs.shape + + # NonLocal3d with 'concatenation' mode + nonlocal_3d = NonLocal3d(3, mode='concatenation') + assert nonlocal_3d.mode == 'concatenation' + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + nonlocal_3d.cuda() + out = nonlocal_3d(imgs) + assert out.shape == imgs.shape + + # NonLocal3d with 'gaussian' mode + nonlocal_3d = NonLocal3d(3, mode='gaussian') + assert not hasattr(nonlocal_3d, 'phi') + assert nonlocal_3d.mode == 'gaussian' + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + nonlocal_3d.cuda() + out = nonlocal_3d(imgs) + assert out.shape == imgs.shape + + # NonLocal3d with 'gaussian' mode and sub_sample + nonlocal_3d = NonLocal3d(3, mode='gaussian', sub_sample=True) + assert isinstance(nonlocal_3d.g, nn.Sequential) and len(nonlocal_3d.g) == 2 + assert isinstance(nonlocal_3d.g[1], nn.MaxPool3d) + assert nonlocal_3d.g[1].kernel_size == (1, 2, 2) + assert isinstance(nonlocal_3d.phi, nn.MaxPool3d) + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + nonlocal_3d.cuda() + out = nonlocal_3d(imgs) + assert out.shape == imgs.shape + + # NonLocal3d with 'dot_product' mode and sub_sample + nonlocal_3d = NonLocal3d(3, mode='dot_product', sub_sample=True) + for m in [nonlocal_3d.g, nonlocal_3d.phi]: + assert isinstance(m, nn.Sequential) and len(m) == 2 + assert isinstance(m[1], nn.MaxPool3d) + assert m[1].kernel_size == (1, 2, 2) + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + nonlocal_3d.cuda() + out = nonlocal_3d(imgs) + assert out.shape == imgs.shape + + +def test_nonlocal2d(): + # NonLocal2d with 'embedded_gaussian' mode + imgs = torch.randn(2, 3, 20, 20) + nonlocal_2d = NonLocal2d(3) + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + imgs = imgs.cuda() + nonlocal_2d.cuda() + out = nonlocal_2d(imgs) + assert out.shape == imgs.shape + + # NonLocal2d with 'dot_product' mode + imgs = torch.randn(2, 3, 20, 20) + nonlocal_2d = NonLocal2d(3, mode='dot_product') + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + imgs = imgs.cuda() + nonlocal_2d.cuda() + out = nonlocal_2d(imgs) + assert out.shape == imgs.shape + + # NonLocal2d with 'concatenation' mode + imgs = torch.randn(2, 3, 20, 20) + nonlocal_2d = NonLocal2d(3, mode='concatenation') + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + imgs = imgs.cuda() + nonlocal_2d.cuda() + out = nonlocal_2d(imgs) + assert out.shape == imgs.shape + + # NonLocal2d with 'gaussian' mode + imgs = torch.randn(2, 3, 20, 20) + nonlocal_2d = NonLocal2d(3, mode='gaussian') + assert not hasattr(nonlocal_2d, 'phi') + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + imgs = imgs.cuda() + nonlocal_2d.cuda() + out = nonlocal_2d(imgs) + assert out.shape == imgs.shape + + # NonLocal2d with 'gaussian' mode and sub_sample + nonlocal_2d = NonLocal2d(3, mode='gaussian', sub_sample=True) + assert isinstance(nonlocal_2d.g, nn.Sequential) and len(nonlocal_2d.g) == 2 + assert isinstance(nonlocal_2d.g[1], nn.MaxPool2d) + assert nonlocal_2d.g[1].kernel_size == (2, 2) + assert isinstance(nonlocal_2d.phi, nn.MaxPool2d) + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + nonlocal_2d.cuda() + out = nonlocal_2d(imgs) + assert out.shape == imgs.shape + + # NonLocal2d with 'dot_product' mode and sub_sample + nonlocal_2d = NonLocal2d(3, mode='dot_product', sub_sample=True) + for m in [nonlocal_2d.g, nonlocal_2d.phi]: + assert isinstance(m, nn.Sequential) and len(m) == 2 + assert isinstance(m[1], nn.MaxPool2d) + assert m[1].kernel_size == (2, 2) + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + nonlocal_2d.cuda() + out = nonlocal_2d(imgs) + assert out.shape == imgs.shape + + +def test_nonlocal1d(): + # NonLocal1d with 'embedded_gaussian' mode + imgs = torch.randn(2, 3, 20) + nonlocal_1d = NonLocal1d(3) + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + imgs = imgs.cuda() + nonlocal_1d.cuda() + out = nonlocal_1d(imgs) + assert out.shape == imgs.shape + + # NonLocal1d with 'dot_product' mode + imgs = torch.randn(2, 3, 20) + nonlocal_1d = NonLocal1d(3, mode='dot_product') + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + imgs = imgs.cuda() + nonlocal_1d.cuda() + out = nonlocal_1d(imgs) + assert out.shape == imgs.shape + + # NonLocal1d with 'concatenation' mode + imgs = torch.randn(2, 3, 20) + nonlocal_1d = NonLocal1d(3, mode='concatenation') + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + imgs = imgs.cuda() + nonlocal_1d.cuda() + out = nonlocal_1d(imgs) + assert out.shape == imgs.shape + + # NonLocal1d with 'gaussian' mode + imgs = torch.randn(2, 3, 20) + nonlocal_1d = NonLocal1d(3, mode='gaussian') + assert not hasattr(nonlocal_1d, 'phi') + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + imgs = imgs.cuda() + nonlocal_1d.cuda() + out = nonlocal_1d(imgs) + assert out.shape == imgs.shape + + # NonLocal1d with 'gaussian' mode and sub_sample + nonlocal_1d = NonLocal1d(3, mode='gaussian', sub_sample=True) + assert isinstance(nonlocal_1d.g, nn.Sequential) and len(nonlocal_1d.g) == 2 + assert isinstance(nonlocal_1d.g[1], nn.MaxPool1d) + assert nonlocal_1d.g[1].kernel_size == 2 + assert isinstance(nonlocal_1d.phi, nn.MaxPool1d) + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + nonlocal_1d.cuda() + out = nonlocal_1d(imgs) + assert out.shape == imgs.shape + + # NonLocal1d with 'dot_product' mode and sub_sample + nonlocal_1d = NonLocal1d(3, mode='dot_product', sub_sample=True) + for m in [nonlocal_1d.g, nonlocal_1d.phi]: + assert isinstance(m, nn.Sequential) and len(m) == 2 + assert isinstance(m[1], nn.MaxPool1d) + assert m[1].kernel_size == 2 + if torch.__version__ == 'parrots': + if torch.cuda.is_available(): + nonlocal_1d.cuda() + out = nonlocal_1d(imgs) + assert out.shape == imgs.shape diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_scale.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_scale.py new file mode 100644 index 000000000..04d75ec16 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_scale.py @@ -0,0 +1,78 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.cnn.bricks import LayerScale, Scale + + +def test_scale(): + # test default scale + scale = Scale() + assert scale.scale.data == 1. + assert scale.scale.dtype == torch.float + x = torch.rand(1, 3, 64, 64) + output = scale(x) + assert output.shape == (1, 3, 64, 64) + + # test given scale + scale = Scale(10.) + assert scale.scale.data == 10. + assert scale.scale.dtype == torch.float + x = torch.rand(1, 3, 64, 64) + output = scale(x) + assert output.shape == (1, 3, 64, 64) + + +def test_layer_scale(): + with pytest.raises(AssertionError): + cfg = dict( + dim=10, + data_format='BNC', + ) + LayerScale(**cfg) + + # test init + cfg = dict(dim=10) + ls = LayerScale(**cfg) + assert torch.equal(ls.weight, torch.ones(10, requires_grad=True) * 1e-5) + + # test forward + # test channels_last + cfg = dict(dim=256, inplace=False, data_format='channels_last') + ls_channels_last = LayerScale(**cfg) + x = torch.randn((4, 49, 256)) + out = ls_channels_last(x) + assert tuple(out.size()) == (4, 49, 256) + assert torch.equal(x * 1e-5, out) + + # test channels_last 2d + cfg = dict(dim=256, inplace=False, data_format='channels_last') + ls_channels_last = LayerScale(**cfg) + x = torch.randn((4, 7, 49, 256)) + out = ls_channels_last(x) + assert tuple(out.size()) == (4, 7, 49, 256) + assert torch.equal(x * 1e-5, out) + + # test channels_first + cfg = dict(dim=256, inplace=False, data_format='channels_first') + ls_channels_first = LayerScale(**cfg) + x = torch.randn((4, 256, 7, 7)) + out = ls_channels_first(x) + assert tuple(out.size()) == (4, 256, 7, 7) + assert torch.equal(x * 1e-5, out) + + # test channels_first 3D + cfg = dict(dim=256, inplace=False, data_format='channels_first') + ls_channels_first = LayerScale(**cfg) + x = torch.randn((4, 256, 7, 7, 7)) + out = ls_channels_first(x) + assert tuple(out.size()) == (4, 256, 7, 7, 7) + assert torch.equal(x * 1e-5, out) + + # test inplace True + cfg = dict(dim=256, inplace=True, data_format='channels_first') + ls_channels_first = LayerScale(**cfg) + x = torch.randn((4, 256, 7, 7)) + out = ls_channels_first(x) + assert tuple(out.size()) == (4, 256, 7, 7) + assert x is out diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_silu.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_silu.py new file mode 100644 index 000000000..e3bbc0f9b --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_silu.py @@ -0,0 +1,28 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +from mmcv.cnn.bricks import build_activation_layer + + +def test_silu(): + act = build_activation_layer(dict(type='SiLU')) + input = torch.randn(1, 3, 64, 64) + expected_output = input * torch.sigmoid(input) + output = act(input) + # test output shape + assert output.shape == expected_output.shape + # test output value + assert torch.allclose(output, expected_output) + + # test inplace + act = build_activation_layer(dict(type='SiLU', inplace=True)) + assert act.inplace + input = torch.randn(1, 3, 64, 64) + expected_output = input * torch.sigmoid(input) + output = act(input) + # test output shape + assert output.shape == expected_output.shape + # test output value + assert torch.allclose(output, expected_output) + assert torch.allclose(input, expected_output) + assert input is output diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_swish.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_swish.py new file mode 100644 index 000000000..2317f5a13 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_swish.py @@ -0,0 +1,16 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn.functional as F + +from mmcv.cnn.bricks import Swish + + +def test_swish(): + act = Swish() + input = torch.randn(1, 3, 64, 64) + expected_output = input * F.sigmoid(input) + output = act(input) + # test output shape + assert output.shape == expected_output.shape + # test output value + assert torch.equal(output, expected_output) diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_transformer.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_transformer.py new file mode 100644 index 000000000..b5a9562ee --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_transformer.py @@ -0,0 +1,687 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy + +import pytest +import torch +from mmengine.model import ModuleList + +from mmcv.cnn.bricks.drop import DropPath +from mmcv.cnn.bricks.transformer import (FFN, AdaptivePadding, + BaseTransformerLayer, + MultiheadAttention, PatchEmbed, + PatchMerging, + TransformerLayerSequence) + + +def test_adaptive_padding(): + + for padding in ('same', 'corner'): + kernel_size = 16 + stride = 16 + dilation = 1 + input = torch.rand(1, 1, 15, 17) + adap_pad = AdaptivePadding( + kernel_size=kernel_size, + stride=stride, + dilation=dilation, + padding=padding) + out = adap_pad(input) + # padding to divisible by 16 + assert (out.shape[2], out.shape[3]) == (16, 32) + input = torch.rand(1, 1, 16, 17) + out = adap_pad(input) + # padding to divisible by 16 + assert (out.shape[2], out.shape[3]) == (16, 32) + + kernel_size = (2, 2) + stride = (2, 2) + dilation = (1, 1) + + adap_pad = AdaptivePadding( + kernel_size=kernel_size, + stride=stride, + dilation=dilation, + padding=padding) + input = torch.rand(1, 1, 11, 13) + out = adap_pad(input) + # padding to divisible by 2 + assert (out.shape[2], out.shape[3]) == (12, 14) + + kernel_size = (2, 2) + stride = (10, 10) + dilation = (1, 1) + + adap_pad = AdaptivePadding( + kernel_size=kernel_size, + stride=stride, + dilation=dilation, + padding=padding) + input = torch.rand(1, 1, 10, 13) + out = adap_pad(input) + # no padding + assert (out.shape[2], out.shape[3]) == (10, 13) + + kernel_size = (11, 11) + adap_pad = AdaptivePadding( + kernel_size=kernel_size, + stride=stride, + dilation=dilation, + padding=padding) + input = torch.rand(1, 1, 11, 13) + out = adap_pad(input) + # all padding + assert (out.shape[2], out.shape[3]) == (21, 21) + + # test padding as kernel is (7,9) + input = torch.rand(1, 1, 11, 13) + stride = (3, 4) + kernel_size = (4, 5) + dilation = (2, 2) + # actually (7, 9) + adap_pad = AdaptivePadding( + kernel_size=kernel_size, + stride=stride, + dilation=dilation, + padding=padding) + dilation_out = adap_pad(input) + assert (dilation_out.shape[2], dilation_out.shape[3]) == (16, 21) + kernel_size = (7, 9) + dilation = (1, 1) + adap_pad = AdaptivePadding( + kernel_size=kernel_size, + stride=stride, + dilation=dilation, + padding=padding) + kernel79_out = adap_pad(input) + assert (kernel79_out.shape[2], kernel79_out.shape[3]) == (16, 21) + assert kernel79_out.shape == dilation_out.shape + + # assert only support "same" "corner" + with pytest.raises(AssertionError): + AdaptivePadding( + kernel_size=kernel_size, + stride=stride, + dilation=dilation, + padding=1) + + +def test_patch_embed(): + B = 2 + H = 3 + W = 4 + C = 3 + embed_dims = 10 + kernel_size = 3 + stride = 1 + dummy_input = torch.rand(B, C, H, W) + patch_merge_1 = PatchEmbed( + in_channels=C, + embed_dims=embed_dims, + kernel_size=kernel_size, + stride=stride, + padding=0, + dilation=1, + norm_cfg=None) + + x1, shape = patch_merge_1(dummy_input) + # test out shape + assert x1.shape == (2, 2, 10) + # test outsize is correct + assert shape == (1, 2) + # test L = out_h * out_w + assert shape[0] * shape[1] == x1.shape[1] + + B = 2 + H = 10 + W = 10 + C = 3 + embed_dims = 10 + kernel_size = 5 + stride = 2 + dummy_input = torch.rand(B, C, H, W) + # test dilation + patch_merge_2 = PatchEmbed( + in_channels=C, + embed_dims=embed_dims, + kernel_size=kernel_size, + stride=stride, + padding=0, + dilation=2, + norm_cfg=None, + ) + + x2, shape = patch_merge_2(dummy_input) + # test out shape + assert x2.shape == (2, 1, 10) + # test outsize is correct + assert shape == (1, 1) + # test L = out_h * out_w + assert shape[0] * shape[1] == x2.shape[1] + + stride = 2 + input_size = (10, 10) + + dummy_input = torch.rand(B, C, H, W) + # test stride and norm + patch_merge_3 = PatchEmbed( + in_channels=C, + embed_dims=embed_dims, + kernel_size=kernel_size, + stride=stride, + padding=0, + dilation=2, + norm_cfg=dict(type='LN'), + input_size=input_size) + + x3, shape = patch_merge_3(dummy_input) + # test out shape + assert x3.shape == (2, 1, 10) + # test outsize is correct + assert shape == (1, 1) + # test L = out_h * out_w + assert shape[0] * shape[1] == x3.shape[1] + + # test the init_out_size with nn.Unfold + assert patch_merge_3.init_out_size[1] == (input_size[0] - 2 * 4 - + 1) // 2 + 1 + assert patch_merge_3.init_out_size[0] == (input_size[0] - 2 * 4 - + 1) // 2 + 1 + H = 11 + W = 12 + input_size = (H, W) + dummy_input = torch.rand(B, C, H, W) + # test stride and norm + patch_merge_3 = PatchEmbed( + in_channels=C, + embed_dims=embed_dims, + kernel_size=kernel_size, + stride=stride, + padding=0, + dilation=2, + norm_cfg=dict(type='LN'), + input_size=input_size) + + _, shape = patch_merge_3(dummy_input) + # when input_size equal to real input + # the out_size should be equal to `init_out_size` + assert shape == patch_merge_3.init_out_size + + input_size = (H, W) + dummy_input = torch.rand(B, C, H, W) + # test stride and norm + patch_merge_3 = PatchEmbed( + in_channels=C, + embed_dims=embed_dims, + kernel_size=kernel_size, + stride=stride, + padding=0, + dilation=2, + norm_cfg=dict(type='LN'), + input_size=input_size) + + _, shape = patch_merge_3(dummy_input) + # when input_size equal to real input + # the out_size should be equal to `init_out_size` + assert shape == patch_merge_3.init_out_size + + # test adap padding + for padding in ('same', 'corner'): + in_c = 2 + embed_dims = 3 + B = 2 + + # test stride is 1 + input_size = (5, 5) + kernel_size = (5, 5) + stride = (1, 1) + dilation = 1 + bias = False + + x = torch.rand(B, in_c, *input_size) + patch_embed = PatchEmbed( + in_channels=in_c, + embed_dims=embed_dims, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + bias=bias) + + x_out, out_size = patch_embed(x) + assert x_out.size() == (B, 25, 3) + assert out_size == (5, 5) + assert x_out.size(1) == out_size[0] * out_size[1] + + # test kernel_size == stride + input_size = (5, 5) + kernel_size = (5, 5) + stride = (5, 5) + dilation = 1 + bias = False + + x = torch.rand(B, in_c, *input_size) + patch_embed = PatchEmbed( + in_channels=in_c, + embed_dims=embed_dims, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + bias=bias) + + x_out, out_size = patch_embed(x) + assert x_out.size() == (B, 1, 3) + assert out_size == (1, 1) + assert x_out.size(1) == out_size[0] * out_size[1] + + # test kernel_size == stride + input_size = (6, 5) + kernel_size = (5, 5) + stride = (5, 5) + dilation = 1 + bias = False + + x = torch.rand(B, in_c, *input_size) + patch_embed = PatchEmbed( + in_channels=in_c, + embed_dims=embed_dims, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + bias=bias) + + x_out, out_size = patch_embed(x) + assert x_out.size() == (B, 2, 3) + assert out_size == (2, 1) + assert x_out.size(1) == out_size[0] * out_size[1] + + # test different kernel_size with different stride + input_size = (6, 5) + kernel_size = (6, 2) + stride = (6, 2) + dilation = 1 + bias = False + + x = torch.rand(B, in_c, *input_size) + patch_embed = PatchEmbed( + in_channels=in_c, + embed_dims=embed_dims, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + bias=bias) + + x_out, out_size = patch_embed(x) + assert x_out.size() == (B, 3, 3) + assert out_size == (1, 3) + assert x_out.size(1) == out_size[0] * out_size[1] + + +def test_patch_merging(): + + # Test the model with int padding + in_c = 3 + out_c = 4 + kernel_size = 3 + stride = 3 + padding = 1 + dilation = 1 + bias = False + # test the case `pad_to_stride` is False + patch_merge = PatchMerging( + in_channels=in_c, + out_channels=out_c, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + bias=bias) + B, L, C = 1, 100, 3 + input_size = (10, 10) + x = torch.rand(B, L, C) + x_out, out_size = patch_merge(x, input_size) + assert x_out.size() == (1, 16, 4) + assert out_size == (4, 4) + # assert out size is consistent with real output + assert x_out.size(1) == out_size[0] * out_size[1] + in_c = 4 + out_c = 5 + kernel_size = 6 + stride = 3 + padding = 2 + dilation = 2 + bias = False + patch_merge = PatchMerging( + in_channels=in_c, + out_channels=out_c, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + bias=bias) + B, L, C = 1, 100, 4 + input_size = (10, 10) + x = torch.rand(B, L, C) + x_out, out_size = patch_merge(x, input_size) + assert x_out.size() == (1, 4, 5) + assert out_size == (2, 2) + # assert out size is consistent with real output + assert x_out.size(1) == out_size[0] * out_size[1] + + # Test with adaptive padding + for padding in ('same', 'corner'): + in_c = 2 + out_c = 3 + B = 2 + + # test stride is 1 + input_size = (5, 5) + kernel_size = (5, 5) + stride = (1, 1) + dilation = 1 + bias = False + L = input_size[0] * input_size[1] + + x = torch.rand(B, L, in_c) + patch_merge = PatchMerging( + in_channels=in_c, + out_channels=out_c, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + bias=bias) + + x_out, out_size = patch_merge(x, input_size) + assert x_out.size() == (B, 25, 3) + assert out_size == (5, 5) + assert x_out.size(1) == out_size[0] * out_size[1] + + # test kernel_size == stride + input_size = (5, 5) + kernel_size = (5, 5) + stride = (5, 5) + dilation = 1 + bias = False + L = input_size[0] * input_size[1] + + x = torch.rand(B, L, in_c) + patch_merge = PatchMerging( + in_channels=in_c, + out_channels=out_c, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + bias=bias) + + x_out, out_size = patch_merge(x, input_size) + assert x_out.size() == (B, 1, 3) + assert out_size == (1, 1) + assert x_out.size(1) == out_size[0] * out_size[1] + + # test kernel_size == stride + input_size = (6, 5) + kernel_size = (5, 5) + stride = (5, 5) + dilation = 1 + bias = False + L = input_size[0] * input_size[1] + + x = torch.rand(B, L, in_c) + patch_merge = PatchMerging( + in_channels=in_c, + out_channels=out_c, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + bias=bias) + + x_out, out_size = patch_merge(x, input_size) + assert x_out.size() == (B, 2, 3) + assert out_size == (2, 1) + assert x_out.size(1) == out_size[0] * out_size[1] + + # test different kernel_size with different stride + input_size = (6, 5) + kernel_size = (6, 2) + stride = (6, 2) + dilation = 1 + bias = False + L = input_size[0] * input_size[1] + + x = torch.rand(B, L, in_c) + patch_merge = PatchMerging( + in_channels=in_c, + out_channels=out_c, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + bias=bias) + + x_out, out_size = patch_merge(x, input_size) + assert x_out.size() == (B, 3, 3) + assert out_size == (1, 3) + assert x_out.size(1) == out_size[0] * out_size[1] + + +def test_multiheadattention(): + MultiheadAttention( + embed_dims=5, + num_heads=5, + attn_drop=0, + proj_drop=0, + dropout_layer=dict(type='Dropout', drop_prob=0.), + batch_first=True) + batch_dim = 2 + embed_dim = 5 + num_query = 100 + attn_batch_first = MultiheadAttention( + embed_dims=5, + num_heads=5, + attn_drop=0, + proj_drop=0, + dropout_layer=dict(type='DropPath', drop_prob=0.), + batch_first=True) + + attn_query_first = MultiheadAttention( + embed_dims=5, + num_heads=5, + attn_drop=0, + proj_drop=0, + dropout_layer=dict(type='DropPath', drop_prob=0.), + batch_first=False) + + param_dict = dict(attn_query_first.named_parameters()) + for n, v in attn_batch_first.named_parameters(): + param_dict[n].data = v.data + + input_batch_first = torch.rand(batch_dim, num_query, embed_dim) + input_query_first = input_batch_first.transpose(0, 1) + + assert torch.allclose( + attn_query_first(input_query_first).sum(), + attn_batch_first(input_batch_first).sum()) + + key_batch_first = torch.rand(batch_dim, num_query, embed_dim) + key_query_first = key_batch_first.transpose(0, 1) + + assert torch.allclose( + attn_query_first(input_query_first, key_query_first).sum(), + attn_batch_first(input_batch_first, key_batch_first).sum()) + + identity = torch.ones_like(input_query_first) + + # check deprecated arguments can be used normally + + assert torch.allclose( + attn_query_first( + input_query_first, key_query_first, residual=identity).sum(), + attn_batch_first(input_batch_first, key_batch_first).sum() + + identity.sum() - input_batch_first.sum()) + + assert torch.allclose( + attn_query_first( + input_query_first, key_query_first, identity=identity).sum(), + attn_batch_first(input_batch_first, key_batch_first).sum() + + identity.sum() - input_batch_first.sum()) + + attn_query_first( + input_query_first, key_query_first, identity=identity).sum(), + + +def test_ffn(): + with pytest.raises(AssertionError): + # num_fcs should be no less than 2 + FFN(num_fcs=1) + ffn = FFN(dropout=0, add_identity=True) + + input_tensor = torch.rand(2, 20, 256) + input_tensor_nbc = input_tensor.transpose(0, 1) + assert torch.allclose(ffn(input_tensor).sum(), ffn(input_tensor_nbc).sum()) + residual = torch.rand_like(input_tensor) + torch.allclose( + ffn(input_tensor, residual=residual).sum(), + ffn(input_tensor).sum() + residual.sum() - input_tensor.sum()) + + torch.allclose( + ffn(input_tensor, identity=residual).sum(), + ffn(input_tensor).sum() + residual.sum() - input_tensor.sum()) + + # test with layer_scale + ffn = FFN(dropout=0, add_identity=True, layer_scale_init_value=0.1) + + input_tensor = torch.rand(2, 20, 256) + input_tensor_nbc = input_tensor.transpose(0, 1) + assert torch.allclose(ffn(input_tensor).sum(), ffn(input_tensor_nbc).sum()) + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='Cuda not available') +def test_basetransformerlayer_cuda(): + # To test if the BaseTransformerLayer's behaviour remains + # consistent after being deepcopied + operation_order = ('self_attn', 'ffn') + baselayer = BaseTransformerLayer( + operation_order=operation_order, + batch_first=True, + attn_cfgs=dict( + type='MultiheadAttention', + embed_dims=256, + num_heads=8, + ), + ) + baselayers = ModuleList([copy.deepcopy(baselayer) for _ in range(2)]) + baselayers.to('cuda') + x = torch.rand(2, 10, 256).cuda() + for m in baselayers: + x = m(x) + assert x.shape == torch.Size([2, 10, 256]) + + +@pytest.mark.parametrize('embed_dims', [False, 256]) +def test_basetransformerlayer(embed_dims): + attn_cfgs = dict(type='MultiheadAttention', embed_dims=256, num_heads=8), + if embed_dims: + ffn_cfgs = dict( + type='FFN', + embed_dims=embed_dims, + feedforward_channels=1024, + num_fcs=2, + ffn_drop=0., + act_cfg=dict(type='ReLU', inplace=True), + ) + else: + ffn_cfgs = dict( + type='FFN', + feedforward_channels=1024, + num_fcs=2, + ffn_drop=0., + act_cfg=dict(type='ReLU', inplace=True), + ) + + feedforward_channels = 2048 + ffn_dropout = 0.1 + operation_order = ('self_attn', 'norm', 'ffn', 'norm') + + # test deprecated_args + baselayer = BaseTransformerLayer( + attn_cfgs=attn_cfgs, + ffn_cfgs=ffn_cfgs, + feedforward_channels=feedforward_channels, + ffn_dropout=ffn_dropout, + operation_order=operation_order) + assert baselayer.batch_first is False + assert baselayer.ffns[0].feedforward_channels == feedforward_channels + + attn_cfgs = dict(type='MultiheadAttention', num_heads=8, embed_dims=256), + feedforward_channels = 2048 + ffn_dropout = 0.1 + operation_order = ('self_attn', 'norm', 'ffn', 'norm') + baselayer = BaseTransformerLayer( + attn_cfgs=attn_cfgs, + feedforward_channels=feedforward_channels, + ffn_dropout=ffn_dropout, + operation_order=operation_order, + batch_first=True) + assert baselayer.attentions[0].batch_first + in_tensor = torch.rand(2, 10, 256) + baselayer(in_tensor) + + +def test_transformerlayersequence(): + squeue = TransformerLayerSequence( + num_layers=6, + transformerlayers=dict( + type='BaseTransformerLayer', + attn_cfgs=[ + dict( + type='MultiheadAttention', + embed_dims=256, + num_heads=8, + dropout=0.1), + dict(type='MultiheadAttention', embed_dims=256, num_heads=4) + ], + feedforward_channels=1024, + ffn_dropout=0.1, + operation_order=('self_attn', 'norm', 'cross_attn', 'norm', 'ffn', + 'norm'))) + assert len(squeue.layers) == 6 + assert squeue.pre_norm is False + with pytest.raises(AssertionError): + # if transformerlayers is a list, len(transformerlayers) + # should be equal to num_layers + TransformerLayerSequence( + num_layers=6, + transformerlayers=[ + dict( + type='BaseTransformerLayer', + attn_cfgs=[ + dict( + type='MultiheadAttention', + embed_dims=256, + num_heads=8, + dropout=0.1), + dict(type='MultiheadAttention', embed_dims=256) + ], + feedforward_channels=1024, + ffn_dropout=0.1, + operation_order=('self_attn', 'norm', 'cross_attn', 'norm', + 'ffn', 'norm')) + ]) + + +def test_drop_path(): + drop_path = DropPath(drop_prob=0) + test_in = torch.rand(2, 3, 4, 5) + assert test_in is drop_path(test_in) + + drop_path = DropPath(drop_prob=0.1) + drop_path.training = False + test_in = torch.rand(2, 3, 4, 5) + assert test_in is drop_path(test_in) + drop_path.training = True + assert test_in is not drop_path(test_in) diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_wrappers.py b/cv/distiller/CWD/mmcv/tests/test_cnn/test_wrappers.py new file mode 100644 index 000000000..02e0f13cd --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_cnn/test_wrappers.py @@ -0,0 +1,376 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest.mock import patch + +import pytest +import torch +import torch.nn as nn + +from mmcv.cnn.bricks import (Conv2d, Conv3d, ConvTranspose2d, ConvTranspose3d, + Linear, MaxPool2d, MaxPool3d) + +if torch.__version__ != 'parrots': + torch_version = '1.1' +else: + torch_version = 'parrots' + + +@patch('torch.__version__', torch_version) +@pytest.mark.parametrize( + 'in_w,in_h,in_channel,out_channel,kernel_size,stride,padding,dilation', + [(10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 3, 3, 5, 2, 1, 2)]) +def test_conv2d(in_w, in_h, in_channel, out_channel, kernel_size, stride, + padding, dilation): + """ + CommandLine: + xdoctest -m tests/test_wrappers.py test_conv2d + """ + # train mode + # wrapper op with 0-dim input + x_empty = torch.randn(0, in_channel, in_h, in_w) + torch.manual_seed(0) + wrapper = Conv2d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation) + wrapper_out = wrapper(x_empty) + + # torch op with 3-dim input as shape reference + x_normal = torch.randn(3, in_channel, in_h, in_w).requires_grad_(True) + torch.manual_seed(0) + ref = nn.Conv2d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation) + ref_out = ref(x_normal) + + assert wrapper_out.shape[0] == 0 + assert wrapper_out.shape[1:] == ref_out.shape[1:] + + wrapper_out.sum().backward() + assert wrapper.weight.grad is not None + assert wrapper.weight.grad.shape == wrapper.weight.shape + + assert torch.equal(wrapper(x_normal), ref_out) + + # eval mode + x_empty = torch.randn(0, in_channel, in_h, in_w) + wrapper = Conv2d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation) + wrapper.eval() + wrapper(x_empty) + + +@patch('torch.__version__', torch_version) +@pytest.mark.parametrize( + 'in_w,in_h,in_t,in_channel,out_channel,kernel_size,stride,padding,dilation', # noqa: E501 + [(10, 10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 20, 3, 3, 5, 2, 1, 2)]) +def test_conv3d(in_w, in_h, in_t, in_channel, out_channel, kernel_size, stride, + padding, dilation): + """ + CommandLine: + xdoctest -m tests/test_wrappers.py test_conv3d + """ + # train mode + # wrapper op with 0-dim input + x_empty = torch.randn(0, in_channel, in_t, in_h, in_w) + torch.manual_seed(0) + wrapper = Conv3d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation) + wrapper_out = wrapper(x_empty) + + # torch op with 3-dim input as shape reference + x_normal = torch.randn(3, in_channel, in_t, in_h, + in_w).requires_grad_(True) + torch.manual_seed(0) + ref = nn.Conv3d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation) + ref_out = ref(x_normal) + + assert wrapper_out.shape[0] == 0 + assert wrapper_out.shape[1:] == ref_out.shape[1:] + + wrapper_out.sum().backward() + assert wrapper.weight.grad is not None + assert wrapper.weight.grad.shape == wrapper.weight.shape + + assert torch.equal(wrapper(x_normal), ref_out) + + # eval mode + x_empty = torch.randn(0, in_channel, in_t, in_h, in_w) + wrapper = Conv3d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation) + wrapper.eval() + wrapper(x_empty) + + +@patch('torch.__version__', torch_version) +@pytest.mark.parametrize( + 'in_w,in_h,in_channel,out_channel,kernel_size,stride,padding,dilation', + [(10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 3, 3, 5, 2, 1, 2)]) +def test_conv_transposed_2d(in_w, in_h, in_channel, out_channel, kernel_size, + stride, padding, dilation): + # wrapper op with 0-dim input + x_empty = torch.randn(0, in_channel, in_h, in_w, requires_grad=True) + # out padding must be smaller than either stride or dilation + op = min(stride, dilation) - 1 + if torch.__version__ == 'parrots': + op = 0 + torch.manual_seed(0) + wrapper = ConvTranspose2d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + output_padding=op) + wrapper_out = wrapper(x_empty) + + # torch op with 3-dim input as shape reference + x_normal = torch.randn(3, in_channel, in_h, in_w) + torch.manual_seed(0) + ref = nn.ConvTranspose2d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + output_padding=op) + ref_out = ref(x_normal) + + assert wrapper_out.shape[0] == 0 + assert wrapper_out.shape[1:] == ref_out.shape[1:] + + wrapper_out.sum().backward() + assert wrapper.weight.grad is not None + assert wrapper.weight.grad.shape == wrapper.weight.shape + + assert torch.equal(wrapper(x_normal), ref_out) + + # eval mode + x_empty = torch.randn(0, in_channel, in_h, in_w) + wrapper = ConvTranspose2d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + output_padding=op) + wrapper.eval() + wrapper(x_empty) + + +@patch('torch.__version__', torch_version) +@pytest.mark.parametrize( + 'in_w,in_h,in_t,in_channel,out_channel,kernel_size,stride,padding,dilation', # noqa: E501 + [(10, 10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 20, 3, 3, 5, 2, 1, 2)]) +def test_conv_transposed_3d(in_w, in_h, in_t, in_channel, out_channel, + kernel_size, stride, padding, dilation): + # wrapper op with 0-dim input + x_empty = torch.randn(0, in_channel, in_t, in_h, in_w, requires_grad=True) + # out padding must be smaller than either stride or dilation + op = min(stride, dilation) - 1 + torch.manual_seed(0) + wrapper = ConvTranspose3d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + output_padding=op) + wrapper_out = wrapper(x_empty) + + # torch op with 3-dim input as shape reference + x_normal = torch.randn(3, in_channel, in_t, in_h, in_w) + torch.manual_seed(0) + ref = nn.ConvTranspose3d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + output_padding=op) + ref_out = ref(x_normal) + + assert wrapper_out.shape[0] == 0 + assert wrapper_out.shape[1:] == ref_out.shape[1:] + + wrapper_out.sum().backward() + assert wrapper.weight.grad is not None + assert wrapper.weight.grad.shape == wrapper.weight.shape + + assert torch.equal(wrapper(x_normal), ref_out) + + # eval mode + x_empty = torch.randn(0, in_channel, in_t, in_h, in_w) + wrapper = ConvTranspose3d( + in_channel, + out_channel, + kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + output_padding=op) + wrapper.eval() + wrapper(x_empty) + + +@patch('torch.__version__', torch_version) +@pytest.mark.parametrize( + 'in_w,in_h,in_channel,out_channel,kernel_size,stride,padding,dilation', + [(10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 3, 3, 5, 2, 1, 2)]) +def test_max_pool_2d(in_w, in_h, in_channel, out_channel, kernel_size, stride, + padding, dilation): + # wrapper op with 0-dim input + x_empty = torch.randn(0, in_channel, in_h, in_w, requires_grad=True) + wrapper = MaxPool2d( + kernel_size, stride=stride, padding=padding, dilation=dilation) + wrapper_out = wrapper(x_empty) + + # torch op with 3-dim input as shape reference + x_normal = torch.randn(3, in_channel, in_h, in_w) + ref = nn.MaxPool2d( + kernel_size, stride=stride, padding=padding, dilation=dilation) + ref_out = ref(x_normal) + + assert wrapper_out.shape[0] == 0 + assert wrapper_out.shape[1:] == ref_out.shape[1:] + + assert torch.equal(wrapper(x_normal), ref_out) + + +@patch('torch.__version__', torch_version) +@pytest.mark.parametrize( + 'in_w,in_h,in_t,in_channel,out_channel,kernel_size,stride,padding,dilation', # noqa: E501 + [(10, 10, 10, 1, 1, 3, 1, 0, 1), (20, 20, 20, 3, 3, 5, 2, 1, 2)]) +@pytest.mark.skipif( + torch.__version__ == 'parrots' and not torch.cuda.is_available(), + reason='parrots requires CUDA support') +def test_max_pool_3d(in_w, in_h, in_t, in_channel, out_channel, kernel_size, + stride, padding, dilation): + # wrapper op with 0-dim input + x_empty = torch.randn(0, in_channel, in_t, in_h, in_w, requires_grad=True) + wrapper = MaxPool3d( + kernel_size, stride=stride, padding=padding, dilation=dilation) + if torch.__version__ == 'parrots': + x_empty = x_empty.cuda() + wrapper_out = wrapper(x_empty) + # torch op with 3-dim input as shape reference + x_normal = torch.randn(3, in_channel, in_t, in_h, in_w) + ref = nn.MaxPool3d( + kernel_size, stride=stride, padding=padding, dilation=dilation) + if torch.__version__ == 'parrots': + x_normal = x_normal.cuda() + ref_out = ref(x_normal) + + assert wrapper_out.shape[0] == 0 + assert wrapper_out.shape[1:] == ref_out.shape[1:] + + assert torch.equal(wrapper(x_normal), ref_out) + + +@patch('torch.__version__', torch_version) +@pytest.mark.parametrize('in_w,in_h,in_feature,out_feature', [(10, 10, 1, 1), + (20, 20, 3, 3)]) +def test_linear(in_w, in_h, in_feature, out_feature): + # wrapper op with 0-dim input + x_empty = torch.randn(0, in_feature, requires_grad=True) + torch.manual_seed(0) + wrapper = Linear(in_feature, out_feature) + wrapper_out = wrapper(x_empty) + + # torch op with 3-dim input as shape reference + x_normal = torch.randn(3, in_feature) + torch.manual_seed(0) + ref = nn.Linear(in_feature, out_feature) + ref_out = ref(x_normal) + + assert wrapper_out.shape[0] == 0 + assert wrapper_out.shape[1:] == ref_out.shape[1:] + + wrapper_out.sum().backward() + assert wrapper.weight.grad is not None + assert wrapper.weight.grad.shape == wrapper.weight.shape + + assert torch.equal(wrapper(x_normal), ref_out) + + # eval mode + x_empty = torch.randn(0, in_feature) + wrapper = Linear(in_feature, out_feature) + wrapper.eval() + wrapper(x_empty) + + +@patch('mmcv.cnn.bricks.wrappers.TORCH_VERSION', (1, 10)) +def test_nn_op_forward_called(): + + for m in ['Conv2d', 'ConvTranspose2d', 'MaxPool2d']: + with patch(f'torch.nn.{m}.forward') as nn_module_forward: + # randn input + x_empty = torch.randn(0, 3, 10, 10) + wrapper = eval(m)(3, 2, 1) + wrapper(x_empty) + nn_module_forward.assert_called_with(x_empty) + + # non-randn input + x_normal = torch.randn(1, 3, 10, 10) + wrapper = eval(m)(3, 2, 1) + wrapper(x_normal) + nn_module_forward.assert_called_with(x_normal) + + for m in ['Conv3d', 'ConvTranspose3d', 'MaxPool3d']: + with patch(f'torch.nn.{m}.forward') as nn_module_forward: + # randn input + x_empty = torch.randn(0, 3, 10, 10, 10) + wrapper = eval(m)(3, 2, 1) + wrapper(x_empty) + nn_module_forward.assert_called_with(x_empty) + + # non-randn input + x_normal = torch.randn(1, 3, 10, 10, 10) + wrapper = eval(m)(3, 2, 1) + wrapper(x_normal) + nn_module_forward.assert_called_with(x_normal) + + with patch('torch.nn.Linear.forward') as nn_module_forward: + # randn input + x_empty = torch.randn(0, 3) + wrapper = Linear(3, 3) + wrapper(x_empty) + nn_module_forward.assert_called_with(x_empty) + + # non-randn input + x_normal = torch.randn(1, 3) + wrapper = Linear(3, 3) + wrapper(x_normal) + nn_module_forward.assert_called_with(x_normal) diff --git a/cv/distiller/CWD/mmcv/tests/test_image/test_colorspace.py b/cv/distiller/CWD/mmcv/tests/test_image/test_colorspace.py new file mode 100644 index 000000000..d53e4e44d --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_image/test_colorspace.py @@ -0,0 +1,355 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import cv2 +import numpy as np +import pytest +from numpy.testing import assert_array_almost_equal, assert_array_equal + +import mmcv +from mmcv.image.colorspace import (_convert_input_type_range, + _convert_output_type_range) + + +def test_bgr2gray(): + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = mmcv.bgr2gray(in_img) + computed_gray = ( + in_img[:, :, 0] * 0.114 + in_img[:, :, 1] * 0.587 + + in_img[:, :, 2] * 0.299) + assert_array_almost_equal(out_img, computed_gray, decimal=4) + out_img_3d = mmcv.bgr2gray(in_img, True) + assert out_img_3d.shape == (10, 10, 1) + assert_array_almost_equal(out_img_3d[..., 0], out_img, decimal=4) + + +def test_rgb2gray(): + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = mmcv.rgb2gray(in_img) + computed_gray = ( + in_img[:, :, 0] * 0.299 + in_img[:, :, 1] * 0.587 + + in_img[:, :, 2] * 0.114) + assert_array_almost_equal(out_img, computed_gray, decimal=4) + out_img_3d = mmcv.rgb2gray(in_img, True) + assert out_img_3d.shape == (10, 10, 1) + assert_array_almost_equal(out_img_3d[..., 0], out_img, decimal=4) + + +def test_gray2bgr(): + in_img = np.random.rand(10, 10).astype(np.float32) + out_img = mmcv.gray2bgr(in_img) + assert out_img.shape == (10, 10, 3) + for i in range(3): + assert_array_almost_equal(out_img[..., i], in_img, decimal=4) + + +def test_gray2rgb(): + in_img = np.random.rand(10, 10).astype(np.float32) + out_img = mmcv.gray2rgb(in_img) + assert out_img.shape == (10, 10, 3) + for i in range(3): + assert_array_almost_equal(out_img[..., i], in_img, decimal=4) + + +def test_bgr2rgb(): + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = mmcv.bgr2rgb(in_img) + assert out_img.shape == in_img.shape + assert_array_equal(out_img[..., 0], in_img[..., 2]) + assert_array_equal(out_img[..., 1], in_img[..., 1]) + assert_array_equal(out_img[..., 2], in_img[..., 0]) + + +def test_rgb2bgr(): + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = mmcv.rgb2bgr(in_img) + assert out_img.shape == in_img.shape + assert_array_equal(out_img[..., 0], in_img[..., 2]) + assert_array_equal(out_img[..., 1], in_img[..., 1]) + assert_array_equal(out_img[..., 2], in_img[..., 0]) + + +def test_bgr2hsv(): + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = mmcv.bgr2hsv(in_img) + argmax = in_img.argmax(axis=2) + computed_hsv = np.empty_like(in_img) + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + b, g, r = in_img[i, j] + v = max(r, g, b) + s = (v - min(r, g, b)) / v if v != 0 else 0 + if argmax[i, j] == 0: + h = 240 + 60 * (r - g) / (v - min(r, g, b)) + elif argmax[i, j] == 1: + h = 120 + 60 * (b - r) / (v - min(r, g, b)) + else: + h = 60 * (g - b) / (v - min(r, g, b)) + if h < 0: + h += 360 + computed_hsv[i, j, :] = [h, s, v] + assert_array_almost_equal(out_img, computed_hsv, decimal=2) + + +def test_convert_input_type_range(): + with pytest.raises(TypeError): + # The img type should be np.float32 or np.uint8 + in_img = np.random.rand(10, 10, 3).astype(np.uint64) + _convert_input_type_range(in_img) + # np.float32 + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = _convert_input_type_range(in_img) + assert out_img.dtype == np.float32 + assert np.absolute(out_img).mean() < 1 + # np.uint8 + in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8) + out_img = _convert_input_type_range(in_img) + assert out_img.dtype == np.float32 + assert np.absolute(out_img).mean() < 1 + + +def test_convert_output_type_range(): + with pytest.raises(TypeError): + # The dst_type should be np.float32 or np.uint8 + in_img = np.random.rand(10, 10, 3).astype(np.float32) + _convert_output_type_range(in_img, np.uint64) + # np.float32 + in_img = (np.random.rand(10, 10, 3) * 255).astype(np.float32) + out_img = _convert_output_type_range(in_img, np.float32) + assert out_img.dtype == np.float32 + assert np.absolute(out_img).mean() < 1 + # np.uint8 + in_img = (np.random.rand(10, 10, 3) * 255).astype(np.float32) + out_img = _convert_output_type_range(in_img, np.uint8) + assert out_img.dtype == np.uint8 + assert np.absolute(out_img).mean() > 1 + + +def assert_image_almost_equal(x, y, atol=1): + assert x.dtype == np.uint8 + assert y.dtype == np.uint8 + assert np.all(np.abs(x.astype(np.int32) - y.astype(np.int32)) <= atol) + + +def test_rgb2ycbcr(): + with pytest.raises(TypeError): + # The img type should be np.float32 or np.uint8 + in_img = np.random.rand(10, 10, 3).astype(np.uint64) + mmcv.rgb2ycbcr(in_img) + + # float32 + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = mmcv.rgb2ycbcr(in_img) + computed_ycbcr = np.empty_like(in_img) + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + r, g, b = in_img[i, j] + y = 16 + r * 65.481 + g * 128.553 + b * 24.966 + cb = 128 - r * 37.797 - g * 74.203 + b * 112.0 + cr = 128 + r * 112.0 - g * 93.786 - b * 18.214 + computed_ycbcr[i, j, :] = [y, cb, cr] + computed_ycbcr /= 255. + assert_array_almost_equal(out_img, computed_ycbcr, decimal=2) + # y_only=True + out_img = mmcv.rgb2ycbcr(in_img, y_only=True) + computed_y = np.empty_like(out_img, dtype=out_img.dtype) + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + r, g, b = in_img[i, j] + y = 16 + r * 65.481 + g * 128.553 + b * 24.966 + computed_y[i, j] = y + computed_y /= 255. + assert_array_almost_equal(out_img, computed_y, decimal=2) + + # uint8 + in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8) + out_img = mmcv.rgb2ycbcr(in_img) + computed_ycbcr = np.empty_like(in_img) + in_img = in_img / 255. + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + r, g, b = in_img[i, j] + y = 16 + r * 65.481 + g * 128.553 + b * 24.966 + cb = 128 - r * 37.797 - g * 74.203 + b * 112.0 + cr = 128 + r * 112.0 - g * 93.786 - b * 18.214 + y, cb, cr = y.round(), cb.round(), cr.round() + computed_ycbcr[i, j, :] = [y, cb, cr] + assert_image_almost_equal(out_img, computed_ycbcr) + # y_only=True + in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8) + out_img = mmcv.rgb2ycbcr(in_img, y_only=True) + computed_y = np.empty_like(out_img, dtype=out_img.dtype) + in_img = in_img / 255. + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + r, g, b = in_img[i, j] + y = 16 + r * 65.481 + g * 128.553 + b * 24.966 + y = y.round() + computed_y[i, j] = y + assert_image_almost_equal(out_img, computed_y) + + +def test_bgr2ycbcr(): + # float32 + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = mmcv.bgr2ycbcr(in_img) + computed_ycbcr = np.empty_like(in_img) + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + b, g, r = in_img[i, j] + y = 16 + r * 65.481 + g * 128.553 + b * 24.966 + cb = 128 - r * 37.797 - g * 74.203 + b * 112.0 + cr = 128 + r * 112.0 - g * 93.786 - b * 18.214 + computed_ycbcr[i, j, :] = [y, cb, cr] + computed_ycbcr /= 255. + assert_array_almost_equal(out_img, computed_ycbcr, decimal=2) + # y_only=True + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = mmcv.bgr2ycbcr(in_img, y_only=True) + computed_y = np.empty_like(out_img, dtype=out_img.dtype) + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + b, g, r = in_img[i, j] + y = 16 + r * 65.481 + g * 128.553 + b * 24.966 + computed_y[i, j] = y + computed_y /= 255. + assert_array_almost_equal(out_img, computed_y, decimal=2) + + # uint8 + in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8) + out_img = mmcv.bgr2ycbcr(in_img) + computed_ycbcr = np.empty_like(in_img) + in_img = in_img / 255. + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + b, g, r = in_img[i, j] + y = 16 + r * 65.481 + g * 128.553 + b * 24.966 + cb = 128 - r * 37.797 - g * 74.203 + b * 112.0 + cr = 128 + r * 112.0 - g * 93.786 - b * 18.214 + y, cb, cr = y.round(), cb.round(), cr.round() + computed_ycbcr[i, j, :] = [y, cb, cr] + assert_image_almost_equal(out_img, computed_ycbcr) + # y_only = True + in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8) + out_img = mmcv.bgr2ycbcr(in_img, y_only=True) + computed_y = np.empty_like(out_img, dtype=out_img.dtype) + in_img = in_img / 255. + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + b, g, r = in_img[i, j] + y = 16 + r * 65.481 + g * 128.553 + b * 24.966 + y = y.round() + computed_y[i, j] = y + assert_image_almost_equal(out_img, computed_y) + + +def test_ycbcr2rgb(): + with pytest.raises(TypeError): + # The img type should be np.float32 or np.uint8 + in_img = np.random.rand(10, 10, 3).astype(np.uint64) + mmcv.ycbcr2rgb(in_img) + + # float32 + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = mmcv.ycbcr2rgb(in_img) + computed_rgb = np.empty_like(in_img) + in_img *= 255. + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + y, cb, cr = in_img[i, j] + r = -222.921 + y * 0.00456621 * 255 + cr * 0.00625893 * 255 + g = 135.576 + y * 0.00456621 * 255 - cb * 0.00153632 * 255 - \ + cr * 0.00318811 * 255 + b = -276.836 + y * 0.00456621 * 255. + cb * 0.00791071 * 255 + computed_rgb[i, j, :] = [r, g, b] + computed_rgb /= 255. + assert_array_almost_equal(out_img, computed_rgb, decimal=2) + + # uint8 + in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8) + out_img = mmcv.ycbcr2rgb(in_img) + computed_rgb = np.empty_like(in_img) + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + y, cb, cr = in_img[i, j] + r = -222.921 + y * 0.00456621 * 255 + cr * 0.00625893 * 255 + g = 135.576 + y * 0.00456621 * 255 - cb * 0.00153632 * 255 - \ + cr * 0.00318811 * 255 + b = -276.836 + y * 0.00456621 * 255. + cb * 0.00791071 * 255 + r, g, b = r.round(), g.round(), b.round() + computed_rgb[i, j, :] = [r, g, b] + assert_image_almost_equal(out_img, computed_rgb) + + +def test_ycbcr2bgr(): + # float32 + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = mmcv.ycbcr2bgr(in_img) + computed_bgr = np.empty_like(in_img) + in_img *= 255. + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + y, cb, cr = in_img[i, j] + r = -222.921 + y * 0.00456621 * 255 + cr * 0.00625893 * 255 + g = 135.576 + y * 0.00456621 * 255 - cb * 0.00153632 * 255 - \ + cr * 0.00318811 * 255 + b = -276.836 + y * 0.00456621 * 255. + cb * 0.00791071 * 255 + computed_bgr[i, j, :] = [b, g, r] + computed_bgr /= 255. + assert_array_almost_equal(out_img, computed_bgr, decimal=2) + + # uint8 + in_img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8) + out_img = mmcv.ycbcr2bgr(in_img) + computed_bgr = np.empty_like(in_img) + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + y, cb, cr = in_img[i, j] + r = -222.921 + y * 0.00456621 * 255 + cr * 0.00625893 * 255 + g = 135.576 + y * 0.00456621 * 255 - cb * 0.00153632 * 255 - \ + cr * 0.00318811 * 255 + b = -276.836 + y * 0.00456621 * 255. + cb * 0.00791071 * 255 + r, g, b = r.round(), g.round(), b.round() + computed_bgr[i, j, :] = [b, g, r] + assert_image_almost_equal(out_img, computed_bgr) + + +def test_bgr2hls(): + in_img = np.random.rand(10, 10, 3).astype(np.float32) + out_img = mmcv.bgr2hls(in_img) + argmax = in_img.argmax(axis=2) + computed_hls = np.empty_like(in_img) + for i in range(in_img.shape[0]): + for j in range(in_img.shape[1]): + b, g, r = in_img[i, j] + maxc = max(r, g, b) + minc = min(r, g, b) + _l = (minc + maxc) / 2.0 + if minc == maxc: + h = 0.0 + s = 0.0 + if _l <= 0.5: + s = (maxc - minc) / (maxc + minc) + else: + s = (maxc - minc) / (2.0 - maxc - minc) + if argmax[i, j] == 2: + h = 60 * (g - b) / (maxc - minc) + elif argmax[i, j] == 1: + h = 60 * (2.0 + (b - r) / (maxc - minc)) + else: + h = 60 * (4.0 + (r - g) / (maxc - minc)) + if h < 0: + h += 360 + computed_hls[i, j, :] = [h, _l, s] + assert_array_almost_equal(out_img, computed_hls, decimal=2) + + +@pytest.mark.parametrize('src,dst,ref', [('bgr', 'gray', cv2.COLOR_BGR2GRAY), + ('rgb', 'gray', cv2.COLOR_RGB2GRAY), + ('bgr', 'rgb', cv2.COLOR_BGR2RGB), + ('rgb', 'bgr', cv2.COLOR_RGB2BGR), + ('bgr', 'hsv', cv2.COLOR_BGR2HSV), + ('hsv', 'bgr', cv2.COLOR_HSV2BGR), + ('bgr', 'hls', cv2.COLOR_BGR2HLS), + ('hls', 'bgr', cv2.COLOR_HLS2BGR)]) +def test_imconvert(src, dst, ref): + img = np.random.rand(10, 10, 3).astype(np.float32) + assert_array_equal(mmcv.imconvert(img, src, dst), cv2.cvtColor(img, ref)) diff --git a/cv/distiller/CWD/mmcv/tests/test_image/test_geometric.py b/cv/distiller/CWD/mmcv/tests/test_image/test_geometric.py new file mode 100644 index 000000000..e6409d7e5 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_image/test_geometric.py @@ -0,0 +1,617 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os.path as osp + +import cv2 +import numpy as np +import pytest +from numpy.testing import assert_array_equal + +import mmcv + + +class TestGeometric: + + @classmethod + def setup_class(cls): + cls.data_dir = osp.join(osp.dirname(__file__), '../data') + # the test img resolution is 400x300 + cls.img_path = osp.join(cls.data_dir, 'color.jpg') + cls.img = cv2.imread(cls.img_path) + + def test_imresize(self): + resized_img = mmcv.imresize(self.img, (1000, 600)) + assert resized_img.shape == (600, 1000, 3) + resized_img, w_scale, h_scale = mmcv.imresize(self.img, (1000, 600), + True) + assert (resized_img.shape == (600, 1000, 3) and w_scale == 2.5 + and h_scale == 2.0) + resized_img_dst = np.empty((600, 1000, 3), dtype=self.img.dtype) + resized_img = mmcv.imresize(self.img, (1000, 600), out=resized_img_dst) + assert id(resized_img_dst) == id(resized_img) + assert_array_equal(resized_img_dst, + mmcv.imresize(self.img, (1000, 600))) + for mode in ['nearest', 'bilinear', 'bicubic', 'area', 'lanczos']: + resized_img = mmcv.imresize( + self.img, (1000, 600), interpolation=mode) + assert resized_img.shape == (600, 1000, 3) + + # test pillow resize + for mode in [ + 'nearest', 'bilinear', 'bicubic', 'box', 'lanczos', 'hamming' + ]: + resized_img = mmcv.imresize( + self.img, (1000, 600), interpolation=mode, backend='pillow') + assert resized_img.shape == (600, 1000, 3) + + # resize backend must be 'cv2' or 'pillow' + with pytest.raises(ValueError): + mmcv.imresize(self.img, (1000, 600), backend='not support') + + def test_imresize_to_multiple(self): + # test size and keep_ratio = False + resized_img = mmcv.imresize_to_multiple( + self.img, divisor=16, size=(511, 513), keep_ratio=False) + assert resized_img.shape == (528, 512, 3) + resized_img = mmcv.imresize_to_multiple( + self.img, divisor=(16, 32), size=(511, 513), keep_ratio=False) + assert resized_img.shape == (544, 512, 3) + + # test size, keep_ratio = True, and return_scale + resized_img, w_scale, h_scale = mmcv.imresize_to_multiple( + self.img, + divisor=16, + size=(1000, 600), + keep_ratio=True, + return_scale=True) + assert resized_img.shape == ( + 608, 800, 3) and h_scale == 608 / 300 and w_scale == 800 / 400 + resized_img, w_scale, h_scale = mmcv.imresize_to_multiple( + self.img, + divisor=(18, 16), + size=(1000, 600), + keep_ratio=True, + return_scale=True) + assert resized_img.shape == ( + 608, 810, 3) and h_scale == 608 / 300 and w_scale == 810 / 400 + + # test scale_factor and return_scale + resized_img, w_scale, h_scale = mmcv.imresize_to_multiple( + self.img, divisor=16, scale_factor=2, return_scale=True) + assert resized_img.shape == ( + 608, 800, 3) and h_scale == 608 / 300 and w_scale == 800 / 400 + resized_img, w_scale, h_scale = mmcv.imresize_to_multiple( + self.img, divisor=16, scale_factor=(2, 3), return_scale=True) + assert resized_img.shape == ( + 912, 800, 3) and h_scale == 912 / 300 and w_scale == 800 / 400 + resized_img, w_scale, h_scale = mmcv.imresize_to_multiple( + self.img, divisor=(18, 16), scale_factor=(2, 3), return_scale=True) + assert resized_img.shape == ( + 912, 810, 3) and h_scale == 912 / 300 and w_scale == 810 / 400 + + # one of size and scale_factor should be given + with pytest.raises(ValueError): + mmcv.imresize_to_multiple( + self.img, divisor=16, size=(1000, 600), scale_factor=2) + with pytest.raises(ValueError): + mmcv.imresize_to_multiple( + self.img, divisor=16, size=None, scale_factor=None) + + def test_imresize_like(self): + a = np.zeros((100, 200, 3)) + resized_img = mmcv.imresize_like(self.img, a) + assert resized_img.shape == (100, 200, 3) + + def test_rescale_size(self): + new_size, scale_factor = mmcv.rescale_size((400, 300), 1.5, True) + assert new_size == (600, 450) and scale_factor == 1.5 + new_size, scale_factor = mmcv.rescale_size((400, 300), 0.934, True) + assert new_size == (374, 280) and scale_factor == 0.934 + + new_size = mmcv.rescale_size((400, 300), 1.5) + assert new_size == (600, 450) + new_size = mmcv.rescale_size((400, 300), 0.934) + assert new_size == (374, 280) + + new_size, scale_factor = mmcv.rescale_size((400, 300), (1000, 600), + True) + assert new_size == (800, 600) and scale_factor == 2.0 + new_size, scale_factor = mmcv.rescale_size((400, 300), (180, 200), + True) + assert new_size == (200, 150) and scale_factor == 0.5 + + new_size = mmcv.rescale_size((400, 300), (1000, 600)) + assert new_size == (800, 600) + new_size = mmcv.rescale_size((400, 300), (180, 200)) + assert new_size == (200, 150) + + with pytest.raises(ValueError): + mmcv.rescale_size((400, 300), -0.5) + with pytest.raises(TypeError): + mmcv.rescale_size()((400, 300), [100, 100]) + + def test_imrescale(self): + # rescale by a certain factor + resized_img = mmcv.imrescale(self.img, 1.5) + assert resized_img.shape == (450, 600, 3) + resized_img = mmcv.imrescale(self.img, 0.934) + assert resized_img.shape == (280, 374, 3) + + # rescale by a certain max_size + # resize (400, 300) to (max_1000, max_600) + resized_img = mmcv.imrescale(self.img, (1000, 600)) + assert resized_img.shape == (600, 800, 3) + resized_img, scale = mmcv.imrescale( + self.img, (1000, 600), return_scale=True) + assert resized_img.shape == (600, 800, 3) and scale == 2.0 + # resize (400, 300) to (max_200, max_180) + resized_img = mmcv.imrescale(self.img, (180, 200)) + assert resized_img.shape == (150, 200, 3) + resized_img, scale = mmcv.imrescale( + self.img, (180, 200), return_scale=True) + assert resized_img.shape == (150, 200, 3) and scale == 0.5 + + # test exceptions + with pytest.raises(ValueError): + mmcv.imrescale(self.img, -0.5) + with pytest.raises(TypeError): + mmcv.imrescale(self.img, [100, 100]) + + def test_imflip(self): + # direction must be "horizontal" or "vertical" or "diagonal" + with pytest.raises(AssertionError): + mmcv.imflip(np.random.rand(80, 60, 3), direction='random') + + # test horizontal flip (color image) + img = np.random.rand(80, 60, 3) + h, w, c = img.shape + flipped_img = mmcv.imflip(img) + assert flipped_img.shape == img.shape + for i in range(h): + for j in range(w): + for k in range(c): + assert flipped_img[i, j, k] == img[i, w - 1 - j, k] + + # test vertical flip (color image) + flipped_img = mmcv.imflip(img, direction='vertical') + assert flipped_img.shape == img.shape + for i in range(h): + for j in range(w): + for k in range(c): + assert flipped_img[i, j, k] == img[h - 1 - i, j, k] + + # test diagonal flip (color image) + flipped_img = mmcv.imflip(img, direction='diagonal') + assert flipped_img.shape == img.shape + for i in range(h): + for j in range(w): + for k in range(c): + assert flipped_img[i, j, k] == img[h - 1 - i, w - 1 - j, k] + + # test horizontal flip (grayscale image) + img = np.random.rand(80, 60) + h, w = img.shape + flipped_img = mmcv.imflip(img) + assert flipped_img.shape == img.shape + for i in range(h): + for j in range(w): + assert flipped_img[i, j] == img[i, w - 1 - j] + + # test vertical flip (grayscale image) + flipped_img = mmcv.imflip(img, direction='vertical') + assert flipped_img.shape == img.shape + for i in range(h): + for j in range(w): + assert flipped_img[i, j] == img[h - 1 - i, j] + + # test diagonal flip (grayscale image) + flipped_img = mmcv.imflip(img, direction='diagonal') + assert flipped_img.shape == img.shape + for i in range(h): + for j in range(w): + assert flipped_img[i, j] == img[h - 1 - i, w - 1 - j] + + def test_imflip_(self): + # direction must be "horizontal" or "vertical" or "diagonal" + with pytest.raises(AssertionError): + mmcv.imflip_(np.random.rand(80, 60, 3), direction='random') + + # test horizontal flip (color image) + img = np.random.rand(80, 60, 3) + h, w, c = img.shape + img_for_flip = img.copy() + flipped_img = mmcv.imflip_(img_for_flip) + assert flipped_img.shape == img.shape + assert flipped_img.shape == img_for_flip.shape + assert id(flipped_img) == id(img_for_flip) + for i in range(h): + for j in range(w): + for k in range(c): + assert flipped_img[i, j, k] == img[i, w - 1 - j, k] + assert flipped_img[i, j, k] == img_for_flip[i, j, k] + + # test vertical flip (color image) + img_for_flip = img.copy() + flipped_img = mmcv.imflip_(img_for_flip, direction='vertical') + assert flipped_img.shape == img.shape + assert flipped_img.shape == img_for_flip.shape + assert id(flipped_img) == id(img_for_flip) + for i in range(h): + for j in range(w): + for k in range(c): + assert flipped_img[i, j, k] == img[h - 1 - i, j, k] + assert flipped_img[i, j, k] == img_for_flip[i, j, k] + + # test diagonal flip (color image) + img_for_flip = img.copy() + flipped_img = mmcv.imflip_(img_for_flip, direction='diagonal') + assert flipped_img.shape == img.shape + assert flipped_img.shape == img_for_flip.shape + assert id(flipped_img) == id(img_for_flip) + for i in range(h): + for j in range(w): + for k in range(c): + assert flipped_img[i, j, k] == img[h - 1 - i, w - 1 - j, k] + assert flipped_img[i, j, k] == img_for_flip[i, j, k] + + # test horizontal flip (grayscale image) + img = np.random.rand(80, 60) + h, w = img.shape + img_for_flip = img.copy() + flipped_img = mmcv.imflip_(img_for_flip) + assert flipped_img.shape == img.shape + assert flipped_img.shape == img_for_flip.shape + assert id(flipped_img) == id(img_for_flip) + for i in range(h): + for j in range(w): + assert flipped_img[i, j] == img[i, w - 1 - j] + assert flipped_img[i, j] == img_for_flip[i, j] + + # test vertical flip (grayscale image) + img_for_flip = img.copy() + flipped_img = mmcv.imflip_(img_for_flip, direction='vertical') + assert flipped_img.shape == img.shape + assert flipped_img.shape == img_for_flip.shape + assert id(flipped_img) == id(img_for_flip) + for i in range(h): + for j in range(w): + assert flipped_img[i, j] == img[h - 1 - i, j] + assert flipped_img[i, j] == img_for_flip[i, j] + + # test diagonal flip (grayscale image) + img_for_flip = img.copy() + flipped_img = mmcv.imflip_(img_for_flip, direction='diagonal') + assert flipped_img.shape == img.shape + assert flipped_img.shape == img_for_flip.shape + assert id(flipped_img) == id(img_for_flip) + for i in range(h): + for j in range(w): + assert flipped_img[i, j] == img[h - 1 - i, w - 1 - j] + assert flipped_img[i, j] == img_for_flip[i, j] + + def test_imcrop(self): + # yapf: disable + bboxes = np.array([[100, 100, 199, 199], # center + [0, 0, 150, 100], # left-top corner + [250, 200, 399, 299], # right-bottom corner + [0, 100, 399, 199], # wide + [150, 0, 299, 299]]) # tall + # yapf: enable + + # crop one bbox + patch = mmcv.imcrop(self.img, bboxes[0, :]) + patches = mmcv.imcrop(self.img, bboxes[[0], :]) + assert patch.shape == (100, 100, 3) + patch_path = osp.join(self.data_dir, 'patches') + ref_patch = np.load(patch_path + '/0.npy') + assert_array_equal(patch, ref_patch) + assert isinstance(patches, list) and len(patches) == 1 + assert_array_equal(patches[0], ref_patch) + + # crop with no scaling and padding + patches = mmcv.imcrop(self.img, bboxes) + assert len(patches) == bboxes.shape[0] + for i in range(len(patches)): + ref_patch = np.load(patch_path + f'/{i}.npy') + assert_array_equal(patches[i], ref_patch) + + # crop with scaling and no padding + patches = mmcv.imcrop(self.img, bboxes, 1.2) + for i in range(len(patches)): + ref_patch = np.load(patch_path + f'/scale_{i}.npy') + assert_array_equal(patches[i], ref_patch) + + # crop with scaling and padding + patches = mmcv.imcrop(self.img, bboxes, 1.2, pad_fill=[255, 255, 0]) + for i in range(len(patches)): + ref_patch = np.load(patch_path + f'/pad_{i}.npy') + assert_array_equal(patches[i], ref_patch) + patches = mmcv.imcrop(self.img, bboxes, 1.2, pad_fill=0) + for i in range(len(patches)): + ref_patch = np.load(patch_path + f'/pad0_{i}.npy') + assert_array_equal(patches[i], ref_patch) + + def test_impad(self): + # grayscale image + img = np.random.rand(10, 10).astype(np.float32) + padded_img = mmcv.impad(img, padding=(0, 0, 2, 5), pad_val=0) + assert_array_equal(img, padded_img[:10, :10]) + assert_array_equal( + np.zeros((5, 12), dtype='float32'), padded_img[10:, :]) + assert_array_equal( + np.zeros((15, 2), dtype='float32'), padded_img[:, 10:]) + + # RGB image + img = np.random.rand(10, 10, 3).astype(np.float32) + padded_img = mmcv.impad(img, padding=(0, 0, 2, 5), pad_val=0) + assert_array_equal(img, padded_img[:10, :10, :]) + assert_array_equal( + np.zeros((5, 12, 3), dtype='float32'), padded_img[10:, :, :]) + assert_array_equal( + np.zeros((15, 2, 3), dtype='float32'), padded_img[:, 10:, :]) + + # RGB image with different values for three channels. + img = np.random.randint(256, size=(10, 10, 3)).astype('uint8') + padded_img = mmcv.impad( + img, padding=(0, 0, 2, 5), pad_val=(100, 110, 120)) + assert_array_equal(img, padded_img[:10, :10, :]) + assert_array_equal( + np.array([100, 110, 120], dtype='uint8') * np.ones( + (5, 12, 3), dtype='uint8'), padded_img[10:, :, :]) + assert_array_equal( + np.array([100, 110, 120], dtype='uint8') * np.ones( + (15, 2, 3), dtype='uint8'), padded_img[:, 10:, :]) + + # Pad the grayscale image to shape (15, 12) + img = np.random.rand(10, 10).astype(np.float32) + padded_img = mmcv.impad(img, shape=(15, 12)) + assert_array_equal(img, padded_img[:10, :10]) + assert_array_equal( + np.zeros((5, 12), dtype='float32'), padded_img[10:, :]) + assert_array_equal( + np.zeros((15, 2), dtype='float32'), padded_img[:, 10:]) + + # Pad the RGB image to shape (15, 12) + img = np.random.rand(10, 10, 3).astype(np.float32) + padded_img = mmcv.impad(img, shape=(15, 12)) + assert_array_equal(img, padded_img[:10, :10, :]) + assert_array_equal( + np.zeros((5, 12, 3), dtype='float32'), padded_img[10:, :, :]) + assert_array_equal( + np.zeros((15, 2, 3), dtype='float32'), padded_img[:, 10:, :]) + + # Pad the RGB image to shape (15, 12) with different values for + # three channels. + img = np.random.randint(256, size=(10, 10, 3)).astype('uint8') + padded_img = mmcv.impad(img, shape=(15, 12), pad_val=(100, 110, 120)) + assert_array_equal(img, padded_img[:10, :10, :]) + assert_array_equal( + np.array([100, 110, 120], dtype='uint8') * np.ones( + (5, 12, 3), dtype='uint8'), padded_img[10:, :, :]) + assert_array_equal( + np.array([100, 110, 120], dtype='uint8') * np.ones( + (15, 2, 3), dtype='uint8'), padded_img[:, 10:, :]) + + # RGB image with padding=[5, 2] + img = np.random.rand(10, 10, 3).astype(np.float32) + padded_img = mmcv.impad(img, padding=(5, 2), pad_val=0) + + assert padded_img.shape == (14, 20, 3) + assert_array_equal(img, padded_img[2:12, 5:15, :]) + assert_array_equal( + np.zeros((2, 5, 3), dtype='float32'), padded_img[:2, :5, :]) + assert_array_equal( + np.zeros((2, 5, 3), dtype='float32'), padded_img[12:, :5, :]) + assert_array_equal( + np.zeros((2, 5, 3), dtype='float32'), padded_img[:2, 15:, :]) + assert_array_equal( + np.zeros((2, 5, 3), dtype='float32'), padded_img[12:, 15:, :]) + + # RGB image with type(pad_val) = tuple + pad_val = (0, 1, 2) + img = np.random.rand(10, 10, 3).astype(np.float32) + padded_img = mmcv.impad(img, padding=(0, 0, 5, 2), pad_val=pad_val) + + assert padded_img.shape == (12, 15, 3) + assert_array_equal(img, padded_img[:10, :10, :]) + assert_array_equal(pad_val[0] * np.ones((2, 15, 1), dtype='float32'), + padded_img[10:, :, 0:1]) + assert_array_equal(pad_val[1] * np.ones((2, 15, 1), dtype='float32'), + padded_img[10:, :, 1:2]) + assert_array_equal(pad_val[2] * np.ones((2, 15, 1), dtype='float32'), + padded_img[10:, :, 2:3]) + + assert_array_equal(pad_val[0] * np.ones((12, 5, 1), dtype='float32'), + padded_img[:, 10:, 0:1]) + assert_array_equal(pad_val[1] * np.ones((12, 5, 1), dtype='float32'), + padded_img[:, 10:, 1:2]) + assert_array_equal(pad_val[2] * np.ones((12, 5, 1), dtype='float32'), + padded_img[:, 10:, 2:3]) + + # test different padding mode with channel number = 3 + for mode in ['constant', 'edge', 'reflect', 'symmetric']: + img = np.random.rand(10, 10, 3).astype(np.float32) + padded_img = mmcv.impad( + img, padding=(0, 0, 5, 2), pad_val=pad_val, padding_mode=mode) + assert padded_img.shape == (12, 15, 3) + + # test different padding mode with channel number = 1 + for mode in ['constant', 'edge', 'reflect', 'symmetric']: + img = np.random.rand(10, 10).astype(np.float32) + padded_img = mmcv.impad( + img, padding=(0, 0, 5, 2), pad_val=0, padding_mode=mode) + assert padded_img.shape == (12, 15) + + # Padding must be a int or a 2, or 4 element tuple. + with pytest.raises(ValueError): + mmcv.impad(img, padding=(1, 1, 1)) + + # pad_val must be a int or a tuple + with pytest.raises(TypeError): + mmcv.impad(img, padding=(1, 1, 1, 1), pad_val='wrong') + + # When pad_val is a tuple, + # len(pad_val) should be equal to img.shape[-1] + img = np.random.rand(10, 10, 3).astype(np.float32) + with pytest.raises(AssertionError): + mmcv.impad(img, padding=3, pad_val=(100, 200)) + + with pytest.raises(AssertionError): + mmcv.impad(img, padding=2, pad_val=0, padding_mode='unknown') + + with pytest.raises(AssertionError): + mmcv.impad(img, shape=(12, 15), padding=(0, 0, 5, 2)) + + # Pad shape smaller than image shape + padded_img = mmcv.impad(img, shape=(8, 8)) + assert padded_img.shape == (10, 10, 3) + + def test_impad_to_multiple(self): + img = np.random.rand(11, 14, 3).astype(np.float32) + padded_img = mmcv.impad_to_multiple(img, 4) + assert padded_img.shape == (12, 16, 3) + img = np.random.rand(20, 12).astype(np.float32) + padded_img = mmcv.impad_to_multiple(img, 5) + assert padded_img.shape == (20, 15) + img = np.random.rand(20, 12).astype(np.float32) + padded_img = mmcv.impad_to_multiple(img, 2) + assert padded_img.shape == (20, 12) + + def test_cutout(self): + img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8) + + # shape must be int or tuple + with pytest.raises(AssertionError): + mmcv.cutout(img, 2.5) + # pad_val must be int or float or tuple with the same length + # of img channels + with pytest.raises(AssertionError): + mmcv.cutout(img, 1, (1, 2, 3)) + with pytest.raises(TypeError): + mmcv.cutout(img, 1, None) + + # test cutout the whole img + assert_array_equal(mmcv.cutout(img, 6), np.zeros_like(img)) + # test not cutout + assert_array_equal(mmcv.cutout(img, 0), img) + # test cutout when shape is int + np.random.seed(0) + img_cutout = np.array([[1, 2, 3], [4, 0, 6], [7, 8, + 9]]).astype(np.uint8) + assert_array_equal(mmcv.cutout(img, 1), img_cutout) + img_cutout = np.array([[1, 2, 3], [4, 10, 6], [7, 8, + 9]]).astype(np.uint8) + assert_array_equal(mmcv.cutout(img, 1, pad_val=10), img_cutout) + # test cutout when shape is tuple + np.random.seed(0) + img_cutout = np.array([[1, 2, 3], [0, 0, 6], [7, 8, + 9]]).astype(np.uint8) + assert_array_equal(mmcv.cutout(img, (1, 2)), img_cutout) + img_cutout = np.array([[1, 2, 3], [10, 10, 6], [7, 8, + 9]]).astype(np.uint8) + assert_array_equal(mmcv.cutout(img, (1, 2), pad_val=10), img_cutout) + + def test_imrotate(self): + img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8) + assert_array_equal(mmcv.imrotate(img, 0), img) + img_r = np.array([[7, 4, 1], [8, 5, 2], [9, 6, 3]]) + assert_array_equal(mmcv.imrotate(img, 90), img_r) + img_r = np.array([[3, 6, 9], [2, 5, 8], [1, 4, 7]]) + assert_array_equal(mmcv.imrotate(img, -90), img_r) + + img = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]).astype(np.uint8) + img_r = np.array([[0, 6, 2, 0], [0, 7, 3, 0]]) + assert_array_equal(mmcv.imrotate(img, 90), img_r) + img_r = np.array([[1, 0, 0, 0], [2, 0, 0, 0]]) + assert_array_equal(mmcv.imrotate(img, 90, center=(0, 0)), img_r) + img_r = np.array([[255, 6, 2, 255], [255, 7, 3, 255]]) + assert_array_equal(mmcv.imrotate(img, 90, border_value=255), img_r) + img_r = np.array([[5, 1], [6, 2], [7, 3], [8, 4]]) + assert_array_equal(mmcv.imrotate(img, 90, auto_bound=True), img_r) + img_r = np.array([[6, 6, 2, 2], [7, 7, 3, 3]]) + assert_array_equal( + mmcv.imrotate(img, 90, border_mode='replicate'), img_r) + + with pytest.raises(ValueError): + mmcv.imrotate(img, 90, center=(0, 0), auto_bound=True) + + def test_imshear(self): + img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8) + assert_array_equal(mmcv.imshear(img, 0), img) + # magnitude=1, horizontal + img_sheared = np.array([[1, 2, 3], [0, 4, 5], [0, 0, 7]], + dtype=np.uint8) + assert_array_equal(mmcv.imshear(img, 1), img_sheared) + # magnitude=-1, vertical + img_sheared = np.array([[1, 5, 9], [4, 8, 0], [7, 0, 0]], + dtype=np.uint8) + assert_array_equal(mmcv.imshear(img, -1, 'vertical'), img_sheared) + # magnitude=1, vertical, borderValue=100 + borderValue = 100 + img_sheared = np.array( + [[1, borderValue, borderValue], [4, 2, borderValue], [7, 5, 3]], + dtype=np.uint8) + assert_array_equal( + mmcv.imshear(img, 1, 'vertical', borderValue), img_sheared) + # magnitude=1, vertical, borderValue=100, img shape (h,w,3) + img = np.stack([img, img, img], axis=-1) + img_sheared = np.stack([img_sheared, img_sheared, img_sheared], + axis=-1) + assert_array_equal( + mmcv.imshear(img, 1, 'vertical', borderValue), img_sheared) + # test tuple format of borderValue + assert_array_equal( + mmcv.imshear(img, 1, 'vertical', + (borderValue, borderValue, borderValue)), img_sheared) + + # test invalid length of borderValue + with pytest.raises(AssertionError): + mmcv.imshear(img, 0.5, 'horizontal', (borderValue, )) + + # test invalid type of borderValue + with pytest.raises(ValueError): + mmcv.imshear(img, 0.5, 'horizontal', [borderValue]) + + # test invalid value of direction + with pytest.raises(AssertionError): + mmcv.imshear(img, 0.5, 'diagonal') + + def test_imtranslate(self): + img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.uint8) + assert_array_equal(mmcv.imtranslate(img, 0), img) + # offset=1, horizontal + img_translated = np.array([[128, 1, 2], [128, 4, 5], [128, 7, 8]], + dtype=np.uint8) + assert_array_equal( + mmcv.imtranslate(img, 1, border_value=128), img_translated) + # offset=-1, vertical + img_translated = np.array([[4, 5, 6], [7, 8, 9], [0, 0, 0]], + dtype=np.uint8) + assert_array_equal( + mmcv.imtranslate(img, -1, 'vertical'), img_translated) + # offset=-2, horizontal + img = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=np.uint8) + img = np.stack([img, img, img], axis=-1) + img_translated = [[3, 4, 128, 128], [7, 8, 128, 128]] + img_translated = np.stack( + [img_translated, img_translated, img_translated], axis=-1) + assert_array_equal( + mmcv.imtranslate(img, -2, border_value=128), img_translated) + # offset=2, vertical + border_value = (110, 120, 130) + img_translated = np.stack([ + np.ones((2, 4)) * border_value[0], + np.ones((2, 4)) * border_value[1], + np.ones((2, 4)) * border_value[2] + ], + axis=-1).astype(np.uint8) + assert_array_equal( + mmcv.imtranslate(img, 2, 'vertical', border_value), img_translated) + # test invalid number elements in border_value + with pytest.raises(AssertionError): + mmcv.imtranslate(img, 1, border_value=(1, )) + # test invalid type of border_value + with pytest.raises(ValueError): + mmcv.imtranslate(img, 1, border_value=[1, 2, 3]) + # test invalid value of direction + with pytest.raises(AssertionError): + mmcv.imtranslate(img, 1, 'diagonal') diff --git a/cv/distiller/CWD/mmcv/tests/test_image/test_image_misc.py b/cv/distiller/CWD/mmcv/tests/test_image/test_image_misc.py new file mode 100644 index 000000000..51e61d8e6 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_image/test_image_misc.py @@ -0,0 +1,73 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +from numpy.testing import assert_array_equal + +import mmcv + +try: + import torch +except ImportError: + torch = None + + +@pytest.mark.skipif(torch is None, reason='requires torch library') +def test_tensor2imgs(): + + # test tensor obj + with pytest.raises(AssertionError): + tensor = np.random.rand(2, 3, 3) + mmcv.tensor2imgs(tensor) + + # test tensor ndim + with pytest.raises(AssertionError): + tensor = torch.randn(2, 3, 3) + mmcv.tensor2imgs(tensor) + + # test tensor dim-1 + with pytest.raises(AssertionError): + tensor = torch.randn(2, 4, 3, 3) + mmcv.tensor2imgs(tensor) + + # test mean length + with pytest.raises(AssertionError): + tensor = torch.randn(2, 3, 5, 5) + mmcv.tensor2imgs(tensor, mean=(1, )) + tensor = torch.randn(2, 1, 5, 5) + mmcv.tensor2imgs(tensor, mean=(0, 0, 0)) + + # test std length + with pytest.raises(AssertionError): + tensor = torch.randn(2, 3, 5, 5) + mmcv.tensor2imgs(tensor, std=(1, )) + tensor = torch.randn(2, 1, 5, 5) + mmcv.tensor2imgs(tensor, std=(1, 1, 1)) + + # test to_rgb + with pytest.raises(AssertionError): + tensor = torch.randn(2, 1, 5, 5) + mmcv.tensor2imgs(tensor, mean=(0, ), std=(1, ), to_rgb=True) + + # test rgb=True + tensor = torch.randn(2, 3, 5, 5) + gts = [ + t.cpu().numpy().transpose(1, 2, 0).astype(np.uint8) + for t in tensor.flip(1) + ] + outputs = mmcv.tensor2imgs(tensor, to_rgb=True) + for gt, output in zip(gts, outputs): + assert_array_equal(gt, output) + + # test rgb=False + tensor = torch.randn(2, 3, 5, 5) + gts = [t.cpu().numpy().transpose(1, 2, 0).astype(np.uint8) for t in tensor] + outputs = mmcv.tensor2imgs(tensor, to_rgb=False) + for gt, output in zip(gts, outputs): + assert_array_equal(gt, output) + + # test tensor channel 1 and rgb=False + tensor = torch.randn(2, 1, 5, 5) + gts = [t.squeeze(0).cpu().numpy().astype(np.uint8) for t in tensor] + outputs = mmcv.tensor2imgs(tensor, to_rgb=False) + for gt, output in zip(gts, outputs): + assert_array_equal(gt, output) diff --git a/cv/distiller/CWD/mmcv/tests/test_image/test_io.py b/cv/distiller/CWD/mmcv/tests/test_image/test_io.py new file mode 100644 index 000000000..6742924f2 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_image/test_io.py @@ -0,0 +1,437 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import os.path as osp +import sys +import tempfile +from pathlib import Path +from unittest.mock import MagicMock, patch + +import cv2 +import mmengine +import numpy as np +import pytest +import torch +from mmengine.fileio.file_client import HTTPBackend, PetrelBackend +from numpy.testing import assert_allclose, assert_array_equal + +import mmcv + +if torch.__version__ == 'parrots': + pytest.skip('not necessary in parrots test', allow_module_level=True) + + +class TestIO: + + @classmethod + def setup_class(cls): + cls.data_dir = osp.join(osp.dirname(__file__), '../data') + # the test img resolution is 400x300 + cls.img_path = osp.join(cls.data_dir, 'color.jpg') + cls.img_path_obj = Path(cls.img_path) + cls.gray_img_path = osp.join(cls.data_dir, 'grayscale.jpg') + cls.gray_img_path_obj = Path(cls.gray_img_path) + cls.gray_img_dim3_path = osp.join(cls.data_dir, 'grayscale_dim3.jpg') + cls.gray_alpha_img_path = osp.join(cls.data_dir, 'gray_alpha.png') + cls.palette_img_path = osp.join(cls.data_dir, 'palette.gif') + cls.exif_img_path = osp.join(cls.data_dir, 'color_exif.jpg') + cls.img = cv2.imread(cls.img_path) + cls.tiff_path = osp.join(cls.data_dir, 'uint16-5channel.tif') + # petrel s3 path + cls.s3_path = 's3://path/of/your/file.jpg' + # http path + cls.http_path = 'http://path/of/your/file.jpg' + # add mock package + sys.modules['petrel_client'] = MagicMock() + sys.modules['petrel_client.client'] = MagicMock() + + @classmethod + def teardown_class(cls): + # clean instances avoid to influence other unittest + mmengine.FileClient._instances = {} + + def assert_img_equal(self, img, ref_img, ratio_thr=0.999): + assert img.shape == ref_img.shape + assert img.dtype == ref_img.dtype + area = ref_img.shape[0] * ref_img.shape[1] + diff = np.abs(img.astype('int32') - ref_img.astype('int32')) + assert np.sum(diff <= 1) / float(area) > ratio_thr + + def test_imread(self): + # backend cv2 + mmcv.use_backend('cv2') + + # file_client_args and backend_args can not be both set + with pytest.raises( + ValueError, + match='"file_client_args" and "backend_args" cannot be set'): + mmcv.imread( + self.img_path, + file_client_args={'backend': 'disk'}, + backend_args={'backend': 'disk'}) + + # HardDiskBackend + img_cv2_color_bgr = mmcv.imread(self.img_path) + assert img_cv2_color_bgr.shape == (300, 400, 3) + img_cv2_color_rgb = mmcv.imread(self.img_path, channel_order='rgb') + assert img_cv2_color_rgb.shape == (300, 400, 3) + assert_array_equal(img_cv2_color_rgb[:, :, ::-1], img_cv2_color_bgr) + img_cv2_grayscale1 = mmcv.imread(self.img_path, 'grayscale') + assert img_cv2_grayscale1.shape == (300, 400) + img_cv2_grayscale2 = mmcv.imread(self.gray_img_path) + assert img_cv2_grayscale2.shape == (300, 400, 3) + img_cv2_unchanged = mmcv.imread(self.gray_img_path, 'unchanged') + assert img_cv2_unchanged.shape == (300, 400) + img_cv2_unchanged = mmcv.imread(img_cv2_unchanged) + assert_array_equal(img_cv2_unchanged, mmcv.imread(img_cv2_unchanged)) + + img_cv2_color_bgr = mmcv.imread(self.img_path_obj) + assert img_cv2_color_bgr.shape == (300, 400, 3) + img_cv2_color_rgb = mmcv.imread(self.img_path_obj, channel_order='rgb') + assert img_cv2_color_rgb.shape == (300, 400, 3) + assert_array_equal(img_cv2_color_rgb[:, :, ::-1], img_cv2_color_bgr) + img_cv2_grayscale1 = mmcv.imread(self.img_path_obj, 'grayscale') + assert img_cv2_grayscale1.shape == (300, 400) + img_cv2_grayscale2 = mmcv.imread(self.gray_img_path_obj) + assert img_cv2_grayscale2.shape == (300, 400, 3) + img_cv2_unchanged = mmcv.imread(self.gray_img_path_obj, 'unchanged') + assert img_cv2_unchanged.shape == (300, 400) + with pytest.raises(TypeError): + mmcv.imread(1) + + # PetrelBackend + img_cv2_color_bgr = mmcv.imread(self.img_path) + with patch.object( + PetrelBackend, 'get', + return_value=img_cv2_color_bgr) as mock_method: + img_cv2_color_bgr_petrel = mmcv.imread(self.s3_path, backend='cv2') + img_cv2_color_bgr_petrel_with_args = mmcv.imread( + self.s3_path, + backend='cv2', + file_client_args={'backend': 'petrel'}) + mock_method.assert_called() + assert_array_equal(img_cv2_color_bgr_petrel, + img_cv2_color_bgr_petrel_with_args) + + mock_method.reset_mock() + + img_cv2_color_bgr_petrel_with_args = mmcv.imread( + self.s3_path, + backend='cv2', + backend_args={'backend': 'petrel'}) + mock_method.assert_called() + assert_array_equal(img_cv2_color_bgr_petrel, + img_cv2_color_bgr_petrel_with_args) + + # HTTPBackend + img_cv2_color_bgr = mmcv.imread(self.img_path) + with patch.object( + HTTPBackend, 'get', + return_value=img_cv2_color_bgr) as mock_method: + img_cv2_color_bgr_http = mmcv.imread(self.http_path, backend='cv2') + img_cv2_color_bgr_http_with_args = mmcv.imread( + self.http_path, + backend='cv2', + file_client_args={'backend': 'http'}) + mock_method.assert_called() + assert_array_equal(img_cv2_color_bgr_http, + img_cv2_color_bgr_http_with_args) + + mock_method.reset_mock() + + img_cv2_color_bgr_http_with_args = mmcv.imread( + self.http_path, + backend='cv2', + backend_args={'backend': 'http'}) + mock_method.assert_called() + assert_array_equal(img_cv2_color_bgr_http, + img_cv2_color_bgr_http_with_args) + + with pytest.raises(FileNotFoundError): + mmcv.imread('/not/exists/' + self.img_path) + + # test arg backend pillow + img_pil_gray_alpha = mmcv.imread( + self.gray_alpha_img_path, 'grayscale', backend='pillow') + assert img_pil_gray_alpha.shape == (400, 500) + mean = img_pil_gray_alpha[300:, 400:].mean() + assert_allclose(img_pil_gray_alpha[300:, 400:] - mean, 0) + img_pil_gray_alpha = mmcv.imread( + self.gray_alpha_img_path, backend='pillow') + mean = img_pil_gray_alpha[300:, 400:].mean(axis=(0, 1)) + assert_allclose(img_pil_gray_alpha[300:, 400:] - mean, 0) + assert img_pil_gray_alpha.shape == (400, 500, 3) + img_pil_gray_alpha = mmcv.imread( + self.gray_alpha_img_path, 'unchanged', backend='pillow') + assert img_pil_gray_alpha.shape == (400, 500, 2) + img_pil_palette = mmcv.imread( + self.palette_img_path, 'grayscale', backend='pillow') + assert img_pil_palette.shape == (300, 400) + img_pil_palette = mmcv.imread(self.palette_img_path, backend='pillow') + assert img_pil_palette.shape == (300, 400, 3) + img_pil_palette = mmcv.imread( + self.palette_img_path, 'unchanged', backend='pillow') + assert img_pil_palette.shape == (300, 400) + + # backend pillow + mmcv.use_backend('pillow') + img_pil_grayscale1 = mmcv.imread(self.img_path, 'grayscale') + assert img_pil_grayscale1.shape == (300, 400) + img_pil_gray_alpha = mmcv.imread(self.gray_alpha_img_path, 'grayscale') + assert img_pil_gray_alpha.shape == (400, 500) + mean = img_pil_gray_alpha[300:, 400:].mean() + assert_allclose(img_pil_gray_alpha[300:, 400:] - mean, 0) + img_pil_gray_alpha = mmcv.imread(self.gray_alpha_img_path) + mean = img_pil_gray_alpha[300:, 400:].mean(axis=(0, 1)) + assert_allclose(img_pil_gray_alpha[300:, 400:] - mean, 0) + assert img_pil_gray_alpha.shape == (400, 500, 3) + img_pil_gray_alpha = mmcv.imread(self.gray_alpha_img_path, 'unchanged') + assert img_pil_gray_alpha.shape == (400, 500, 2) + img_pil_palette = mmcv.imread(self.palette_img_path, 'grayscale') + assert img_pil_palette.shape == (300, 400) + img_pil_palette = mmcv.imread(self.palette_img_path) + assert img_pil_palette.shape == (300, 400, 3) + img_pil_palette = mmcv.imread(self.palette_img_path, 'unchanged') + assert img_pil_palette.shape == (300, 400) + img_pil_grayscale2 = mmcv.imread(self.gray_img_path) + assert img_pil_grayscale2.shape == (300, 400, 3) + img_pil_unchanged = mmcv.imread(self.gray_img_path, 'unchanged') + assert img_pil_unchanged.shape == (300, 400) + img_pil_unchanged = mmcv.imread(img_pil_unchanged) + assert_array_equal(img_pil_unchanged, mmcv.imread(img_pil_unchanged)) + + img_pil_color_bgr = mmcv.imread(self.img_path_obj) + assert img_pil_color_bgr.shape == (300, 400, 3) + img_pil_color_rgb = mmcv.imread(self.img_path_obj, channel_order='rgb') + assert img_pil_color_rgb.shape == (300, 400, 3) + assert (img_pil_color_rgb == img_cv2_color_rgb).sum() / float( + img_cv2_color_rgb.size) > 0.5 + assert_array_equal(img_pil_color_rgb[:, :, ::-1], img_pil_color_bgr) + img_pil_grayscale1 = mmcv.imread(self.img_path_obj, 'grayscale') + assert img_pil_grayscale1.shape == (300, 400) + img_pil_grayscale2 = mmcv.imread(self.gray_img_path_obj) + assert img_pil_grayscale2.shape == (300, 400, 3) + img_pil_unchanged = mmcv.imread(self.gray_img_path_obj, 'unchanged') + assert img_pil_unchanged.shape == (300, 400) + with pytest.raises(TypeError): + mmcv.imread(1) + + # backend turbojpeg + mmcv.use_backend('turbojpeg') + + img_turbojpeg_color_bgr = mmcv.imread(self.img_path) + assert img_turbojpeg_color_bgr.shape == (300, 400, 3) + assert_array_equal(img_turbojpeg_color_bgr, img_cv2_color_bgr) + + img_turbojpeg_color_rgb = mmcv.imread( + self.img_path, channel_order='rgb') + assert img_turbojpeg_color_rgb.shape == (300, 400, 3) + assert_array_equal(img_turbojpeg_color_rgb, img_cv2_color_rgb) + + with pytest.raises(ValueError): + mmcv.imread(self.img_path, channel_order='unsupport_order') + + img_turbojpeg_grayscale1 = mmcv.imread(self.img_path, flag='grayscale') + assert img_turbojpeg_grayscale1.shape == (300, 400) + assert_array_equal(img_turbojpeg_grayscale1, img_cv2_grayscale1) + + img_turbojpeg_grayscale2 = mmcv.imread(self.gray_img_path) + assert img_turbojpeg_grayscale2.shape == (300, 400, 3) + assert_array_equal(img_turbojpeg_grayscale2, img_cv2_grayscale2) + + img_turbojpeg_grayscale2 = mmcv.imread(img_turbojpeg_grayscale2) + assert_array_equal(img_turbojpeg_grayscale2, + mmcv.imread(img_turbojpeg_grayscale2)) + + with pytest.raises(ValueError): + mmcv.imread(self.gray_img_path, 'unchanged') + + with pytest.raises(TypeError): + mmcv.imread(1) + + with pytest.raises(AssertionError): + mmcv.use_backend('unsupport_backend') + + with pytest.raises(ValueError): + mmcv.imread(self.img_path, 'unsupported_backend') + + # backend tifffile, multi channel tiff file(> 4 channels). + mmcv.use_backend('tifffile') + img_tifffile = mmcv.imread(self.tiff_path) + assert img_tifffile.shape == (200, 150, 5) + + mmcv.use_backend('cv2') + + # consistent exif behaviour + img_cv2_exif = mmcv.imread(self.exif_img_path) + img_pil_exif = mmcv.imread(self.exif_img_path, backend='pillow') + assert img_cv2_exif.shape == (400, 300, 3) + assert img_pil_exif.shape == (400, 300, 3) + img_cv2_exif_unchanged = mmcv.imread( + self.exif_img_path, flag='unchanged') + img_pil_exif_unchanged = mmcv.imread( + self.exif_img_path, backend='pillow', flag='unchanged') + assert img_cv2_exif_unchanged.shape == (300, 400, 3) + assert img_pil_exif_unchanged.shape == (300, 400, 3) + img_cv2_color_ignore_exif = mmcv.imread( + self.exif_img_path, flag='color_ignore_orientation') + img_pil_color_ignore_exif = mmcv.imread( + self.exif_img_path, + backend='pillow', + flag='color_ignore_orientation') + assert img_cv2_color_ignore_exif.shape == (300, 400, 3) + assert img_pil_color_ignore_exif.shape == (300, 400, 3) + img_cv2_grayscale_ignore_exif = mmcv.imread( + self.exif_img_path, flag='grayscale_ignore_orientation') + img_pil_grayscale_ignore_exif = mmcv.imread( + self.exif_img_path, + backend='pillow', + flag='grayscale_ignore_orientation') + assert img_cv2_grayscale_ignore_exif.shape == (300, 400) + assert img_pil_grayscale_ignore_exif.shape == (300, 400) + + def test_imfrombytes(self): + # backend cv2, channel order: bgr + mmcv.use_backend('cv2') + with open(self.img_path, 'rb') as f: + img_bytes = f.read() + img_cv2 = mmcv.imfrombytes(img_bytes) + assert img_cv2.shape == (300, 400, 3) + + # backend cv2, channel order: rgb + mmcv.use_backend('cv2') + with open(self.img_path, 'rb') as f: + img_bytes = f.read() + img_rgb_cv2 = mmcv.imfrombytes(img_bytes, channel_order='rgb') + assert img_rgb_cv2.shape == (300, 400, 3) + assert_array_equal(img_rgb_cv2, img_cv2[:, :, ::-1]) + + # backend cv2, grayscale, decode as 3 channels + with open(self.gray_img_path, 'rb') as f: + img_bytes = f.read() + gray_img_rgb_cv2 = mmcv.imfrombytes(img_bytes) + assert gray_img_rgb_cv2.shape == (300, 400, 3) + + # backend cv2, grayscale + with open(self.gray_img_path, 'rb') as f: + img_bytes = f.read() + gray_img_cv2 = mmcv.imfrombytes(img_bytes, flag='grayscale') + assert gray_img_cv2.shape == (300, 400) + + # backend cv2, grayscale dim3 + with open(self.gray_img_dim3_path, 'rb') as f: + img_bytes = f.read() + gray_img_dim3_cv2 = mmcv.imfrombytes(img_bytes, flag='grayscale') + assert gray_img_dim3_cv2.shape == (300, 400) + + # arg backend pillow, channel order: bgr + with open(self.img_path, 'rb') as f: + img_bytes = f.read() + img_pillow = mmcv.imfrombytes(img_bytes, backend='pillow') + assert img_pillow.shape == (300, 400, 3) + # Pillow and opencv decoding may not be the same + assert (img_cv2 == img_pillow).sum() / float(img_cv2.size) > 0.5 + + # backend pillow, channel order: bgr + mmcv.use_backend('pillow') + with open(self.img_path, 'rb') as f: + img_bytes = f.read() + img_pillow = mmcv.imfrombytes(img_bytes) + assert img_pillow.shape == (300, 400, 3) + # Pillow and opencv decoding may not be the same + assert (img_cv2 == img_pillow).sum() / float(img_cv2.size) > 0.5 + + # backend turbojpeg, channel order: bgr + mmcv.use_backend('turbojpeg') + with open(self.img_path, 'rb') as f: + img_bytes = f.read() + img_turbojpeg = mmcv.imfrombytes(img_bytes) + assert img_turbojpeg.shape == (300, 400, 3) + assert_array_equal(img_cv2, img_turbojpeg) + + # backend turbojpeg, channel order: rgb + with open(self.img_path, 'rb') as f: + img_bytes = f.read() + img_rgb_turbojpeg = mmcv.imfrombytes(img_bytes, channel_order='rgb') + assert img_rgb_turbojpeg.shape == (300, 400, 3) + assert_array_equal(img_rgb_turbojpeg, img_cv2[:, :, ::-1]) + + # backend turbojpeg, grayscale, decode as 3 channels + with open(self.gray_img_path, 'rb') as f: + img_bytes = f.read() + gray_img_turbojpeg = mmcv.imfrombytes(img_bytes) + assert gray_img_turbojpeg.shape == (300, 400, 3) + assert_array_equal(gray_img_rgb_cv2, gray_img_turbojpeg) + + # backend turbojpeg, grayscale + with open(self.gray_img_path, 'rb') as f: + img_bytes = f.read() + gray_img_turbojpeg = mmcv.imfrombytes(img_bytes, flag='grayscale') + assert gray_img_turbojpeg.shape == (300, 400) + assert_array_equal(gray_img_cv2, gray_img_turbojpeg) + + # backend turbojpeg, grayscale dim3 + with open(self.gray_img_dim3_path, 'rb') as f: + img_bytes = f.read() + gray_img_dim3_turbojpeg = mmcv.imfrombytes(img_bytes, flag='grayscale') + assert gray_img_dim3_turbojpeg.shape == (300, 400) + assert_array_equal(gray_img_dim3_cv2, gray_img_dim3_turbojpeg) + + mmcv.use_backend('cv2') + + with pytest.raises(ValueError): + with open(self.img_path, 'rb') as f: + img_bytes = f.read() + mmcv.imfrombytes(img_bytes, backend='unsupported_backend') + + def test_imwrite(self): + img = mmcv.imread(self.img_path) + out_file = osp.join(tempfile.gettempdir(), 'mmcv_test.jpg') + + # file_client_args and backend_args can not be both set + with pytest.raises( + ValueError, + match='"file_client_args" and "backend_args" cannot be set'): + mmcv.imwrite( + img, + out_file, + file_client_args={'backend': 'disk'}, + backend_args={'backend': 'disk'}) + + mmcv.imwrite(img, out_file) + rewrite_img = mmcv.imread(out_file) + os.remove(out_file) + self.assert_img_equal(img, rewrite_img) + + # test petrel client + with patch.object( + PetrelBackend, 'put', return_value=None) as mock_method: + ret = mmcv.imwrite(img, self.s3_path) + ret_with_args = mmcv.imwrite( + img, self.s3_path, file_client_args={'backend': 'petrel'}) + assert ret + assert ret_with_args + mock_method.assert_called() + + mock_method.reset_mock() + + ret_with_args = mmcv.imwrite( + img, self.s3_path, backend_args={'backend': 'petrel'}) + assert ret_with_args + mock_method.assert_called() + + with pytest.raises(cv2.error): + mmcv.imwrite(img, 'error_file.jppg') + + @patch('mmcv.image.io.TurboJPEG', None) + def test_no_turbojpeg(self): + with pytest.raises(ImportError): + mmcv.use_backend('turbojpeg') + + mmcv.use_backend('cv2') + + @patch('mmcv.image.io.Image', None) + def test_no_pillow(self): + with pytest.raises(ImportError): + mmcv.use_backend('pillow') + + mmcv.use_backend('cv2') diff --git a/cv/distiller/CWD/mmcv/tests/test_image/test_photometric.py b/cv/distiller/CWD/mmcv/tests/test_image/test_photometric.py new file mode 100644 index 000000000..2288a5ef6 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_image/test_photometric.py @@ -0,0 +1,426 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os.path as osp + +import cv2 +import numpy as np +import pytest +from numpy.testing import assert_array_equal + +import mmcv + + +class TestPhotometric: + + @classmethod + def setup_class(cls): + # the test img resolution is 400x300 + cls.img_path = osp.join(osp.dirname(__file__), '../data/color.jpg') + cls.img = cv2.imread(cls.img_path) + cls.mean = np.array([123.675, 116.28, 103.53], dtype=np.float32) + cls.std = np.array([58.395, 57.12, 57.375], dtype=np.float32) + + def test_imnormalize(self): + rgb_img = self.img[:, :, ::-1] + baseline = (rgb_img - self.mean) / self.std + img = mmcv.imnormalize(self.img, self.mean, self.std) + assert np.allclose(img, baseline) + assert id(img) != id(self.img) + img = mmcv.imnormalize(rgb_img, self.mean, self.std, to_rgb=False) + assert np.allclose(img, baseline) + assert id(img) != id(rgb_img) + + def test_imnormalize_(self): + img_for_normalize = np.float32(self.img) + rgb_img_for_normalize = np.float32(self.img[:, :, ::-1]) + baseline = (rgb_img_for_normalize - self.mean) / self.std + img = mmcv.imnormalize_(img_for_normalize, self.mean, self.std) + assert np.allclose(img_for_normalize, baseline) + assert id(img) == id(img_for_normalize) + img = mmcv.imnormalize_( + rgb_img_for_normalize, self.mean, self.std, to_rgb=False) + assert np.allclose(img, baseline) + assert id(img) == id(rgb_img_for_normalize) + + def test_imdenormalize(self): + norm_img = (self.img[:, :, ::-1] - self.mean) / self.std + rgb_baseline = (norm_img * self.std + self.mean) + bgr_baseline = rgb_baseline[:, :, ::-1] + img = mmcv.imdenormalize(norm_img, self.mean, self.std) + assert np.allclose(img, bgr_baseline) + img = mmcv.imdenormalize(norm_img, self.mean, self.std, to_bgr=False) + assert np.allclose(img, rgb_baseline) + + def test_iminvert(self): + img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]], + dtype=np.uint8) + img_r = np.array([[255, 127, 0], [254, 128, 1], [253, 126, 2]], + dtype=np.uint8) + assert_array_equal(mmcv.iminvert(img), img_r) + + def test_solarize(self): + img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]], + dtype=np.uint8) + img_r = np.array([[0, 127, 0], [1, 127, 1], [2, 126, 2]], + dtype=np.uint8) + assert_array_equal(mmcv.solarize(img), img_r) + img_r = np.array([[0, 127, 0], [1, 128, 1], [2, 126, 2]], + dtype=np.uint8) + assert_array_equal(mmcv.solarize(img, 100), img_r) + + def test_posterize(self): + img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]], + dtype=np.uint8) + img_r = np.array([[0, 128, 128], [0, 0, 128], [0, 128, 128]], + dtype=np.uint8) + assert_array_equal(mmcv.posterize(img, 1), img_r) + img_r = np.array([[0, 128, 224], [0, 96, 224], [0, 128, 224]], + dtype=np.uint8) + assert_array_equal(mmcv.posterize(img, 3), img_r) + + def test_adjust_color(self, nb_rand_test=100): + img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]], + dtype=np.uint8) + img = np.stack([img, img, img], axis=-1) + assert_array_equal(mmcv.adjust_color(img), img) + img_gray = mmcv.bgr2gray(img) + img_r = np.stack([img_gray, img_gray, img_gray], axis=-1) + assert_array_equal(mmcv.adjust_color(img, 0), img_r) + assert_array_equal(mmcv.adjust_color(img, 0, 1), img_r) + assert_array_equal( + mmcv.adjust_color(img, 0.5, 0.5), + np.round(np.clip((img * 0.5 + img_r * 0.5), 0, + 255)).astype(img.dtype)) + assert_array_equal( + mmcv.adjust_color(img, 1, 1.5), + np.round(np.clip(img * 1 + img_r * 1.5, 0, 255)).astype(img.dtype)) + assert_array_equal( + mmcv.adjust_color(img, 0.8, -0.6, gamma=2), + np.round(np.clip(img * 0.8 - 0.6 * img_r + 2, 0, + 255)).astype(img.dtype)) + assert_array_equal( + mmcv.adjust_color(img, 0.8, -0.6, gamma=-0.6), + np.round(np.clip(img * 0.8 - 0.6 * img_r - 0.6, 0, + 255)).astype(img.dtype)) + + # test float type of image + img = img.astype(np.float32) + assert_array_equal( + np.round(mmcv.adjust_color(img, 0.8, -0.6, gamma=-0.6)), + np.round(np.clip(img * 0.8 - 0.6 * img_r - 0.6, 0, 255))) + + # test equalize with randomly sampled image. + for _ in range(nb_rand_test): + img = np.clip(np.random.normal(0, 1, (256, 256, 3)) * 260, 0, + 255).astype(np.uint8) + factor = np.random.uniform() + cv2_img = mmcv.adjust_color(img, alpha=factor) + pil_img = mmcv.adjust_color(img, alpha=factor, backend='pillow') + np.testing.assert_allclose(cv2_img, pil_img, rtol=0, atol=2) + + # the input type must be uint8 for pillow backend + with pytest.raises(AssertionError): + mmcv.adjust_color(img.astype(np.float32), backend='pillow') + + # backend must be 'cv2' or 'pillow' + with pytest.raises(ValueError): + mmcv.adjust_color(img.astype(np.uint8), backend='not support') + + def test_imequalize(self, nb_rand_test=100): + + def _imequalize(img): + # equalize the image using PIL.ImageOps.equalize + from PIL import Image, ImageOps + img = Image.fromarray(img) + equalized_img = np.asarray(ImageOps.equalize(img)) + return equalized_img + + img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]], + dtype=np.uint8) + img = np.stack([img, img, img], axis=-1) + equalized_img = mmcv.imequalize(img) + assert_array_equal(equalized_img, _imequalize(img)) + + # test equalize with case step=0 + img = np.array([[0, 0, 0], [120, 120, 120], [255, 255, 255]], + dtype=np.uint8) + img = np.stack([img, img, img], axis=-1) + assert_array_equal(mmcv.imequalize(img), img) + + # test equalize with randomly sampled image. + for _ in range(nb_rand_test): + img = np.clip(np.random.normal(0, 1, (256, 256, 3)) * 260, 0, + 255).astype(np.uint8) + equalized_img = mmcv.imequalize(img) + assert_array_equal(equalized_img, _imequalize(img)) + + def test_adjust_brightness(self, nb_rand_test=100): + + img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]], + dtype=np.uint8) + img = np.stack([img, img, img], axis=-1) + # test case with factor 1.0 + assert_array_equal(mmcv.adjust_brightness(img, 1.), img) + # test case with factor 0.0 + assert_array_equal(mmcv.adjust_brightness(img, 0.), np.zeros_like(img)) + # test adjust_brightness with randomly sampled images and factors. + for _ in range(nb_rand_test): + img = np.clip( + np.random.uniform(0, 1, (1000, 1200, 3)) * 260, 0, + 255).astype(np.uint8) + factor = np.random.uniform() + np.random.choice([0, 1]) + np.testing.assert_allclose( + mmcv.adjust_brightness(img, factor).astype(np.int32), + mmcv.adjust_brightness(img, factor, + backend='pillow').astype(np.int32), + rtol=0, + atol=1) + + # the input type must be uint8 for pillow backend + with pytest.raises(AssertionError): + mmcv.adjust_brightness(img.astype(np.float32), backend='pillow') + + # backend must be 'cv2' or 'pillow' + with pytest.raises(ValueError): + mmcv.adjust_brightness(img.astype(np.uint8), backend='not support') + + def test_adjust_contrast(self, nb_rand_test=100): + + img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]], + dtype=np.uint8) + img = np.stack([img, img, img], axis=-1) + # test case with factor 1.0 + assert_array_equal(mmcv.adjust_contrast(img, 1.), img) + # test case with factor 0.0 + assert_array_equal( + mmcv.adjust_contrast(img, 0.), + mmcv.adjust_contrast(img, 0., backend='pillow')) + # test adjust_contrast with randomly sampled images and factors. + for _ in range(nb_rand_test): + img = np.clip( + np.random.uniform(0, 1, (1200, 1000, 3)) * 260, 0, + 255).astype(np.uint8) + factor = np.random.uniform() + np.random.choice([0, 1]) + # Note the gap (less_equal 1) between PIL.ImageEnhance.Contrast + # and mmcv.adjust_contrast comes from the gap that converts from + # a color image to gray image using mmcv or PIL. + np.testing.assert_allclose( + mmcv.adjust_contrast(img, factor).astype(np.int32), + mmcv.adjust_contrast(img, factor, + backend='pillow').astype(np.int32), + rtol=0, + atol=1) + + # the input type must be uint8 pillow backend + with pytest.raises(AssertionError): + mmcv.adjust_contrast(img.astype(np.float32), backend='pillow') + + # backend must be 'cv2' or 'pillow' + with pytest.raises(ValueError): + mmcv.adjust_contrast(img.astype(np.uint8), backend='not support') + + def test_auto_contrast(self, nb_rand_test=100): + + def _auto_contrast(img, cutoff=0): + from PIL import Image + from PIL.ImageOps import autocontrast + + # Image.fromarray defaultly supports RGB, not BGR. + # convert from BGR to RGB + img = Image.fromarray(img[..., ::-1], mode='RGB') + contrasted_img = autocontrast(img, cutoff) + # convert from RGB to BGR + return np.asarray(contrasted_img)[..., ::-1] + + img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]], + dtype=np.uint8) + img = np.stack([img, img, img], axis=-1) + + # test case without cut-off + assert_array_equal(mmcv.auto_contrast(img), _auto_contrast(img)) + # test case with cut-off as int + assert_array_equal( + mmcv.auto_contrast(img, 10), _auto_contrast(img, 10)) + # test case with cut-off as float + assert_array_equal( + mmcv.auto_contrast(img, 12.5), _auto_contrast(img, 12.5)) + # test case with cut-off as tuple + assert_array_equal( + mmcv.auto_contrast(img, (10, 10)), _auto_contrast(img, 10)) + # test case with cut-off with sum over 100 + assert_array_equal( + mmcv.auto_contrast(img, 60), _auto_contrast(img, 60)) + + # test auto_contrast with randomly sampled images and factors. + for _ in range(nb_rand_test): + img = np.clip( + np.random.uniform(0, 1, (1200, 1000, 3)) * 260, 0, + 255).astype(np.uint8) + # cut-offs are not set as tuple since in `build.yml`, pillow 6.2.2 + # is installed, which does not support setting low cut-off and high + # cut-off differently. + # With pillow above 8.0.0, cutoff can be set as tuple + cutoff = np.random.rand() * 100 + assert_array_equal( + mmcv.auto_contrast(img, cutoff), _auto_contrast(img, cutoff)) + + def test_adjust_sharpness(self, nb_rand_test=100): + + def _adjust_sharpness(img, factor): + # adjust the sharpness of image using + # PIL.ImageEnhance.Sharpness + from PIL import Image + from PIL.ImageEnhance import Sharpness + img = Image.fromarray(img) + sharpened_img = Sharpness(img).enhance(factor) + return np.asarray(sharpened_img) + + img = np.array([[0, 128, 255], [1, 127, 254], [2, 129, 253]], + dtype=np.uint8) + img = np.stack([img, img, img], axis=-1) + + # test case with invalid type of kernel + with pytest.raises(AssertionError): + mmcv.adjust_sharpness(img, 1., kernel=1.) + # test case with invalid shape of kernel + kernel = np.ones((3, 3, 3)) + with pytest.raises(AssertionError): + mmcv.adjust_sharpness(img, 1., kernel=kernel) + # test case with all-zero kernel, factor 0.0 + kernel = np.zeros((3, 3)) + assert_array_equal( + mmcv.adjust_sharpness(img, 0., kernel=kernel), np.zeros_like(img)) + + # test case with factor 1.0 + assert_array_equal(mmcv.adjust_sharpness(img, 1.), img) + # test adjust_sharpness with randomly sampled images and factors. + for _ in range(nb_rand_test): + img = np.clip( + np.random.uniform(0, 1, (1000, 1200, 3)) * 260, 0, + 255).astype(np.uint8) + factor = np.random.uniform() + # Note the gap between PIL.ImageEnhance.Sharpness and + # mmcv.adjust_sharpness mainly comes from the difference ways of + # handling img edges when applying filters + np.testing.assert_allclose( + mmcv.adjust_sharpness(img, factor).astype(np.int32)[1:-1, + 1:-1], + _adjust_sharpness(img, factor).astype(np.int32)[1:-1, 1:-1], + rtol=0, + atol=1) + + def test_adjust_lighting(self): + img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8) + img = np.stack([img, img, img], axis=-1) + + # eigval and eigvec must be np.ndarray + with pytest.raises(AssertionError): + mmcv.adjust_lighting(img, 1, np.ones((3, 1))) + with pytest.raises(AssertionError): + mmcv.adjust_lighting(img, np.array([1]), (1, 1, 1)) + # we must have the same number of eigval and eigvec + with pytest.raises(AssertionError): + mmcv.adjust_lighting(img, np.array([1]), np.eye(2)) + with pytest.raises(AssertionError): + mmcv.adjust_lighting(img, np.array([1]), np.array([1])) + + img_adjusted = mmcv.adjust_lighting( + img, + np.random.normal(0, 1, 2), + np.random.normal(0, 1, (3, 2)), + alphastd=0.) + assert_array_equal(img_adjusted, img) + + def test_lut_transform(self): + lut_table = np.array(list(range(256))) + + # test assertion image values should between 0 and 255. + with pytest.raises(AssertionError): + mmcv.lut_transform(np.array([256]), lut_table) + with pytest.raises(AssertionError): + mmcv.lut_transform(np.array([-1]), lut_table) + + # test assertion lut_table should be ndarray with shape (256, ) + with pytest.raises(AssertionError): + mmcv.lut_transform(np.array([0]), list(range(256))) + with pytest.raises(AssertionError): + mmcv.lut_transform(np.array([1]), np.array(list(range(257)))) + + img = mmcv.lut_transform(self.img, lut_table) + baseline = cv2.LUT(self.img, lut_table) + assert np.allclose(img, baseline) + + input_img = np.array( + [[[0, 128, 255], [255, 128, 0]], [[0, 128, 255], [255, 128, 0]]], + dtype=float) + img = mmcv.lut_transform(input_img, lut_table) + baseline = cv2.LUT(np.array(input_img, dtype=np.uint8), lut_table) + assert np.allclose(img, baseline) + + input_img = np.random.randint(0, 256, size=(7, 8, 9, 10, 11)) + img = mmcv.lut_transform(input_img, lut_table) + baseline = cv2.LUT(np.array(input_img, dtype=np.uint8), lut_table) + assert np.allclose(img, baseline) + + def test_clahe(self): + + def _clahe(img, clip_limit=40.0, tile_grid_size=(8, 8)): + clahe = cv2.createCLAHE(clip_limit, tile_grid_size) + return clahe.apply(np.array(img, dtype=np.uint8)) + + # test assertion image should have the right shape + with pytest.raises(AssertionError): + mmcv.clahe(self.img) + + # test assertion tile_grid_size should be a tuple with 2 integers + with pytest.raises(AssertionError): + mmcv.clahe(self.img[:, :, 0], tile_grid_size=(8.0, 8.0)) + with pytest.raises(AssertionError): + mmcv.clahe(self.img[:, :, 0], tile_grid_size=(8, 8, 8)) + with pytest.raises(AssertionError): + mmcv.clahe(self.img[:, :, 0], tile_grid_size=[8, 8]) + + # test with different channels + for i in range(self.img.shape[-1]): + img = mmcv.clahe(self.img[:, :, i]) + img_std = _clahe(self.img[:, :, i]) + assert np.allclose(img, img_std) + assert id(img) != id(self.img[:, :, i]) + assert id(img_std) != id(self.img[:, :, i]) + + # test case with clip_limit=1.2 + for i in range(self.img.shape[-1]): + img = mmcv.clahe(self.img[:, :, i], 1.2) + img_std = _clahe(self.img[:, :, i], 1.2) + assert np.allclose(img, img_std) + assert id(img) != id(self.img[:, :, i]) + assert id(img_std) != id(self.img[:, :, i]) + + def test_adjust_hue(self): + # test case with img is not ndarray + from PIL import Image + pil_img = Image.fromarray(self.img) + + with pytest.raises(TypeError): + mmcv.adjust_hue(pil_img, hue_factor=0.0) + + # test case with hue_factor > 0.5 or hue_factor < -0.5 + with pytest.raises(ValueError): + mmcv.adjust_hue(self.img, hue_factor=-0.6) + with pytest.raises(ValueError): + mmcv.adjust_hue(self.img, hue_factor=0.6) + + for i in np.arange(-0.5, 0.5, 0.2): + pil_res = mmcv.adjust_hue(self.img, hue_factor=i, backend='pillow') + pil_res = np.array(pil_res) + cv2_res = mmcv.adjust_hue(self.img, hue_factor=i) + assert np.allclose(pil_res, cv2_res, atol=10.0) + + # test pillow backend + with pytest.raises(AssertionError): + mmcv.adjust_hue( + self.img.astype(np.float32), hue_factor=0, backend='pillow') + + # backend must be 'cv2' or 'pillow' + with pytest.raises(ValueError): + mmcv.adjust_hue( + self.img.astype(np.uint8), hue_factor=0, backend='not support') diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/output.pkl b/cv/distiller/CWD/mmcv/tests/test_ops/output.pkl new file mode 100644 index 0000000000000000000000000000000000000000..bcb7b2dd606930522b102d3a59fef70d6f3eb885 GIT binary patch literal 2168 zcmd^BO=}ZT6n)9$%dxbj6hQ)YAwmUB(`ibn3r9kU!c!bm#NZ}OCqojPB)-WcD+R$t zai<$sA{FVzO@Bc%E<(Yj3zx2Rp$oyKf~fB%IU$qUty%QK;pDyC`#w$%@5bOtgt0_| z9g0~t$4u9%RNMAa$@I+B{d-O>JI(F};!)W08Zs+YYezQ7e8+7|IAmep_^+w!W7dQ-jWmTcE9ZB#8!6^ZkCal#X7 zUYtxBJf8SCwVT|Ns}hVOub*Uz!1b4cC(C6cJtYom^EzCK=7#b5pV`6Ab42_AQF)=hIhQ`FlZC`kb z7@i`Ar-c#0UFBA$q;{==q<+~Z%El+MR(UwZHle!Z>lL>VI- z{ov2Av%?3!ZM#j`NOIXTW9=@``)IJD(hl!mmT!mUFHJCbh-lbTN88OTeG!Q94m(~w zdiG?X@{b&iR*yBP@r6c@I1^atyKJ#oXmD|Z$6^--NejxwVLCaP0^IEnS)SUv3|ZIv VbZYQ_BGj9UQV*9k3Zwjf?q5M}yi@=H literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_active_rotated_filter.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_active_rotated_filter.py new file mode 100644 index 000000000..30ea59c5c --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_active_rotated_filter.py @@ -0,0 +1,258 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.ops import active_rotated_filter + +np_feature = np.array([[[[[-1.4934e-01, 1.1341e+00, -1.6241e-01], + [-1.0986e+00, -1.1463e+00, -1.3176e+00], + [1.4808e+00, 7.6572e-01, -1.4548e+00]]]], + [[[[1.9370e+00, 6.2799e-01, 2.5834e-02], + [-1.4242e+00, 7.6566e-01, 1.0015e+00], + [9.8669e-01, 4.1356e-01, 6.1068e-01]]]], + [[[[1.4565e+00, 1.4960e+00, 2.4339e-01], + [-2.2484e-01, 7.5942e-01, -8.1184e-01], + [-1.7077e+00, 1.0658e+00, 3.8311e-01]]]], + [[[[8.4734e-01, 1.0904e+00, 2.4356e+00], + [9.5822e-01, 2.2260e-01, -2.4450e-01], + [-1.5078e+00, 7.0902e-02, -1.5921e+00]]]], + [[[[2.1173e+00, -7.3524e-01, 1.8888e+00], + [1.0169e+00, 4.7033e-01, -1.0875e+00], + [-1.0736e+00, -5.2245e-01, -2.8733e-01]]]], + [[[[-5.6433e-01, 1.5835e+00, -1.5826e+00], + [-8.8974e-01, -4.3128e-01, -2.2423e-01], + [1.6552e-03, -1.7292e+00, 2.6639e-01]]]], + [[[[-1.2951e-01, 1.3493e+00, -1.9329e+00], + [5.6248e-01, -5.1189e-01, 1.3614e+00], + [3.3680e-01, -8.7148e-01, 5.0592e-01]]]], + [[[[1.6781e-02, -8.3929e-01, 1.2060e+00], + [-1.0764e+00, 4.7821e-01, 1.5342e+00], + [-4.4542e-01, -1.8606e+00, 3.0827e-01]]]]]) + +np_indices = np.array([[[[1, 2, 3, 6, 9, 8, 7, 4], [2, 3, 6, 9, 8, 7, 4, 1], + [3, 6, 9, 8, 7, 4, 1, 2]], + [[4, 1, 2, 3, 6, 9, 8, 7], [5, 5, 5, 5, 5, 5, 5, 5], + [6, 9, 8, 7, 4, 1, 2, 3]], + [[7, 4, 1, 2, 3, 6, 9, 8], [8, 7, 4, 1, 2, 3, 6, 9], + [9, 8, 7, 4, 1, 2, 3, 6]]]]) + +expected_output = np.array([[[[-1.4934e-01, 1.1341e+00, -1.6241e-01], + [-1.0986e+00, -1.1463e+00, -1.3176e+00], + [1.4808e+00, 7.6572e-01, -1.4548e+00]]], + [[[-1.0986e+00, -1.4934e-01, 1.1341e+00], + [1.4808e+00, -1.1463e+00, -1.6241e-01], + [7.6572e-01, -1.4548e+00, -1.3176e+00]]], + [[[1.4808e+00, -1.0986e+00, -1.4934e-01], + [7.6572e-01, -1.1463e+00, 1.1341e+00], + [-1.4548e+00, -1.3176e+00, -1.6241e-01]]], + [[[7.6572e-01, 1.4808e+00, -1.0986e+00], + [-1.4548e+00, -1.1463e+00, -1.4934e-01], + [-1.3176e+00, -1.6241e-01, 1.1341e+00]]], + [[[-1.4548e+00, 7.6572e-01, 1.4808e+00], + [-1.3176e+00, -1.1463e+00, -1.0986e+00], + [-1.6241e-01, 1.1341e+00, -1.4934e-01]]], + [[[-1.3176e+00, -1.4548e+00, 7.6572e-01], + [-1.6241e-01, -1.1463e+00, 1.4808e+00], + [1.1341e+00, -1.4934e-01, -1.0986e+00]]], + [[[-1.6241e-01, -1.3176e+00, -1.4548e+00], + [1.1341e+00, -1.1463e+00, 7.6572e-01], + [-1.4934e-01, -1.0986e+00, 1.4808e+00]]], + [[[1.1341e+00, -1.6241e-01, -1.3176e+00], + [-1.4934e-01, -1.1463e+00, -1.4548e+00], + [-1.0986e+00, 1.4808e+00, 7.6572e-01]]], + [[[1.9370e+00, 6.2799e-01, 2.5834e-02], + [-1.4242e+00, 7.6566e-01, 1.0015e+00], + [9.8669e-01, 4.1356e-01, 6.1068e-01]]], + [[[-1.4242e+00, 1.9370e+00, 6.2799e-01], + [9.8669e-01, 7.6566e-01, 2.5834e-02], + [4.1356e-01, 6.1068e-01, 1.0015e+00]]], + [[[9.8669e-01, -1.4242e+00, 1.9370e+00], + [4.1356e-01, 7.6566e-01, 6.2799e-01], + [6.1068e-01, 1.0015e+00, 2.5834e-02]]], + [[[4.1356e-01, 9.8669e-01, -1.4242e+00], + [6.1068e-01, 7.6566e-01, 1.9370e+00], + [1.0015e+00, 2.5834e-02, 6.2799e-01]]], + [[[6.1068e-01, 4.1356e-01, 9.8669e-01], + [1.0015e+00, 7.6566e-01, -1.4242e+00], + [2.5834e-02, 6.2799e-01, 1.9370e+00]]], + [[[1.0015e+00, 6.1068e-01, 4.1356e-01], + [2.5834e-02, 7.6566e-01, 9.8669e-01], + [6.2799e-01, 1.9370e+00, -1.4242e+00]]], + [[[2.5834e-02, 1.0015e+00, 6.1068e-01], + [6.2799e-01, 7.6566e-01, 4.1356e-01], + [1.9370e+00, -1.4242e+00, 9.8669e-01]]], + [[[6.2799e-01, 2.5834e-02, 1.0015e+00], + [1.9370e+00, 7.6566e-01, 6.1068e-01], + [-1.4242e+00, 9.8669e-01, 4.1356e-01]]], + [[[1.4565e+00, 1.4960e+00, 2.4339e-01], + [-2.2484e-01, 7.5942e-01, -8.1184e-01], + [-1.7077e+00, 1.0658e+00, 3.8311e-01]]], + [[[-2.2484e-01, 1.4565e+00, 1.4960e+00], + [-1.7077e+00, 7.5942e-01, 2.4339e-01], + [1.0658e+00, 3.8311e-01, -8.1184e-01]]], + [[[-1.7077e+00, -2.2484e-01, 1.4565e+00], + [1.0658e+00, 7.5942e-01, 1.4960e+00], + [3.8311e-01, -8.1184e-01, 2.4339e-01]]], + [[[1.0658e+00, -1.7077e+00, -2.2484e-01], + [3.8311e-01, 7.5942e-01, 1.4565e+00], + [-8.1184e-01, 2.4339e-01, 1.4960e+00]]], + [[[3.8311e-01, 1.0658e+00, -1.7077e+00], + [-8.1184e-01, 7.5942e-01, -2.2484e-01], + [2.4339e-01, 1.4960e+00, 1.4565e+00]]], + [[[-8.1184e-01, 3.8311e-01, 1.0658e+00], + [2.4339e-01, 7.5942e-01, -1.7077e+00], + [1.4960e+00, 1.4565e+00, -2.2484e-01]]], + [[[2.4339e-01, -8.1184e-01, 3.8311e-01], + [1.4960e+00, 7.5942e-01, 1.0658e+00], + [1.4565e+00, -2.2484e-01, -1.7077e+00]]], + [[[1.4960e+00, 2.4339e-01, -8.1184e-01], + [1.4565e+00, 7.5942e-01, 3.8311e-01], + [-2.2484e-01, -1.7077e+00, 1.0658e+00]]], + [[[8.4734e-01, 1.0904e+00, 2.4356e+00], + [9.5822e-01, 2.2260e-01, -2.4450e-01], + [-1.5078e+00, 7.0902e-02, -1.5921e+00]]], + [[[9.5822e-01, 8.4734e-01, 1.0904e+00], + [-1.5078e+00, 2.2260e-01, 2.4356e+00], + [7.0902e-02, -1.5921e+00, -2.4450e-01]]], + [[[-1.5078e+00, 9.5822e-01, 8.4734e-01], + [7.0902e-02, 2.2260e-01, 1.0904e+00], + [-1.5921e+00, -2.4450e-01, 2.4356e+00]]], + [[[7.0902e-02, -1.5078e+00, 9.5822e-01], + [-1.5921e+00, 2.2260e-01, 8.4734e-01], + [-2.4450e-01, 2.4356e+00, 1.0904e+00]]], + [[[-1.5921e+00, 7.0902e-02, -1.5078e+00], + [-2.4450e-01, 2.2260e-01, 9.5822e-01], + [2.4356e+00, 1.0904e+00, 8.4734e-01]]], + [[[-2.4450e-01, -1.5921e+00, 7.0902e-02], + [2.4356e+00, 2.2260e-01, -1.5078e+00], + [1.0904e+00, 8.4734e-01, 9.5822e-01]]], + [[[2.4356e+00, -2.4450e-01, -1.5921e+00], + [1.0904e+00, 2.2260e-01, 7.0902e-02], + [8.4734e-01, 9.5822e-01, -1.5078e+00]]], + [[[1.0904e+00, 2.4356e+00, -2.4450e-01], + [8.4734e-01, 2.2260e-01, -1.5921e+00], + [9.5822e-01, -1.5078e+00, 7.0902e-02]]], + [[[2.1173e+00, -7.3524e-01, 1.8888e+00], + [1.0169e+00, 4.7033e-01, -1.0875e+00], + [-1.0736e+00, -5.2245e-01, -2.8733e-01]]], + [[[1.0169e+00, 2.1173e+00, -7.3524e-01], + [-1.0736e+00, 4.7033e-01, 1.8888e+00], + [-5.2245e-01, -2.8733e-01, -1.0875e+00]]], + [[[-1.0736e+00, 1.0169e+00, 2.1173e+00], + [-5.2245e-01, 4.7033e-01, -7.3524e-01], + [-2.8733e-01, -1.0875e+00, 1.8888e+00]]], + [[[-5.2245e-01, -1.0736e+00, 1.0169e+00], + [-2.8733e-01, 4.7033e-01, 2.1173e+00], + [-1.0875e+00, 1.8888e+00, -7.3524e-01]]], + [[[-2.8733e-01, -5.2245e-01, -1.0736e+00], + [-1.0875e+00, 4.7033e-01, 1.0169e+00], + [1.8888e+00, -7.3524e-01, 2.1173e+00]]], + [[[-1.0875e+00, -2.8733e-01, -5.2245e-01], + [1.8888e+00, 4.7033e-01, -1.0736e+00], + [-7.3524e-01, 2.1173e+00, 1.0169e+00]]], + [[[1.8888e+00, -1.0875e+00, -2.8733e-01], + [-7.3524e-01, 4.7033e-01, -5.2245e-01], + [2.1173e+00, 1.0169e+00, -1.0736e+00]]], + [[[-7.3524e-01, 1.8888e+00, -1.0875e+00], + [2.1173e+00, 4.7033e-01, -2.8733e-01], + [1.0169e+00, -1.0736e+00, -5.2245e-01]]], + [[[-5.6433e-01, 1.5835e+00, -1.5826e+00], + [-8.8974e-01, -4.3128e-01, -2.2423e-01], + [1.6552e-03, -1.7292e+00, 2.6639e-01]]], + [[[-8.8974e-01, -5.6433e-01, 1.5835e+00], + [1.6552e-03, -4.3128e-01, -1.5826e+00], + [-1.7292e+00, 2.6639e-01, -2.2423e-01]]], + [[[1.6552e-03, -8.8974e-01, -5.6433e-01], + [-1.7292e+00, -4.3128e-01, 1.5835e+00], + [2.6639e-01, -2.2423e-01, -1.5826e+00]]], + [[[-1.7292e+00, 1.6552e-03, -8.8974e-01], + [2.6639e-01, -4.3128e-01, -5.6433e-01], + [-2.2423e-01, -1.5826e+00, 1.5835e+00]]], + [[[2.6639e-01, -1.7292e+00, 1.6552e-03], + [-2.2423e-01, -4.3128e-01, -8.8974e-01], + [-1.5826e+00, 1.5835e+00, -5.6433e-01]]], + [[[-2.2423e-01, 2.6639e-01, -1.7292e+00], + [-1.5826e+00, -4.3128e-01, 1.6552e-03], + [1.5835e+00, -5.6433e-01, -8.8974e-01]]], + [[[-1.5826e+00, -2.2423e-01, 2.6639e-01], + [1.5835e+00, -4.3128e-01, -1.7292e+00], + [-5.6433e-01, -8.8974e-01, 1.6552e-03]]], + [[[1.5835e+00, -1.5826e+00, -2.2423e-01], + [-5.6433e-01, -4.3128e-01, 2.6639e-01], + [-8.8974e-01, 1.6552e-03, -1.7292e+00]]], + [[[-1.2951e-01, 1.3493e+00, -1.9329e+00], + [5.6248e-01, -5.1189e-01, 1.3614e+00], + [3.3680e-01, -8.7148e-01, 5.0592e-01]]], + [[[5.6248e-01, -1.2951e-01, 1.3493e+00], + [3.3680e-01, -5.1189e-01, -1.9329e+00], + [-8.7148e-01, 5.0592e-01, 1.3614e+00]]], + [[[3.3680e-01, 5.6248e-01, -1.2951e-01], + [-8.7148e-01, -5.1189e-01, 1.3493e+00], + [5.0592e-01, 1.3614e+00, -1.9329e+00]]], + [[[-8.7148e-01, 3.3680e-01, 5.6248e-01], + [5.0592e-01, -5.1189e-01, -1.2951e-01], + [1.3614e+00, -1.9329e+00, 1.3493e+00]]], + [[[5.0592e-01, -8.7148e-01, 3.3680e-01], + [1.3614e+00, -5.1189e-01, 5.6248e-01], + [-1.9329e+00, 1.3493e+00, -1.2951e-01]]], + [[[1.3614e+00, 5.0592e-01, -8.7148e-01], + [-1.9329e+00, -5.1189e-01, 3.3680e-01], + [1.3493e+00, -1.2951e-01, 5.6248e-01]]], + [[[-1.9329e+00, 1.3614e+00, 5.0592e-01], + [1.3493e+00, -5.1189e-01, -8.7148e-01], + [-1.2951e-01, 5.6248e-01, 3.3680e-01]]], + [[[1.3493e+00, -1.9329e+00, 1.3614e+00], + [-1.2951e-01, -5.1189e-01, 5.0592e-01], + [5.6248e-01, 3.3680e-01, -8.7148e-01]]], + [[[1.6781e-02, -8.3929e-01, 1.2060e+00], + [-1.0764e+00, 4.7821e-01, 1.5342e+00], + [-4.4542e-01, -1.8606e+00, 3.0827e-01]]], + [[[-1.0764e+00, 1.6781e-02, -8.3929e-01], + [-4.4542e-01, 4.7821e-01, 1.2060e+00], + [-1.8606e+00, 3.0827e-01, 1.5342e+00]]], + [[[-4.4542e-01, -1.0764e+00, 1.6781e-02], + [-1.8606e+00, 4.7821e-01, -8.3929e-01], + [3.0827e-01, 1.5342e+00, 1.2060e+00]]], + [[[-1.8606e+00, -4.4542e-01, -1.0764e+00], + [3.0827e-01, 4.7821e-01, 1.6781e-02], + [1.5342e+00, 1.2060e+00, -8.3929e-01]]], + [[[3.0827e-01, -1.8606e+00, -4.4542e-01], + [1.5342e+00, 4.7821e-01, -1.0764e+00], + [1.2060e+00, -8.3929e-01, 1.6781e-02]]], + [[[1.5342e+00, 3.0827e-01, -1.8606e+00], + [1.2060e+00, 4.7821e-01, -4.4542e-01], + [-8.3929e-01, 1.6781e-02, -1.0764e+00]]], + [[[1.2060e+00, 1.5342e+00, 3.0827e-01], + [-8.3929e-01, 4.7821e-01, -1.8606e+00], + [1.6781e-02, -1.0764e+00, -4.4542e-01]]], + [[[-8.3929e-01, 1.2060e+00, 1.5342e+00], + [1.6781e-02, 4.7821e-01, 3.0827e-01], + [-1.0764e+00, -4.4542e-01, -1.8606e+00]]]]) + +expected_grad = np.array([[[[[8., 8., 8.], [8., 8., 8.], [8., 8., 8.]]]], + [[[[8., 8., 8.], [8., 8., 8.], [8., 8., 8.]]]], + [[[[8., 8., 8.], [8., 8., 8.], [8., 8., 8.]]]], + [[[[8., 8., 8.], [8., 8., 8.], [8., 8., 8.]]]], + [[[[8., 8., 8.], [8., 8., 8.], [8., 8., 8.]]]], + [[[[8., 8., 8.], [8., 8., 8.], [8., 8., 8.]]]], + [[[[8., 8., 8.], [8., 8., 8.], [8., 8., 8.]]]], + [[[[8., 8., 8.], [8., 8., 8.], [8., 8., 8.]]]]]) + + +@pytest.mark.parametrize('device', [ + 'cpu', + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support')), +]) +def test_active_rotated_filter(device): + feature = torch.tensor( + np_feature, dtype=torch.float, device=device, requires_grad=True) + indices = torch.tensor(np_indices, dtype=torch.int, device=device) + output = active_rotated_filter(feature, indices) + output.backward(torch.ones_like(output)) + assert np.allclose(output.data.cpu().numpy(), expected_output, atol=1e-3) + assert np.allclose( + feature.grad.data.cpu().numpy(), expected_grad, atol=1e-3) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_assign_score_withk.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_assign_score_withk.py new file mode 100644 index 000000000..f8fc6ae62 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_assign_score_withk.py @@ -0,0 +1,188 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import assign_score_withk + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_paconv_assign_scores(): + scores = torch.tensor([[[[0.06947571, 0.6065746], [0.28462553, 0.8378516], + [0.7595994, 0.97220325], [0.519155, 0.766185]], + [[0.15348864, 0.6051019], [0.21510637, 0.31916398], + [0.00236845, 0.5842595], [0.6783676, 0.5216348]]], + [[[0.23089725, 0.5568468], [0.7405102, 0.06438422], + [0.6887394, 0.22089851], [0.0502342, 0.79228795]], + [[0.44883424, 0.15427643], + [0.13817799, 0.34856772], [0.7989621, 0.33788306], + [0.15699774, 0.7693662]]]]).float().cuda() + scores.requires_grad_() + points = torch.tensor([[[[0.06001121, 0.92963666, 0.5753327, 0.7251477], + [0.53563064, 0.23129565, 0.92366195, 0.44261628]], + [[0.5770022, 0.56625944, 0.23560429, 0.11178821], + [0.7735967, 0.95678777, 0.25468266, 0.02895975]], + [[0.0589869, 0.09017515, 0.5977862, 0.02797985], + [0.603862, 0.35991007, 0.85761684, 0.3096559]], + [[0.22359002, 0.13983732, 0.5544243, 0.68863827], + [0.85646236, 0.75651926, 0.8638947, 0.83600986]], + [[0.45424145, 0.27458847, 0.6456112, 0.47162914], + [0.15773582, 0.47645122, 0.79964715, 0.3323908]], + [[0.8351399, 0.84696376, 0.9431732, 0.29418713], + [0.77168906, 0.6996871, 0.19354361, 0.03392768]], + [[0.30976456, 0.7074133, 0.581795, 0.976677], + [0.69656056, 0.07199162, 0.4708506, 0.29117996]], + [[0.5829035, 0.30201727, 0.76556486, 0.0935446], + [0.88030535, 0.16129416, 0.9242525, 0.49545723]]], + [[[0.50899494, 0.06482804, 0.44939405, 0.37704808], + [0.47028124, 0.11969638, 0.62823206, 0.28560323]], + [[0.40690207, 0.689753, 0.51636654, 0.23040164], + [0.06935787, 0.00488842, 0.22462702, 0.09182382]], + [[0.26611632, 0.00184339, 0.7730655, 0.5228131], + [0.87776035, 0.77895886, 0.2787183, 0.16620636]], + [[0.502574, 0.04039001, 0.5368497, 0.98379374], + [0.40973026, 0.3238272, 0.9733018, 0.13988364]], + [[0.04586202, 0.20983845, 0.20662665, 0.22270602], + [0.60387236, 0.5155574, 0.51237285, 0.6528438]], + [[0.45735973, 0.86821306, 0.61054605, 0.8370336], + [0.45193362, 0.3734138, 0.7825672, 0.5699416]], + [[0.44591594, 0.12447512, 0.09282011, 0.7055254], + [0.25223452, 0.46696228, 0.7051136, 0.892151]], + [[0.49615085, 0.47321403, 0.93138885, 0.7652197], + [0.38766378, 0.30332977, 0.23131835, + 0.02863514]]]]).float().cuda() + points.requires_grad_() + centers = torch.tensor([[[[0.83878064, 0.96658987, 0.8033424, 0.9598312], + [0.45035273, 0.8768925, 0.977736, 0.54547966]], + [[0.01041394, 0.597893, 0.36212963, 0.4410367], + [0.94879234, 0.8372817, 0.21237361, 0.67945415]], + [[0.5096087, 0.26401454, 0.60034937, 0.5417416], + [0.87591463, 0.546456, 0.4096033, 0.16373193]], + [[0.79547447, 0.1482386, 0.12840575, 0.45384115], + [0.5640288, 0.944541, 0.5745328, 0.73229736]], + [[0.93011934, 0.7406011, 0.62621707, 0.8677915], + [0.91563636, 0.3595413, 0.6678378, 0.6085383]], + [[0.22431666, 0.65617776, 0.7483924, 0.6263364], + [0.30968404, 0.78204364, 0.14899081, + 0.09628749]], + [[0.73675203, 0.72104895, 0.4648038, 0.6101647], + [0.7817645, 0.16572917, 0.3311919, 0.43407398]], + [[0.8193154, 0.09559608, 0.05978829, 0.90262103], + [0.4256065, 0.8165596, 0.8206446, 0.6604721]]], + [[[0.7159653, 0.18600845, 0.21433902, 0.3159626], + [0.3921569, 0.33221376, 0.5061177, 0.7961841]], + [[0.95338356, 0.04785997, 0.67185795, 0.6538394], + [0.4729132, 0.33404195, 0.17750603, 0.8445621]], + [[0.6755793, 0.16193843, 0.75943846, 0.92123103], + [0.2781859, 0.03114432, 0.710638, 0.52729136]], + [[0.8376105, 0.10858494, 0.13208169, 0.365772], + [0.5930795, 0.27390373, 0.14036089, 0.170403]], + [[0.3479789, 0.89855295, 0.04844379, 0.9871029], + [0.29781651, 0.0244137, 0.9179047, 0.8081611]], + [[0.12460887, 0.44991326, 0.19382608, 0.35037738], + [0.2773472, 0.4362057, 0.36757517, 0.5993509]], + [[0.29630446, 0.90046406, 0.5417113, 0.13510644], + [0.09623539, 0.04226565, 0.32001644, + 0.44358212]], + [[0.5274848, 0.82096446, 0.9415489, 0.7123748], + [0.7537517, 0.8086482, 0.85345286, + 0.7472754]]]]).float().cuda() + centers.requires_grad_() + knn_idx = torch.tensor([[[6, 7, 4, 6], [2, 4, 2, 4]], + [[7, 1, 3, 2], [6, 0, 2, 6]]]).long().cuda() + aggregate = 'sum' + expected_output = torch.tensor( + [[[[-0.08134781, 0.03877336, -0.8212776, -0.2869547], + [-0.23378491, -0.24112664, -0.1600166, -0.4121864]], + [[-0.05780616, -0.12298299, -0.0370461, -0.07889931], + [-0.13956165, -0.02006848, -0.10940295, -0.0293439]], + [[0.09284145, 0.58250105, 0.5927749, 0.16774094], + [0.27070042, 0.13422406, 0.2617501, 0.23416464]], + [[-0.06121218, -0.09561322, -0.20408826, 0.08079343], + [0.00944228, 0.03874819, 0.08404065, 0.04041629]]], + [[[-0.2110898, -0.13335688, -0.09315082, 0.08512095], + [0.09121774, 0.15976946, 0.23994486, 0.14350912]], + [[-0.36167958, -0.14891288, -0.64470863, -0.0646704], + [-0.28276974, -0.08847666, -0.46904767, 0.20491874]], + [[-0.34877953, -0.35533834, -0.25225785, -0.4638189], + [-0.1420663, 0.09467781, 0.17088932, 0.22580585]], + [[-0.3879708, -0.3991068, 0.05276498, -0.46989647], + [0.32522714, -0.02163534, 0.21604237, 0.4346682]]]]).float() + + # test forward + output = assign_score_withk(scores, points, centers, knn_idx, aggregate) + assert torch.allclose(output.detach().cpu(), expected_output, atol=1e-6) + + # test backward + loss = output.sum() + loss.backward() + expected_scores_grad = torch.tensor([[[[0.04288036, -0.18217683], + [-0.78873926, 0.7485497], + [-0.6866992, 0.05346543], + [0.04288036, -0.18217683]], + [[-1.1407862, 0.13533896], + [-0.06964391, -0.22948086], + [-1.1407862, 0.13533896], + [-0.06964391, -0.22948086]]], + [[[-0.3363995, -2.212181], + [-1.1589496, -2.7724311], + [-0.9387654, -1.3163853], + [-1.4385346, -1.0614843]], + [[-0.5048497, 1.4143617], + [-0.47332114, 0.6017133], + [-0.30974793, 1.1995442], + [-0.5048497, 1.4143617]]]]).float() + expected_points_grad = torch.tensor( + [[[[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0.15585709, 0.15585709, 0.15585709, 0.15585709], + [1.1893613, 1.1893613, 1.1893613, 1.1893613]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[1.6530733, 1.6530733, 1.6530733, 1.6530733], + [1.8130021, 1.8130021, 1.8130021, 1.8130021]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0.58863074, 0.58863074, 0.58863074, 0.58863074], + [1.3727596, 1.3727596, 1.3727596, 1.3727596]], + [[0.28462553, 0.28462553, 0.28462553, 0.28462553], + [0.8378516, 0.8378516, 0.8378516, 0.8378516]]], + [[[0.13817799, 0.13817799, 0.13817799, 0.13817799], + [0.34856772, 0.34856772, 0.34856772, 0.34856772]], + [[0.7405102, 0.7405102, 0.7405102, 0.7405102], + [0.06438422, 0.06438422, 0.06438422, 0.06438422]], + [[0.8491963, 0.8491963, 0.8491963, 0.8491963], + [1.1301711, 1.1301711, 1.1301711, 1.1301711]], + [[0.6887394, 0.6887394, 0.6887394, 0.6887394], + [0.22089851, 0.22089851, 0.22089851, 0.22089851]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0.605832, 0.605832, 0.605832, 0.605832], + [0.92364264, 0.92364264, 0.92364264, 0.92364264]], + [[0.23089725, 0.23089725, 0.23089725, 0.23089725], + [0.5568468, 0.5568468, 0.5568468, 0.5568468]]]]).float() + expected_centers_grad = torch.tensor( + [[[[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[-1.0493311, -1.0493311, -1.0493311, -1.0493311], + [-2.0301602, -2.0301602, -2.0301602, -2.0301602]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[-1.6328557, -1.6328557, -1.6328557, -1.6328557], + [-3.1828144, -3.1828144, -3.1828144, -3.1828144]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]]], + [[[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[0., 0., 0., 0.], [0., 0., 0., 0.]], + [[-1.5429721, -1.5429721, -1.5429721, -1.5429721], + [-1.6100934, -1.6100934, -1.6100934, -1.6100934]], + [[-1.7103812, -1.7103812, -1.7103812, -1.7103812], + [-1.6344175, -1.6344175, -1.6344175, -1.6344175]]]]).float() + assert torch.allclose( + scores.grad.detach().cpu(), expected_scores_grad, atol=1e-6) + assert torch.allclose( + points.grad.detach().cpu(), expected_points_grad, atol=1e-6) + assert torch.allclose( + centers.grad.detach().cpu(), expected_centers_grad, atol=1e-6) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_ball_query.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_ball_query.py new file mode 100644 index 000000000..d3fc7912c --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_ball_query.py @@ -0,0 +1,102 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import ball_query + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_ball_query(): + new_xyz = torch.tensor([[[-0.0740, 1.3147, -1.3625], + [-2.2769, 2.7817, -0.2334], + [-0.4003, 2.4666, -0.5116], + [-0.0740, 1.3147, -1.3625], + [-0.0740, 1.3147, -1.3625]], + [[-2.0289, 2.4952, -0.1708], + [-2.0668, 6.0278, -0.4875], + [0.4066, 1.4211, -0.2947], + [-2.0289, 2.4952, -0.1708], + [-2.0289, 2.4952, -0.1708]]]).cuda() + + xyz = torch.tensor([[[-0.0740, 1.3147, -1.3625], [0.5555, 1.0399, -1.3634], + [-0.4003, 2.4666, + -0.5116], [-0.5251, 2.4379, -0.8466], + [-0.9691, 1.1418, + -1.3733], [-0.2232, 0.9561, -1.3626], + [-2.2769, 2.7817, -0.2334], + [-0.2822, 1.3192, -1.3645], [0.1533, 1.5024, -1.0432], + [0.4917, 1.1529, -1.3496]], + [[-2.0289, 2.4952, + -0.1708], [-0.7188, 0.9956, -0.5096], + [-2.0668, 6.0278, -0.4875], [-1.9304, 3.3092, 0.6610], + [0.0949, 1.4332, 0.3140], [-1.2879, 2.0008, -0.7791], + [-0.7252, 0.9611, -0.6371], [0.4066, 1.4211, -0.2947], + [0.3220, 1.4447, 0.3548], [-0.9744, 2.3856, + -1.2000]]]).cuda() + + idx = ball_query(0, 0.2, 5, xyz, new_xyz) + expected_idx = torch.tensor([[[0, 0, 0, 0, 0], [6, 6, 6, 6, 6], + [2, 2, 2, 2, 2], [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]], + [[0, 0, 0, 0, 0], [2, 2, 2, 2, 2], + [7, 7, 7, 7, 7], [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]]]).cuda() + assert torch.all(idx == expected_idx) + + # test dilated ball query + idx = ball_query(0.2, 0.4, 5, xyz, new_xyz) + expected_idx = torch.tensor([[[0, 5, 7, 0, 0], [6, 6, 6, 6, 6], + [2, 3, 2, 2, 2], [0, 5, 7, 0, 0], + [0, 5, 7, 0, 0]], + [[0, 0, 0, 0, 0], [2, 2, 2, 2, 2], + [7, 7, 7, 7, 7], [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]]]).cuda() + assert torch.all(idx == expected_idx) + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_stack_ball_query(): + new_xyz = torch.tensor([[-0.0740, 1.3147, -1.3625], + [-2.2769, 2.7817, -0.2334], + [-0.4003, 2.4666, -0.5116], + [-0.0740, 1.3147, -1.3625], + [-0.0740, 1.3147, -1.3625], + [-2.0289, 2.4952, -0.1708], + [-2.0668, 6.0278, -0.4875], + [0.4066, 1.4211, -0.2947], + [-2.0289, 2.4952, -0.1708], + [-2.0289, 2.4952, -0.1708]]).cuda() + new_xyz_batch_cnt = torch.tensor([5, 5], dtype=torch.int32).cuda() + xyz = torch.tensor([[-0.0740, 1.3147, -1.3625], [0.5555, 1.0399, -1.3634], + [-0.4003, 2.4666, -0.5116], [-0.5251, 2.4379, -0.8466], + [-0.9691, 1.1418, -1.3733], [-0.2232, 0.9561, -1.3626], + [-2.2769, 2.7817, -0.2334], [-0.2822, 1.3192, -1.3645], + [0.1533, 1.5024, -1.0432], [0.4917, 1.1529, -1.3496], + [-2.0289, 2.4952, -0.1708], [-0.7188, 0.9956, -0.5096], + [-2.0668, 6.0278, -0.4875], [-1.9304, 3.3092, 0.6610], + [0.0949, 1.4332, 0.3140], [-1.2879, 2.0008, -0.7791], + [-0.7252, 0.9611, -0.6371], [0.4066, 1.4211, -0.2947], + [0.3220, 1.4447, 0.3548], [-0.9744, 2.3856, + -1.2000]]).cuda() + xyz_batch_cnt = torch.tensor([10, 10], dtype=torch.int32).cuda() + idx = ball_query(0, 0.2, 5, xyz, new_xyz, xyz_batch_cnt, new_xyz_batch_cnt) + expected_idx = torch.tensor([[0, 0, 0, 0, 0], [6, 6, 6, 6, 6], + [2, 2, 2, 2, 2], [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], + [2, 2, 2, 2, 2], [7, 7, 7, 7, 7], + [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]).cuda() + assert torch.all(idx == expected_idx) + + xyz = xyz.double() + new_xyz = new_xyz.double() + expected_idx = expected_idx.double() + idx = ball_query(0, 0.2, 5, xyz, new_xyz, xyz_batch_cnt, new_xyz_batch_cnt) + assert torch.all(idx == expected_idx) + + xyz = xyz.half() + new_xyz = new_xyz.half() + expected_idx = expected_idx.half() + idx = ball_query(0, 0.2, 5, xyz, new_xyz, xyz_batch_cnt, new_xyz_batch_cnt) + assert torch.all(idx == expected_idx) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_bbox.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_bbox.py new file mode 100644 index 000000000..7123b1ee1 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_bbox.py @@ -0,0 +1,66 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE, IS_MPS_AVAILABLE + + +class TestBBox: + + def _test_bbox_overlaps(self, device='cpu', dtype=torch.float): + from mmcv.ops import bbox_overlaps + b1 = torch.tensor([[1.0, 1.0, 3.0, 4.0], [2.0, 2.0, 3.0, 4.0], + [7.0, 7.0, 8.0, 8.0]]).to(device).type(dtype) + b2 = torch.tensor([[0.0, 2.0, 2.0, 5.0], [2.0, 1.0, 3.0, + 3.0]]).to(device).type(dtype) + should_output = np.array([[0.33333334, 0.5], [0.2, 0.5], [0.0, 0.0]]) + out = bbox_overlaps(b1, b2, offset=1) + assert np.allclose(out.cpu().numpy(), should_output, 1e-2) + + b1 = torch.tensor([[1.0, 1.0, 3.0, 4.0], [2.0, 2.0, 3.0, + 4.0]]).to(device).type(dtype) + b2 = torch.tensor([[0.0, 2.0, 2.0, 5.0], [2.0, 1.0, 3.0, + 3.0]]).to(device).type(dtype) + should_output = np.array([0.33333334, 0.5]) + out = bbox_overlaps(b1, b2, aligned=True, offset=1) + assert np.allclose(out.cpu().numpy(), should_output, 1e-2) + + b1 = torch.tensor([[0.0, 0.0, 3.0, 3.0]]).to(device).type(dtype) + b2 = torch.tensor([[4.0, 0.0, 5.0, 3.0], [3.0, 0.0, 4.0, 3.0], + [2.0, 0.0, 3.0, 3.0], [1.0, 0.0, 2.0, + 3.0]]).to(device).type(dtype) + should_output = np.array([0, 0.2, 0.5, 0.5]) + out = bbox_overlaps(b1, b2, offset=1) + assert np.allclose(out.cpu().numpy(), should_output, 1e-2) + + @pytest.mark.parametrize('device', [ + 'cpu', + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')), + pytest.param( + 'mps', + marks=pytest.mark.skipif( + not IS_MPS_AVAILABLE, reason='requires MPS support')) + ]) + def test_bbox_overlaps_float(self, device): + self._test_bbox_overlaps(device, dtype=torch.float) + + @pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) + ]) + def test_bbox_overlaps_half(self, device): + self._test_bbox_overlaps(device, dtype=torch.half) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_bezier_align.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_bezier_align.py new file mode 100644 index 000000000..b86812ace --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_bezier_align.py @@ -0,0 +1,54 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE + +inputs = ([[[ + [1., 2., 5., 6.], + [3., 4., 7., 8.], + [9., 10., 13., 14.], + [11., 12., 15., 16.], +]]], [[0., 0., 0., 1, 0., 2., 0., 3., 0., 3., 3., 2., 3., 1., 3., 0., 3.]]) +outputs = ([[[[1., 1.75, 3.5, 5.25], [2.5, 3.25, 5., 6.75], + [6., 6.75, 8.5, 10.25], + [9.5, 10.25, 12., 13.75]]]], [[[[1.5625, 1.5625, 1.5625, 0.3125], + [1.5625, 1.5625, 1.5625, 0.3125], + [1.5625, 1.5625, 1.5625, 0.3125], + [0.3125, 0.3125, 0.3125, + 0.0625]]]]) + + +@pytest.mark.parametrize('device', [ + 'cpu', + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')) +]) +@pytest.mark.parametrize('dtype', [torch.float, torch.double, torch.half]) +def test_bezieralign(device, dtype): + try: + from mmcv.ops import bezier_align + except ModuleNotFoundError: + pytest.skip('test requires compilation') + pool_h = 4 + pool_w = 4 + spatial_scale = 1.0 + sampling_ratio = 1 + np_input = np.array(inputs[0]) + np_rois = np.array(inputs[1]) + np_output = np.array(outputs[0]) + np_grad = np.array(outputs[1]) + + x = torch.tensor(np_input, dtype=dtype, device=device, requires_grad=True) + rois = torch.tensor(np_rois, dtype=dtype, device=device) + + output = bezier_align(x, rois, (pool_h, pool_w), spatial_scale, + sampling_ratio, False) + output.backward(torch.ones_like(output)) + assert np.allclose( + output.data.type(torch.float).cpu().numpy(), np_output, atol=1e-3) + assert np.allclose( + x.grad.data.type(torch.float).cpu().numpy(), np_grad, atol=1e-3) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_bilinear_grid_sample.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_bilinear_grid_sample.py new file mode 100644 index 000000000..8f43d4ff2 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_bilinear_grid_sample.py @@ -0,0 +1,41 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import torch +import torch.nn.functional as F + + +class TestBilinearGridSample: + + def _test_bilinear_grid_sample(self, + dtype=torch.float, + align_corners=False, + multiplier=1, + precision=1e-3): + from mmcv.ops.point_sample import bilinear_grid_sample + + input = torch.rand(1, 1, 20, 20, dtype=dtype) + grid = torch.Tensor([[[1, 0, 0], [0, 1, 0]]]) + grid = F.affine_grid( + grid, (1, 1, 15, 15), align_corners=align_corners).type_as(input) + grid *= multiplier + + out = bilinear_grid_sample(input, grid, align_corners=align_corners) + ref_out = F.grid_sample(input, grid, align_corners=align_corners) + + assert np.allclose(out.data.detach().cpu().numpy(), + ref_out.data.detach().cpu().numpy(), precision) + + def test_bilinear_grid_sample(self): + self._test_bilinear_grid_sample(torch.double, False) + self._test_bilinear_grid_sample(torch.double, True) + self._test_bilinear_grid_sample(torch.float, False) + self._test_bilinear_grid_sample(torch.float, True) + self._test_bilinear_grid_sample(torch.float, False) + self._test_bilinear_grid_sample(torch.float, True, 5) + self._test_bilinear_grid_sample(torch.float, False, 10) + self._test_bilinear_grid_sample(torch.float, True, -6) + self._test_bilinear_grid_sample(torch.float, False, -10) + self._test_bilinear_grid_sample(torch.double, True, 5) + self._test_bilinear_grid_sample(torch.double, False, 10) + self._test_bilinear_grid_sample(torch.double, True, -6) + self._test_bilinear_grid_sample(torch.double, False, -10) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_border_align.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_border_align.py new file mode 100644 index 000000000..71518ce96 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_border_align.py @@ -0,0 +1,91 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy + +import numpy as np +import pytest +import torch + +# [1,4c,h,w] +input_arr = [[[[1., 2., 3., 4.], [5., 6., 7., 8.], [9., 10., 11., 12.]], + [[6, 7, 5, 8], [2, 1, 3, 4], [12, 9, 11, 10]], + [[-2, -3, 2, 0], [-4, -5, 1, -1], [-1, -1, -1, -1]], + [[0, -1, 2, 1], [-4, -3, -2, -1], [-1, -2, -3, -4]]]] +# [1,h*w,4] +boxes_arr = [[[0, 0, 2, 1], [1, 0, 3, 1], [1, 0, 2, 1], [0, 0, 3, 1], + [0, 0, 1, 2], [0, 0, 2, 2], [1, 0, 2, 1], [1, 0, 3, 1], + [0, 1, 1, 2], [0, 0, 3, 2], [1, 0, 3, 2], [2, 0, 3, 2]]] +output_dict = { + # [1,c,h*w,4] for each value, + # the output is manually checked for its correctness + + # pool_size=1 + 1: [[[[3., 6., 1., 2.], [4., 7., -1., 1.], [3., 7., 1., 2.], + [4., 6., -1., 1.], [2., 12., -1., -1.], [3., 12., -1., 2.], + [3., 7., 1., 2.], [4., 7., -1., 1.], [6., 12., -1., -2.], + [4., 12., -1., 1.], [4., 9., -1., 1.], [4., 11., -1., 1.]]]], + + # pool_size=2 + 2: [[[[3., 6., 1., 2.], [4., 7., 1., 1.], [3., 7., 1., 2.], + [4., 6., -1., 1.], [2., 12., -1., -1.], [3., 12., -1., 2.], + [3., 7., 1., 2.], [4., 7., 1., 1.], [6., 12., -1., -2.], + [4., 12., -1., 1.], [4., 9., -1., 1.], [4., 11., -1., 1.]]]], +} +input_grad_dict = { + # [1,4c,h,w] for each value + # the grad is manually checked for its correctness + + # pool_size=1 + 1: [[[[0., 1., 4., 6.], [0., 1., 0., 0.], [0., 0., 0., 0.]], + [[2., 4., 0., 0.], [0., 0., 0., 0.], [4., 1., 1., 0.]], + [[0., 0., 0., 0.], [0., 0., 3., 3.], [0., 2., 1., 3.]], + [[0., 1., 4., 6.], [0., 0., 0., 0.], [0., 1., 0., 0.]]]], + + # pool_size=2 + 2: [[[[0., 1., 4., 6.], [0., 1., 0., 0.], [0., 0., 0., 0.]], + [[2., 4., 0., 0.], [0., 0., 0., 0.], [4., 1., 1., 0.]], + [[0., 0., 0., 0.], [0., 0., 5., 1.], [0., 2., 1., 3.]], + [[0., 1., 4., 6.], [0., 0., 0., 0.], [0., 1., 0., 0.]]]], +} + + +def _test_border_align_allclose(device, dtype, pool_size): + if not torch.cuda.is_available() and device == 'cuda': + pytest.skip('test requires GPU') + try: + from mmcv.ops import BorderAlign, border_align + except ModuleNotFoundError: + pytest.skip('BorderAlign op is not successfully compiled') + + np_input = np.array(input_arr) + np_boxes = np.array(boxes_arr) + np_output = np.array(output_dict[pool_size]) + np_grad = np.array(input_grad_dict[pool_size]) + + input = torch.tensor( + np_input, dtype=dtype, device=device, requires_grad=True) + boxes = torch.tensor(np_boxes, dtype=dtype, device=device) + + # test for border_align + input_cp = copy.deepcopy(input) + output = border_align(input_cp, boxes, pool_size) + output.backward(torch.ones_like(output)) + assert np.allclose( + output.data.type(dtype).cpu().numpy(), np_output, atol=1e-5) + assert np.allclose( + input_cp.grad.data.type(dtype).cpu().numpy(), np_grad, atol=1e-5) + + # test for BorderAlign + pool_module = BorderAlign(pool_size) + output = pool_module(input, boxes) + output.backward(torch.ones_like(output)) + assert np.allclose( + output.data.type(dtype).cpu().numpy(), np_output, atol=1e-5) + assert np.allclose( + input.grad.data.type(dtype).cpu().numpy(), np_grad, atol=1e-5) + + +@pytest.mark.parametrize('device', ['cuda']) +@pytest.mark.parametrize('dtype', [torch.float, torch.half, torch.double]) +@pytest.mark.parametrize('pool_size', [1, 2]) +def test_border_align(device, dtype, pool_size): + _test_border_align_allclose(device, dtype, pool_size) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_quadri.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_quadri.py new file mode 100644 index 000000000..e5cfcab61 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_quadri.py @@ -0,0 +1,77 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE + + +class TestBoxIoUQuadri: + + @pytest.mark.parametrize('device', [ + 'cpu', + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + ]) + def test_box_iou_quadri_cuda(self, device): + from mmcv.ops import box_iou_quadri + np_boxes1 = np.asarray([[1.0, 1.0, 3.0, 4.0, 4.0, 4.0, 4.0, 1.0], + [2.0, 2.0, 3.0, 4.0, 4.0, 2.0, 3.0, 1.0], + [7.0, 7.0, 8.0, 8.0, 9.0, 7.0, 8.0, 6.0]], + dtype=np.float32) + np_boxes2 = np.asarray([[0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 2.0, 0.0], + [2.0, 1.0, 2.0, 4.0, 4.0, 4.0, 4.0, 1.0], + [7.0, 6.0, 7.0, 8.0, 9.0, 8.0, 9.0, 6.0]], + dtype=np.float32) + np_expect_ious = np.asarray( + [[0.0714, 1.0000, 0.0000], [0.0000, 0.5000, 0.0000], + [0.0000, 0.0000, 0.5000]], + dtype=np.float32) + np_expect_ious_aligned = np.asarray([0.0714, 0.5000, 0.5000], + dtype=np.float32) + + boxes1 = torch.from_numpy(np_boxes1).to(device) + boxes2 = torch.from_numpy(np_boxes2).to(device) + + ious = box_iou_quadri(boxes1, boxes2) + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + + ious = box_iou_quadri(boxes1, boxes2, aligned=True) + assert np.allclose( + ious.cpu().numpy(), np_expect_ious_aligned, atol=1e-4) + + @pytest.mark.parametrize('device', [ + 'cpu', + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + ]) + def test_box_iou_quadri_iof_cuda(self, device): + from mmcv.ops import box_iou_quadri + np_boxes1 = np.asarray([[1.0, 1.0, 3.0, 4.0, 4.0, 4.0, 4.0, 1.0], + [2.0, 2.0, 3.0, 4.0, 4.0, 2.0, 3.0, 1.0], + [7.0, 7.0, 8.0, 8.0, 9.0, 7.0, 8.0, 6.0]], + dtype=np.float32) + np_boxes2 = np.asarray([[0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 2.0, 0.0], + [2.0, 1.0, 2.0, 4.0, 4.0, 4.0, 4.0, 1.0], + [7.0, 6.0, 7.0, 8.0, 9.0, 8.0, 9.0, 6.0]], + dtype=np.float32) + np_expect_ious = np.asarray( + [[0.1111, 1.0000, 0.0000], [0.0000, 1.0000, 0.0000], + [0.0000, 0.0000, 1.0000]], + dtype=np.float32) + np_expect_ious_aligned = np.asarray([0.1111, 1.0000, 1.0000], + dtype=np.float32) + + boxes1 = torch.from_numpy(np_boxes1).to(device) + boxes2 = torch.from_numpy(np_boxes2).to(device) + + ious = box_iou_quadri(boxes1, boxes2, mode='iof') + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + + ious = box_iou_quadri(boxes1, boxes2, mode='iof', aligned=True) + assert np.allclose( + ious.cpu().numpy(), np_expect_ious_aligned, atol=1e-4) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_rotated.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_rotated.py new file mode 100644 index 000000000..9f5e0dfa3 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_rotated.py @@ -0,0 +1,163 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + + +class TestBoxIoURotated: + + def test_box_iou_rotated_cpu(self): + from mmcv.ops import box_iou_rotated + np_boxes1 = np.asarray( + [[1.0, 1.0, 3.0, 4.0, 0.5], [2.0, 2.0, 3.0, 4.0, 0.6], + [7.0, 7.0, 8.0, 8.0, 0.4]], + dtype=np.float32) + np_boxes2 = np.asarray( + [[0.0, 2.0, 2.0, 5.0, 0.3], [2.0, 1.0, 3.0, 3.0, 0.5], + [5.0, 5.0, 6.0, 7.0, 0.4]], + dtype=np.float32) + np_expect_ious = np.asarray( + [[0.3708, 0.4351, 0.0000], [0.1104, 0.4487, 0.0424], + [0.0000, 0.0000, 0.3622]], + dtype=np.float32) + np_expect_ious_aligned = np.asarray([0.3708, 0.4487, 0.3622], + dtype=np.float32) + + boxes1 = torch.from_numpy(np_boxes1) + boxes2 = torch.from_numpy(np_boxes2) + + # test cw angle definition + ious = box_iou_rotated(boxes1, boxes2) + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + + ious = box_iou_rotated(boxes1, boxes2, aligned=True) + assert np.allclose( + ious.cpu().numpy(), np_expect_ious_aligned, atol=1e-4) + + # test ccw angle definition + boxes1[..., -1] *= -1 + boxes2[..., -1] *= -1 + ious = box_iou_rotated(boxes1, boxes2, clockwise=False) + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + + ious = box_iou_rotated(boxes1, boxes2, aligned=True, clockwise=False) + assert np.allclose( + ious.cpu().numpy(), np_expect_ious_aligned, atol=1e-4) + + @pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') + def test_box_iou_rotated_cuda(self): + from mmcv.ops import box_iou_rotated + np_boxes1 = np.asarray( + [[1.0, 1.0, 3.0, 4.0, 0.5], [2.0, 2.0, 3.0, 4.0, 0.6], + [7.0, 7.0, 8.0, 8.0, 0.4]], + dtype=np.float32) + np_boxes2 = np.asarray( + [[0.0, 2.0, 2.0, 5.0, 0.3], [2.0, 1.0, 3.0, 3.0, 0.5], + [5.0, 5.0, 6.0, 7.0, 0.4]], + dtype=np.float32) + np_expect_ious = np.asarray( + [[0.3708, 0.4351, 0.0000], [0.1104, 0.4487, 0.0424], + [0.0000, 0.0000, 0.3622]], + dtype=np.float32) + np_expect_ious_aligned = np.asarray([0.3708, 0.4487, 0.3622], + dtype=np.float32) + + boxes1 = torch.from_numpy(np_boxes1).cuda() + boxes2 = torch.from_numpy(np_boxes2).cuda() + + # test cw angle definition + ious = box_iou_rotated(boxes1, boxes2) + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + + ious = box_iou_rotated(boxes1, boxes2, aligned=True) + assert np.allclose( + ious.cpu().numpy(), np_expect_ious_aligned, atol=1e-4) + + # test ccw angle definition + boxes1[..., -1] *= -1 + boxes2[..., -1] *= -1 + ious = box_iou_rotated(boxes1, boxes2, clockwise=False) + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + + ious = box_iou_rotated(boxes1, boxes2, aligned=True, clockwise=False) + assert np.allclose( + ious.cpu().numpy(), np_expect_ious_aligned, atol=1e-4) + + def test_box_iou_rotated_iof_cpu(self): + from mmcv.ops import box_iou_rotated + np_boxes1 = np.asarray( + [[1.0, 1.0, 3.0, 4.0, 0.5], [2.0, 2.0, 3.0, 4.0, 0.6], + [7.0, 7.0, 8.0, 8.0, 0.4]], + dtype=np.float32) + np_boxes2 = np.asarray( + [[0.0, 2.0, 2.0, 5.0, 0.3], [2.0, 1.0, 3.0, 3.0, 0.5], + [5.0, 5.0, 6.0, 7.0, 0.4]], + dtype=np.float32) + np_expect_ious = np.asarray( + [[0.4959, 0.5306, 0.0000], [0.1823, 0.5420, 0.1832], + [0.0000, 0.0000, 0.4404]], + dtype=np.float32) + np_expect_ious_aligned = np.asarray([0.4959, 0.5420, 0.4404], + dtype=np.float32) + + boxes1 = torch.from_numpy(np_boxes1) + boxes2 = torch.from_numpy(np_boxes2) + + # test cw angle definition + ious = box_iou_rotated(boxes1, boxes2, mode='iof') + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + ious = box_iou_rotated(boxes1, boxes2, mode='iof', aligned=True) + assert np.allclose( + ious.cpu().numpy(), np_expect_ious_aligned, atol=1e-4) + + # test ccw angle definition + boxes1[..., -1] *= -1 + boxes2[..., -1] *= -1 + ious = box_iou_rotated(boxes1, boxes2, mode='iof', clockwise=False) + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + ious = box_iou_rotated( + boxes1, boxes2, mode='iof', aligned=True, clockwise=False) + assert np.allclose( + ious.cpu().numpy(), np_expect_ious_aligned, atol=1e-4) + + @pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') + def test_box_iou_rotated_iof_cuda(self): + from mmcv.ops import box_iou_rotated + np_boxes1 = np.asarray( + [[1.0, 1.0, 3.0, 4.0, 0.5], [2.0, 2.0, 3.0, 4.0, 0.6], + [7.0, 7.0, 8.0, 8.0, 0.4]], + dtype=np.float32) + np_boxes2 = np.asarray( + [[0.0, 2.0, 2.0, 5.0, 0.3], [2.0, 1.0, 3.0, 3.0, 0.5], + [5.0, 5.0, 6.0, 7.0, 0.4]], + dtype=np.float32) + np_expect_ious = np.asarray( + [[0.4959, 0.5306, 0.0000], [0.1823, 0.5420, 0.1832], + [0.0000, 0.0000, 0.4404]], + dtype=np.float32) + np_expect_ious_aligned = np.asarray([0.4959, 0.5420, 0.4404], + dtype=np.float32) + + boxes1 = torch.from_numpy(np_boxes1).cuda() + boxes2 = torch.from_numpy(np_boxes2).cuda() + + # test cw angle definition + ious = box_iou_rotated(boxes1, boxes2, mode='iof') + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + + ious = box_iou_rotated(boxes1, boxes2, mode='iof', aligned=True) + assert np.allclose( + ious.cpu().numpy(), np_expect_ious_aligned, atol=1e-4) + + # test ccw angle definition + boxes1[..., -1] *= -1 + boxes2[..., -1] *= -1 + ious = box_iou_rotated(boxes1, boxes2, mode='iof', clockwise=False) + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + + ious = box_iou_rotated( + boxes1, boxes2, mode='iof', aligned=True, clockwise=False) + assert np.allclose( + ious.cpu().numpy(), np_expect_ious_aligned, atol=1e-4) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_carafe.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_carafe.py new file mode 100644 index 000000000..02d00f1ff --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_carafe.py @@ -0,0 +1,85 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch +from torch.autograd import gradcheck + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE + + +class TestCarafe: + + def test_carafe_naive_gradcheck(self): + if not torch.cuda.is_available(): + return + from mmcv.ops import CARAFENaive + feat = torch.randn( + 2, 64, 3, 3, requires_grad=True, device='cuda').double() + mask = torch.randn( + 2, 100, 6, 6, requires_grad=True, + device='cuda').sigmoid().double() + gradcheck(CARAFENaive(5, 4, 2), (feat, mask), atol=1e-4, eps=1e-4) + + def test_carafe_gradcheck(self): + if not torch.cuda.is_available(): + return + from mmcv.ops import CARAFE + feat = torch.randn( + 2, 64, 3, 3, requires_grad=True, device='cuda').double() + mask = torch.randn( + 2, 100, 6, 6, requires_grad=True, + device='cuda').sigmoid().double() + gradcheck(CARAFE(5, 4, 2), (feat, mask), atol=1e-4, eps=1e-4) + + @pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) + ]) + def test_carafe_allclose(self, device): + try: + from mmcv.ops import CARAFE + except ModuleNotFoundError: + pytest.skip('test requires compilation') + + np_feat = np.fromfile( + 'tests/data/for_carafe/carafe_feat.bin', dtype=np.float32) + np_mask = np.fromfile( + 'tests/data/for_carafe/carafe_mask.bin', dtype=np.float32) + np_output = np.fromfile( + 'tests/data/for_carafe/carafe_output.bin', dtype=np.float32) + np_feat_grad = np.fromfile( + 'tests/data/for_carafe/carafe_feat_grad.bin', dtype=np.float32) + np_mask_grad = np.fromfile( + 'tests/data/for_carafe/carafe_mask_grad.bin', dtype=np.float32) + + np_feat = np_feat.reshape((2, 64, 3, 3)) + np_mask = np_mask.reshape((2, 100, 6, 6)) + np_output = np_output.reshape((2, 64, 6, 6)) + np_feat_grad = np_feat_grad.reshape((2, 64, 3, 3)) + np_mask_grad = np_mask_grad.reshape((2, 100, 6, 6)) + + feat = torch.tensor( + np_feat, dtype=torch.float, device=device, requires_grad=True) + mask = torch.tensor( + np_mask, dtype=torch.float, device=device, requires_grad=True) + + carafe = CARAFE(5, 4, 2) + + output = carafe(feat, mask) + output.backward(torch.ones_like(output)) + assert np.allclose( + output.data.type(torch.float).cpu().numpy(), np_output, atol=1e-3) + assert np.allclose( + feat.grad.data.type(torch.float).cpu().numpy(), + np_feat_grad, + atol=1e-3) + assert np.allclose( + mask.grad.data.type(torch.float).cpu().numpy(), + np_mask_grad, + atol=1e-3) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_cc_attention.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_cc_attention.py new file mode 100644 index 000000000..b2a8d22a3 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_cc_attention.py @@ -0,0 +1,56 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import torch +import torch.nn as nn + + +class Loss(nn.Module): + + def __init__(self): + super().__init__() + + def forward(self, input, target): + input = input.view(-1) + target = target.view(-1) + return torch.mean(input - target) + + +class TestCrissCrossAttention: + + def test_cc_attention(self): + device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') + + from mmcv.ops import CrissCrossAttention + loss_func = Loss() + + input = np.fromfile( + 'tests/data/for_ccattention/ccattention_input.bin', + dtype=np.float32) + output = np.fromfile( + 'tests/data/for_ccattention/ccattention_output.bin', + dtype=np.float32) + input = input.reshape((1, 32, 45, 45)) + output = output.reshape((1, 32, 45, 45)) + label = torch.ones((1, 32, 45, 45)) + + input = torch.FloatTensor(input) + output = torch.FloatTensor(output) + + input.requires_grad = True + + shape = input.shape + channel = shape[1] + + cca = CrissCrossAttention(channel) + cca.to(device) + input = input.to(device) + label = label.to(device) + cca.train() + test_output = cca(input) + test_loss = loss_func(test_output, label) + test_loss.backward() + test_output = test_output.detach().cpu().numpy() + output = output.numpy() + + assert np.allclose(test_output, output) + assert test_output.shape == shape diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_chamfer_distance.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_chamfer_distance.py new file mode 100644 index 000000000..522dcdddc --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_chamfer_distance.py @@ -0,0 +1,57 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import chamfer_distance + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_chamfer_distance(): + pointset1 = torch.tensor( + [[[1.3, 9.39], [2.3, 9.39], [2.3, 10.39], [1.3, 10.39]], + [[1.0, 9.39], [3.0, 9.39], [3.0, 10.39], [1.0, 10.39]], + [[1.6, 9.99], [2.3, 9.99], [2.3, 10.39], [1.6, 10.39]]], + device='cuda', + requires_grad=True) + + pointset2 = torch.tensor( + [[[1.0, 9.39], [3.0, 9.39], [3.0, 10.39], [1.0, 10.39]], + [[1.3, 9.39], [2.3, 9.39], [2.3, 10.39], [1.3, 10.39]], + [[1.0, 9.39], [3.0, 9.39], [3.0, 10.39], [1.0, 10.39]]], + device='cuda', + requires_grad=True) + + expected_dist1 = torch.tensor( + [[0.0900, 0.4900, 0.4900, 0.0900], [0.0900, 0.4900, 0.4900, 0.0900], + [0.5200, 0.6500, 0.4900, 0.3600]], + device='cuda') + expected_dist2 = torch.tensor( + [[0.0900, 0.4900, 0.4900, 0.0900], [0.0900, 0.4900, 0.4900, 0.0900], + [0.7200, 0.8500, 0.4900, 0.3600]], + device='cuda') + + expected_pointset1_grad = torch.tensor( + [[[0.6000, 0.0000], [-1.4000, 0.0000], [-1.4000, 0.0000], + [0.6000, 0.0000]], + [[-0.6000, 0.0000], [1.4000, 0.0000], [1.4000, 0.0000], + [-0.6000, 0.0000]], + [[1.2000, -0.8000], [-1.4000, -0.8000], [-1.4000, 0.0000], + [1.2000, 0.0000]]], + device='cuda') + + expected_pointset2_grad = torch.tensor( + [[[-0.6000, 0.0000], [1.4000, 0.0000], [1.4000, 0.0000], + [-0.6000, 0.0000]], + [[0.6000, 0.0000], [-1.4000, 0.0000], [-1.4000, 0.0000], + [0.6000, 0.0000]], + [[0.0000, 0.0000], [0.0000, 0.0000], [2.8000, 0.8000], + [-2.4000, 0.8000]]], + device='cuda') + + dist1, dist2, idx1, idx2 = chamfer_distance(pointset1, pointset2) + dist1.backward(torch.ones_like(dist1)) + assert torch.allclose(dist1, expected_dist1, 1e-2) + assert torch.allclose(dist2, expected_dist2, 1e-2) + assert torch.allclose(pointset1.grad.data, expected_pointset1_grad, 1e-2) + assert torch.allclose(pointset2.grad.data, expected_pointset2_grad, 1e-2) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_contour_expand.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_contour_expand.py new file mode 100644 index 000000000..b36bbf415 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_contour_expand.py @@ -0,0 +1,49 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import torch + + +def test_contour_expand(): + from mmcv.ops import contour_expand + + np_internal_kernel_label = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 0, 0, 0, 0, 2, 0], + [0, 0, 1, 1, 0, 0, 0, 0, 2, 0], + [0, 0, 1, 1, 0, 0, 0, 0, 2, 0], + [0, 0, 1, 1, 0, 0, 0, 0, 2, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, + 0]]).astype(np.int32) + np_kernel_mask1 = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 0, 1, 1, 1, 1, 1, 1, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, + 0]]).astype(np.uint8) + np_kernel_mask2 = (np_internal_kernel_label > 0).astype(np.uint8) + + np_kernel_mask = np.stack([np_kernel_mask1, np_kernel_mask2]) + min_area = 1 + kernel_region_num = 3 + result = contour_expand(np_kernel_mask, np_internal_kernel_label, min_area, + kernel_region_num) + gt = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 2, 2, 2, 0], + [0, 0, 1, 1, 1, 1, 2, 2, 2, 0], [0, 0, 1, 1, 1, 1, 2, 2, 2, 0], + [0, 0, 1, 1, 1, 1, 2, 2, 2, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] + assert np.allclose(result, gt) + + np_kernel_mask_t = torch.from_numpy(np_kernel_mask) + np_internal_kernel_label_t = torch.from_numpy(np_internal_kernel_label) + result = contour_expand(np_kernel_mask_t, np_internal_kernel_label_t, + min_area, kernel_region_num) + assert np.allclose(result, gt) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_convex_iou.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_convex_iou.py new file mode 100644 index 000000000..95dc48243 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_convex_iou.py @@ -0,0 +1,56 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.ops import convex_giou, convex_iou + +np_pointsets = np.asarray([[ + 1.0, 1.0, 2.0, 2.0, 1.0, 2.0, 2.0, 1.0, 1.0, 3.0, 3.0, 1.0, 2.0, 3.0, 3.0, + 2.0, 1.5, 1.5 +], + [ + 1.5, 1.5, 2.5, 2.5, 1.5, 2.5, 2.5, 1.5, 1.5, + 3.5, 3.5, 1.5, 2.5, 3.5, 3.5, 2.5, 2.0, 2.0 + ]]) + +np_polygons = np.asarray([[1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 1.0], + [1.0, 1.0, 1.0, 3.0, 3.0, 3.0, 3.0, 1.0]]) + +np_expected_iou = np.asarray([[0.2857, 0.8750], [0.0588, 0.4286]]) + +np_expected_giou = np.asarray([0.2857, 0.3831]) + +np_expected_grad = np.asarray([[ + 0.0204, 0.0408, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0612, + -0.0408, -0.0408, 0.0816, -0.0408, -0.0816, -0.0816, -0.0408, 0.0000, + 0.0000 +], + [ + -0.1848, -0.1848, 0.0000, 0.0000, 0.0000, + 0.0000, 0.0000, 0.0000, -0.1076, -0.0801, + -0.0801, -0.1076, -0.0367, -0.0734, -0.0734, + -0.0367, 0.0000, 0.0000 + ]]) + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_convex_iou(): + pointsets = torch.from_numpy(np_pointsets).cuda().float() + polygons = torch.from_numpy(np_polygons).cuda().float() + expected_iou = torch.from_numpy(np_expected_iou).cuda().float() + assert torch.allclose( + convex_iou(pointsets, polygons), expected_iou, atol=1e-3) + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_convex_giou(): + pointsets = torch.from_numpy(np_pointsets).cuda().float() + polygons = torch.from_numpy(np_polygons).cuda().float() + expected_giou = torch.from_numpy(np_expected_giou).cuda().float() + expected_grad = torch.from_numpy(np_expected_grad).cuda().float() + giou, grad = convex_giou(pointsets, polygons) + assert torch.allclose(giou, expected_giou, atol=1e-3) + assert torch.allclose(grad, expected_grad, atol=1e-3) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_corner_pool.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_corner_pool.py new file mode 100644 index 000000000..d6dd25f22 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_corner_pool.py @@ -0,0 +1,59 @@ +# Copyright (c) OpenMMLab. All rights reserved. +""" +CommandLine: + pytest tests/test_corner_pool.py +""" +import pytest +import torch + +from mmcv.ops import CornerPool + + +def test_corner_pool_device_and_dtypes_cpu(): + """ + CommandLine: + xdoctest -m tests/test_corner_pool.py \ + test_corner_pool_device_and_dtypes_cpu + """ + with pytest.raises(AssertionError): + # pool mode must in ['bottom', 'left', 'right', 'top'] + pool = CornerPool('corner') + + lr_tensor = torch.tensor([[[[0, 0, 0, 0, 0], [2, 1, 3, 0, 2], + [5, 4, 1, 1, 6], [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]]]]) + tb_tensor = torch.tensor([[[[0, 3, 1, 0, 0], [0, 1, 1, 0, 0], + [0, 3, 4, 0, 0], [0, 2, 2, 0, 0], + [0, 0, 2, 0, 0]]]]) + # Left Pool + left_answer = torch.tensor([[[[0, 0, 0, 0, 0], [3, 3, 3, 2, 2], + [6, 6, 6, 6, 6], [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]]]]) + pool = CornerPool('left') + left_tensor = pool(lr_tensor) + assert left_tensor.type() == lr_tensor.type() + assert torch.equal(left_tensor, left_answer) + # Right Pool + right_answer = torch.tensor([[[[0, 0, 0, 0, 0], [2, 2, 3, 3, 3], + [5, 5, 5, 5, 6], [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]]]]) + pool = CornerPool('right') + right_tensor = pool(lr_tensor) + assert right_tensor.type() == lr_tensor.type() + assert torch.equal(right_tensor, right_answer) + # Top Pool + top_answer = torch.tensor([[[[0, 3, 4, 0, 0], [0, 3, 4, 0, 0], + [0, 3, 4, 0, 0], [0, 2, 2, 0, 0], + [0, 0, 2, 0, 0]]]]) + pool = CornerPool('top') + top_tensor = pool(tb_tensor) + assert top_tensor.type() == tb_tensor.type() + assert torch.equal(top_tensor, top_answer) + # Bottom Pool + bottom_answer = torch.tensor([[[[0, 3, 1, 0, 0], [0, 3, 1, 0, 0], + [0, 3, 4, 0, 0], [0, 3, 4, 0, 0], + [0, 3, 4, 0, 0]]]]) + pool = CornerPool('bottom') + bottom_tensor = pool(tb_tensor) + assert bottom_tensor.type() == tb_tensor.type() + assert torch.equal(bottom_tensor, bottom_answer) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_correlation.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_correlation.py new file mode 100644 index 000000000..6cf5f9f72 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_correlation.py @@ -0,0 +1,46 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import Correlation + +_input1 = [[[[1., 2., 3.], [0., 1., 2.], [3., 5., 2.]]]] +_input2 = [[[[1., 2., 3.], [3., 1., 2.], [8., 5., 2.]]]] + +gt_out_shape = (1, 1, 1, 3, 3) +_gt_out = [[[[[1., 4., 9.], [0., 1., 4.], [24., 25., 4.]]]]] +gt_input1_grad = [[[[1., 2., 3.], [3., 1., 2.], [8., 5., 2.]]]] + + +def assert_equal_tensor(tensor_a, tensor_b): + + assert tensor_a.eq(tensor_b).all() + + +class TestCorrelation: + + def _test_correlation(self, dtype=torch.float): + + layer = Correlation(max_displacement=0) + + input1 = torch.tensor(_input1, dtype=dtype).cuda() + input2 = torch.tensor(_input2, dtype=dtype).cuda() + input1.requires_grad = True + input2.requires_grad = True + out = layer(input1, input2) + out.backward(torch.ones_like(out)) + + # `eq_cpu` is not implemented for 'Half' in torch1.5.0, + # so we need to make a comparison for cuda tensor + # rather than cpu tensor + gt_out = torch.tensor(_gt_out, dtype=dtype).cuda() + assert_equal_tensor(out, gt_out) + assert_equal_tensor(input1.grad.detach(), input2) + assert_equal_tensor(input2.grad.detach(), input1) + + @pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') + def test_correlation(self): + self._test_correlation(torch.float) + self._test_correlation(torch.double) + self._test_correlation(torch.half) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_conv.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_conv.py new file mode 100644 index 000000000..64dcccfde --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_conv.py @@ -0,0 +1,200 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch +from mmengine.utils import digit_version +from mmengine.utils.dl_utils import TORCH_VERSION + +try: + # If PyTorch version >= 1.6.0 and fp16 is enabled, torch.cuda.amp.autocast + # would be imported and used; we should test if our modules support it. + from torch.cuda.amp import autocast +except ImportError: + pass + +input = [[[[1., 2., 3.], [0., 1., 2.], [3., 5., 2.]]]] +offset_weight = [[[0.1, 0.4, 0.6, 0.1]], [[0.3, 0.2, 0.1, 0.3]], + [[0.5, 0.5, 0.2, 0.8]], [[0.8, 0.3, 0.9, 0.1]], + [[0.3, 0.1, 0.2, 0.5]], [[0.3, 0.7, 0.5, 0.3]], + [[0.6, 0.2, 0.5, 0.3]], [[0.4, 0.1, 0.8, 0.4]]] +offset_bias = [0.7, 0.1, 0.8, 0.5, 0.6, 0.5, 0.4, 0.7] +deform_weight = [[[0.4, 0.2, 0.1, 0.9]]] + +gt_out = [[[[1.650, 0.], [0.000, 0.]]]] +gt_x_grad = [[[[-0.666, 0.204, 0.000], [0.030, -0.416, 0.012], + [0.000, 0.252, 0.129]]]] +gt_offset_weight_grad = [[[[1.44, 2.88], [0.00, 1.44]]], + [[[-0.72, -1.44], [0.00, -0.72]]], + [[[0.00, 0.00], [0.00, 0.00]]], + [[[0.00, 0.00], [0.00, 0.00]]], + [[[-0.10, -0.20], [0.00, -0.10]]], + [[[-0.08, -0.16], [0.00, -0.08]]], + [[[-0.54, -1.08], [0.00, -0.54]]], + [[[-0.54, -1.08], [0.00, -0.54]]]] +gt_offset_bias_grad = [1.44, -0.72, 0., 0., -0.10, -0.08, -0.54, -0.54], +gt_deform_weight_grad = [[[[3.62, 0.], [0.40, 0.18]]]] + + +class TestDeformconv: + + def _test_deformconv(self, + dtype=torch.float, + threshold=1e-3, + device='cuda', + batch_size=10, + im2col_step=2): + if not torch.cuda.is_available() and device == 'cuda': + pytest.skip('test requires GPU') + from mmcv.ops import DeformConv2dPack + c_in = 1 + c_out = 1 + batch_size = 10 + repeated_input = np.repeat(input, batch_size, axis=0) + repeated_gt_out = np.repeat(gt_out, batch_size, axis=0) + repeated_gt_x_grad = np.repeat(gt_x_grad, batch_size, axis=0) + x = torch.tensor(repeated_input, device=device, dtype=dtype) + x.requires_grad = True + model = DeformConv2dPack( + in_channels=c_in, + out_channels=c_out, + kernel_size=2, + stride=1, + padding=0, + im2col_step=im2col_step) + model.conv_offset.weight.data = torch.nn.Parameter( + torch.Tensor(offset_weight).reshape(8, 1, 2, 2)) + model.conv_offset.bias.data = torch.nn.Parameter( + torch.Tensor(offset_bias).reshape(8)) + model.weight.data = torch.nn.Parameter( + torch.Tensor(deform_weight).reshape(1, 1, 2, 2)) + if device == 'cuda': + model.cuda() + model.type(dtype) + + out = model(x) + out.backward(torch.ones_like(out)) + + assert np.allclose(out.data.detach().cpu().numpy(), repeated_gt_out, + threshold) + assert np.allclose(x.grad.detach().cpu().numpy(), repeated_gt_x_grad, + threshold) + # the batch size of the input is increased which results in + # a larger gradient so we need to divide by the batch_size + assert np.allclose( + model.conv_offset.weight.grad.detach().cpu().numpy() / batch_size, + gt_offset_weight_grad, threshold) + assert np.allclose( + model.conv_offset.bias.grad.detach().cpu().numpy() / batch_size, + gt_offset_bias_grad, threshold) + assert np.allclose( + model.weight.grad.detach().cpu().numpy() / batch_size, + gt_deform_weight_grad, threshold) + + from mmcv.ops import DeformConv2d + + # test bias + model = DeformConv2d(1, 1, 2, stride=1, padding=0) + assert not hasattr(model, 'bias') + # test bias=True + with pytest.raises(AssertionError): + model = DeformConv2d(1, 1, 2, stride=1, padding=0, bias=True) + # test in_channels % group != 0 + with pytest.raises(AssertionError): + model = DeformConv2d(3, 2, 3, groups=2) + # test out_channels % group != 0 + with pytest.raises(AssertionError): + model = DeformConv2d(3, 4, 3, groups=3) + + def _test_amp_deformconv(self, + input_dtype, + threshold=1e-3, + batch_size=10, + im2col_step=2): + """The function to test amp released on pytorch 1.6.0. + + The type of input data might be torch.float or torch.half, + so we should test deform_conv in both cases. With amp, the + data type of model will NOT be set manually. + + Args: + input_dtype: torch.float or torch.half. + threshold: the same as above function. + """ + if not torch.cuda.is_available(): + return + from mmcv.ops import DeformConv2dPack + c_in = 1 + c_out = 1 + repeated_input = np.repeat(input, batch_size, axis=0) + repeated_gt_out = np.repeat(gt_out, batch_size, axis=0) + repeated_gt_x_grad = np.repeat(gt_x_grad, batch_size, axis=0) + x = torch.Tensor(repeated_input).cuda().type(input_dtype) + x.requires_grad = True + model = DeformConv2dPack( + in_channels=c_in, + out_channels=c_out, + kernel_size=2, + stride=1, + padding=0, + im2col_step=im2col_step) + model.conv_offset.weight.data = torch.nn.Parameter( + torch.Tensor(offset_weight).reshape(8, 1, 2, 2)) + model.conv_offset.bias.data = torch.nn.Parameter( + torch.Tensor(offset_bias).reshape(8)) + model.weight.data = torch.nn.Parameter( + torch.Tensor(deform_weight).reshape(1, 1, 2, 2)) + model.cuda() + + out = model(x) + out.backward(torch.ones_like(out)) + + assert np.allclose(out.data.detach().cpu().numpy(), repeated_gt_out, + threshold) + assert np.allclose(x.grad.detach().cpu().numpy(), repeated_gt_x_grad, + threshold) + assert np.allclose( + model.conv_offset.weight.grad.detach().cpu().numpy() / batch_size, + gt_offset_weight_grad, threshold) + assert np.allclose( + model.conv_offset.bias.grad.detach().cpu().numpy() / batch_size, + gt_offset_bias_grad, threshold) + assert np.allclose( + model.weight.grad.detach().cpu().numpy() / batch_size, + gt_deform_weight_grad, threshold) + + from mmcv.ops import DeformConv2d + + # test bias + model = DeformConv2d(1, 1, 2, stride=1, padding=0) + assert not hasattr(model, 'bias') + # test bias=True + with pytest.raises(AssertionError): + model = DeformConv2d(1, 1, 2, stride=1, padding=0, bias=True) + # test in_channels % group != 0 + with pytest.raises(AssertionError): + model = DeformConv2d(3, 2, 3, groups=2) + # test out_channels % group != 0 + with pytest.raises(AssertionError): + model = DeformConv2d(3, 4, 3, groups=3) + + def test_deformconv(self): + self._test_deformconv(torch.double, device='cpu') + self._test_deformconv(torch.float, device='cpu', threshold=1e-1) + self._test_deformconv(torch.double) + self._test_deformconv(torch.float) + self._test_deformconv(torch.half, threshold=1e-1) + # test batch_size < im2col_step + self._test_deformconv(torch.float, batch_size=1, im2col_step=2) + # test bach_size % im2col_step != 0 + with pytest.raises( + AssertionError, + match='batch size must be divisible by im2col_step'): + self._test_deformconv(torch.float, batch_size=10, im2col_step=3) + + # test amp when torch version >= '1.6.0', the type of + # input data for deformconv might be torch.float or torch.half + if (TORCH_VERSION != 'parrots' + and digit_version(TORCH_VERSION) >= digit_version('1.6.0')): + with autocast(enabled=True): + self._test_amp_deformconv(torch.float, 1e-1) + self._test_amp_deformconv(torch.half, 1e-1) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_roi_pool.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_roi_pool.py new file mode 100644 index 000000000..346301fe4 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_roi_pool.py @@ -0,0 +1,152 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os + +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE, IS_NPU_AVAILABLE + +_USING_PARROTS = True +try: + from parrots.autograd import gradcheck +except ImportError: + from torch.autograd import gradcheck + _USING_PARROTS = False + +cur_dir = os.path.dirname(os.path.abspath(__file__)) + +inputs = [([[[[1., 2.], [3., 4.]]]], [[0., 0., 0., 1., 1.]]), + ([[[[1., 2.], [3., 4.]], [[4., 3.], [2., + 1.]]]], [[0., 0., 0., 1., 1.]]), + ([[[[1., 2., 5., 6.], [3., 4., 7., 8.], [9., 10., 13., 14.], + [11., 12., 15., 16.]]]], [[0., 0., 0., 3., 3.]])] +outputs = [([[[[1, 1.25], [1.5, 1.75]]]], [[[[3.0625, 0.4375], + [0.4375, 0.0625]]]]), + ([[[[1., 1.25], [1.5, 1.75]], [[4, 3.75], + [3.5, 3.25]]]], [[[[3.0625, 0.4375], + [0.4375, 0.0625]], + [[3.0625, 0.4375], + [0.4375, + 0.0625]]]]), + ([[[[1.9375, 4.75], + [7.5625, + 10.375]]]], [[[[0.47265625, 0.4296875, 0.4296875, 0.04296875], + [0.4296875, 0.390625, 0.390625, 0.0390625], + [0.4296875, 0.390625, 0.390625, 0.0390625], + [0.04296875, 0.0390625, 0.0390625, + 0.00390625]]]])] + + +class TestDeformRoIPool: + + def test_deform_roi_pool_gradcheck(self): + if not torch.cuda.is_available(): + return + from mmcv.ops import DeformRoIPoolPack + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + sampling_ratio = 2 + + for case in inputs: + np_input = np.array(case[0]) + np_rois = np.array(case[1]) + + x = torch.tensor( + np_input, device='cuda', dtype=torch.float, requires_grad=True) + rois = torch.tensor(np_rois, device='cuda', dtype=torch.float) + output_c = x.size(1) + + droipool = DeformRoIPoolPack((pool_h, pool_w), + output_c, + spatial_scale=spatial_scale, + sampling_ratio=sampling_ratio).cuda() + + if _USING_PARROTS: + gradcheck(droipool, (x, rois), no_grads=[rois]) + else: + gradcheck(droipool, (x, rois), eps=1e-2, atol=1e-2) + + def test_modulated_deform_roi_pool_gradcheck(self): + if not torch.cuda.is_available(): + return + from mmcv.ops import ModulatedDeformRoIPoolPack + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + sampling_ratio = 2 + + for case in inputs: + np_input = np.array(case[0]) + np_rois = np.array(case[1]) + + x = torch.tensor( + np_input, device='cuda', dtype=torch.float, requires_grad=True) + rois = torch.tensor(np_rois, device='cuda', dtype=torch.float) + output_c = x.size(1) + + droipool = ModulatedDeformRoIPoolPack( + (pool_h, pool_w), + output_c, + spatial_scale=spatial_scale, + sampling_ratio=sampling_ratio).cuda() + + if _USING_PARROTS: + gradcheck(droipool, (x, rois), no_grads=[rois]) + else: + gradcheck(droipool, (x, rois), eps=1e-2, atol=1e-2) + + def _test_deform_roi_pool_allclose(self, device, dtype=torch.float): + from mmcv.ops import DeformRoIPoolPack + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + sampling_ratio = 2 + + for case, output in zip(inputs, outputs): + np_input = np.array(case[0]) + np_rois = np.array(case[1]) + np_output = np.array(output[0]) + np_grad = np.array(output[1]) + + x = torch.tensor( + np_input, device=device, dtype=torch.float, requires_grad=True) + rois = torch.tensor(np_rois, device=device, dtype=torch.float) + output_c = x.size(1) + droipool = DeformRoIPoolPack( + (pool_h, pool_w), + output_c, + spatial_scale=spatial_scale, + sampling_ratio=sampling_ratio).to(device) + + output = droipool(x, rois) + output.backward(torch.ones_like(output)) + assert np.allclose(output.data.cpu().numpy(), np_output, 1e-3) + assert np.allclose(x.grad.data.cpu().numpy(), np_grad, 1e-3) + + @pytest.mark.parametrize('device', [ + pytest.param( + 'npu', + marks=pytest.mark.skipif( + not IS_NPU_AVAILABLE, reason='requires NPU support')), + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) + ]) + @pytest.mark.parametrize('dtype', [ + torch.float, + pytest.param( + torch.double, + marks=pytest.mark.skipif( + IS_MLU_AVAILABLE, + reason='MLU does not support for 64-bit floating point')), + torch.half + ]) + def test_deform_roi_pool_allclose(self, device, dtype): + self._test_deform_roi_pool_allclose(device, dtype) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_diff_iou_rotated.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_diff_iou_rotated.py new file mode 100644 index 000000000..01e05551b --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_diff_iou_rotated.py @@ -0,0 +1,49 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.ops import diff_iou_rotated_2d, diff_iou_rotated_3d + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_diff_iou_rotated_2d(): + np_boxes1 = np.asarray([[[0.5, 0.5, 1., 1., .0], [0.5, 0.5, 1., 1., .0], + [0.5, 0.5, 1., 1., .0], [0.5, 0.5, 1., 1., .0], + [0.5, 0.5, 1., 1., .0]]], + dtype=np.float32) + np_boxes2 = np.asarray( + [[[0.5, 0.5, 1., 1., .0], [0.5, 0.5, 1., 1., np.pi / 2], + [0.5, 0.5, 1., 1., np.pi / 4], [1., 1., 1., 1., .0], + [1.5, 1.5, 1., 1., .0]]], + dtype=np.float32) + + boxes1 = torch.from_numpy(np_boxes1).cuda() + boxes2 = torch.from_numpy(np_boxes2).cuda() + + np_expect_ious = np.asarray([[1., 1., .7071, 1 / 7, .0]]) + ious = diff_iou_rotated_2d(boxes1, boxes2) + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_diff_iou_rotated_3d(): + np_boxes1 = np.asarray( + [[[.5, .5, .5, 1., 1., 1., .0], [.5, .5, .5, 1., 1., 1., .0], + [.5, .5, .5, 1., 1., 1., .0], [.5, .5, .5, 1., 1., 1., .0], + [.5, .5, .5, 1., 1., 1., .0]]], + dtype=np.float32) + np_boxes2 = np.asarray( + [[[.5, .5, .5, 1., 1., 1., .0], [.5, .5, .5, 1., 1., 2., np.pi / 2], + [.5, .5, .5, 1., 1., 1., np.pi / 4], [1., 1., 1., 1., 1., 1., .0], + [-1.5, -1.5, -1.5, 2.5, 2.5, 2.5, .0]]], + dtype=np.float32) + + boxes1 = torch.from_numpy(np_boxes1).cuda() + boxes2 = torch.from_numpy(np_boxes2).cuda() + + np_expect_ious = np.asarray([[1., .5, .7071, 1 / 15, .0]]) + ious = diff_iou_rotated_3d(boxes1, boxes2) + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_focal_loss.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_focal_loss.py new file mode 100644 index 000000000..ee7c9861a --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_focal_loss.py @@ -0,0 +1,170 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE, IS_NPU_AVAILABLE + +_USING_PARROTS = True +try: + from parrots.autograd import gradcheck +except ImportError: + from torch.autograd import gradcheck + _USING_PARROTS = False + +# torch.set_printoptions(precision=8, threshold=100) + +inputs = [ + ([[1., 0], [0, 1.]], [0, 1]), + ([[1., 0, -1.], [0, 1., 2.]], [2, 1]), + ([[1e-6, 2e-6, 3e-6], [4e-6, 5e-5, 6e-4], [7e-3, 8e-2, 9e-1]], [1, 2, 0]), +] + +softmax_outputs = [(0.00566451, [[-0.00657264, 0.00657264], + [0.00657264, -0.00657264]]), + (0.34956908, [[0.10165970, 0.03739851, -0.13905823], + [0.01227554, -0.10298023, 0.09070466]]), + (0.15754992, [[0.02590877, -0.05181759, 0.02590882], + [0.02589641, 0.02589760, -0.05179400], + [-0.07307514, 0.02234372, 0.05073142]])] + +sigmoid_outputs = [(0.13562961, [[-0.00657264, 0.11185755], + [0.11185755, -0.00657264]]), + (1.10251057, [[0.28808805, 0.11185755, -0.09602935], + [0.11185755, -0.00657264, 0.40376765]]), + (0.42287254, [[0.07457182, -0.02485716, 0.07457201], + [0.07457211, 0.07457669, -0.02483728], + [-0.02462499, 0.08277918, 0.18050370]])] + + +class Testfocalloss: + + def _test_softmax(self, dtype=torch.float): + if not torch.cuda.is_available(): + return + from mmcv.ops import softmax_focal_loss + alpha = 0.25 + gamma = 2.0 + for case, output in zip(inputs, softmax_outputs): + np_x = np.array(case[0]) + np_y = np.array(case[1]) + np_x_grad = np.array(output[1]) + + x = torch.from_numpy(np_x).cuda().type(dtype) + x.requires_grad_() + y = torch.from_numpy(np_y).cuda().long() + + loss = softmax_focal_loss(x, y, gamma, alpha, None, 'mean') + loss.backward() + + assert np.allclose(loss.data.cpu().numpy(), output[0], 1e-2) + assert np.allclose(x.grad.data.cpu(), np_x_grad, 1e-2) + + def _test_sigmoid(self, device, dtype=torch.float): + from mmcv.ops import sigmoid_focal_loss + alpha = 0.25 + gamma = 2.0 + for case, output in zip(inputs, sigmoid_outputs): + np_x = np.array(case[0]) + np_y = np.array(case[1]) + np_x_grad = np.array(output[1]) + + x = torch.from_numpy(np_x).to(device).type(dtype) + x.requires_grad_() + y = torch.from_numpy(np_y).to(device).long() + + loss = sigmoid_focal_loss(x, y, gamma, alpha, None, 'mean') + loss.backward() + + assert np.allclose(loss.data.cpu().numpy(), output[0], 1e-2) + assert np.allclose(x.grad.data.cpu(), np_x_grad, 1e-2) + + def _test_grad_softmax(self, dtype=torch.float): + if not torch.cuda.is_available(): + return + from mmcv.ops import SoftmaxFocalLoss + alpha = 0.25 + gamma = 2.0 + for case in inputs: + np_x = np.array(case[0]) + np_y = np.array(case[1]) + + x = torch.from_numpy(np_x).cuda().type(dtype) + x.requires_grad_() + y = torch.from_numpy(np_y).cuda().long() + + floss = SoftmaxFocalLoss(gamma, alpha) + if _USING_PARROTS: + # gradcheck(floss, (x, y), + # no_grads=[y]) + pass + else: + gradcheck(floss, (x, y), eps=1e-2, atol=1e-2) + + def _test_grad_sigmoid(self, dtype=torch.float): + if not torch.cuda.is_available(): + return + from mmcv.ops import SigmoidFocalLoss + alpha = 0.25 + gamma = 2.0 + for case in inputs: + np_x = np.array(case[0]) + np_y = np.array(case[1]) + + x = torch.from_numpy(np_x).cuda().type(dtype) + x.requires_grad_() + y = torch.from_numpy(np_y).cuda().long() + + floss = SigmoidFocalLoss(gamma, alpha) + if _USING_PARROTS: + # gradcheck(floss, (x, y), + # no_grads=[y]) + pass + else: + gradcheck(floss, (x, y), eps=1e-2, atol=1e-2) + + def test_softmax_float(self): + self._test_softmax(dtype=torch.float) + + def test_softmax_half(self): + self._test_softmax(dtype=torch.half) + + @pytest.mark.parametrize('device', [ + pytest.param( + 'npu', + marks=pytest.mark.skipif( + not IS_NPU_AVAILABLE, reason='requires NPU support')), + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) + ]) + def test_sigmoid_float(self, device): + self._test_sigmoid(device=device, dtype=torch.float) + + @pytest.mark.parametrize('device', [ + pytest.param( + 'npu', + marks=pytest.mark.skipif( + not IS_NPU_AVAILABLE, reason='requires NPU support')), + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) + ]) + def test_sigmoid_half(self, device): + self._test_sigmoid(device, dtype=torch.half) + + def test_grad_softmax_float(self): + self._test_grad_softmax(dtype=torch.float) + + def test_grad_sigmoid_float(self): + self._test_grad_sigmoid(dtype=torch.float) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_furthest_point_sample.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_furthest_point_sample.py new file mode 100644 index 000000000..7e61e64a9 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_furthest_point_sample.py @@ -0,0 +1,52 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import furthest_point_sample, furthest_point_sample_with_dist + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_fps(): + xyz = torch.tensor([[[-0.2748, 1.0020, -1.1674], [0.1015, 1.3952, -1.2681], + [-0.8070, 2.4137, + -0.5845], [-1.0001, 2.1982, -0.5859], + [0.3841, 1.8983, -0.7431]], + [[-1.0696, 3.0758, + -0.1899], [-0.2559, 3.5521, -0.1402], + [0.8164, 4.0081, -0.1839], [-1.1000, 3.0213, -0.8205], + [-0.0518, 3.7251, -0.3950]]]).cuda() + + idx = furthest_point_sample(xyz, 3) + expected_idx = torch.tensor([[0, 2, 4], [0, 2, 1]]).cuda() + assert torch.all(idx == expected_idx) + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_fps_with_dist(): + xyz = torch.tensor([[[-0.2748, 1.0020, -1.1674], [0.1015, 1.3952, -1.2681], + [-0.8070, 2.4137, + -0.5845], [-1.0001, 2.1982, -0.5859], + [0.3841, 1.8983, -0.7431]], + [[-1.0696, 3.0758, + -0.1899], [-0.2559, 3.5521, -0.1402], + [0.8164, 4.0081, -0.1839], [-1.1000, 3.0213, -0.8205], + [-0.0518, 3.7251, -0.3950]]]).cuda() + + expected_idx = torch.tensor([[0, 2, 4], [0, 2, 1]]).cuda() + xyz_square_dist = ((xyz.unsqueeze(dim=1) - + xyz.unsqueeze(dim=2))**2).sum(-1) + idx = furthest_point_sample_with_dist(xyz_square_dist, 3) + assert torch.all(idx == expected_idx) + + import numpy as np + fps_idx = np.load('tests/data/for_3d_ops/fps_idx.npy') + features_for_fps_distance = np.load( + 'tests/data/for_3d_ops/features_for_fps_distance.npy') + expected_idx = torch.from_numpy(fps_idx).cuda() + features_for_fps_distance = torch.from_numpy( + features_for_fps_distance).cuda() + + idx = furthest_point_sample_with_dist(features_for_fps_distance, 16) + assert torch.all(idx == expected_idx) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_fused_bias_leakyrelu.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_fused_bias_leakyrelu.py new file mode 100644 index 000000000..e6f6fb9f7 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_fused_bias_leakyrelu.py @@ -0,0 +1,74 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_NPU_AVAILABLE + +_USING_PARROTS = True +try: + from parrots.autograd import gradcheck +except ImportError: + from torch.autograd import gradcheck, gradgradcheck + _USING_PARROTS = False + + +class TestFusedBiasLeakyReLU: + + @classmethod + def setup_class(cls): + if not IS_CUDA_AVAILABLE and not IS_NPU_AVAILABLE: + return + if IS_CUDA_AVAILABLE: + cls.input_tensor = torch.randn((2, 2, 2, 2), + requires_grad=True).cuda() + cls.bias = torch.zeros(2, requires_grad=True).cuda() + elif IS_NPU_AVAILABLE: + cls.input_tensor = torch.randn((2, 2, 2, 2), + requires_grad=True).npu() + cls.bias = torch.zeros(2, requires_grad=True).npu() + + @pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'npu', + marks=pytest.mark.skipif( + not IS_NPU_AVAILABLE, reason='requires NPU support')) + ]) + def test_gradient(self, device): + + from mmcv.ops import FusedBiasLeakyReLU + if _USING_PARROTS: + if IS_CUDA_AVAILABLE: + gradcheck( + FusedBiasLeakyReLU(2).cuda(), + self.input_tensor, + delta=1e-4, + pt_atol=1e-3) + else: + gradcheck( + FusedBiasLeakyReLU(2).to(device), + self.input_tensor, + eps=1e-4, + atol=1e-3) + + @pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'npu', + marks=pytest.mark.skipif( + not IS_NPU_AVAILABLE, reason='requires NPU support')) + ]) + def test_gradgradient(self, device): + + from mmcv.ops import FusedBiasLeakyReLU + gradgradcheck( + FusedBiasLeakyReLU(2).to(device), + self.input_tensor, + eps=1e-4, + atol=1e-3) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_gather_points.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_gather_points.py new file mode 100644 index 000000000..a93df692a --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_gather_points.py @@ -0,0 +1,51 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import gather_points + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_gather_points(): + features = torch.tensor([[[ + -1.6095, -0.1029, -0.8876, -1.2447, -2.4031, 0.3708, -1.1586, -1.4967, + -0.4800, 0.2252 + ], + [ + 1.9138, 3.4979, 1.6854, 1.5631, 3.6776, + 3.1154, 2.1705, 2.5221, 2.0411, 3.1446 + ], + [ + -1.4173, 0.3073, -1.4339, -1.4340, -1.2770, + -0.2867, -1.4162, -1.4044, -1.4245, -1.4074 + ]], + [[ + 0.2160, 0.0842, 0.3661, -0.2749, -0.4909, + -0.6066, -0.8773, -0.0745, -0.9496, 0.1434 + ], + [ + 1.3644, 1.8087, 1.6855, 1.9563, 1.2746, + 1.9662, 0.9566, 1.8778, 1.1437, 1.3639 + ], + [ + -0.7172, 0.1692, 0.2241, 0.0721, -0.7540, + 0.0462, -0.6227, 0.3223, -0.6944, -0.5294 + ]]]).cuda() + + idx = torch.tensor([[0, 1, 4, 0, 0, 0], [0, 5, 6, 0, 0, 0]]).int().cuda() + + output = gather_points(features, idx) + expected_output = torch.tensor( + [[[-1.6095, -0.1029, -2.4031, -1.6095, -1.6095, -1.6095], + [1.9138, 3.4979, 3.6776, 1.9138, 1.9138, 1.9138], + [-1.4173, 0.3073, -1.2770, -1.4173, -1.4173, -1.4173]], + [[0.2160, -0.6066, -0.8773, 0.2160, 0.2160, 0.2160], + [1.3644, 1.9662, 0.9566, 1.3644, 1.3644, 1.3644], + [-0.7172, 0.0462, -0.6227, -0.7172, -0.7172, -0.7172]]]).cuda() + + assert torch.allclose(output, expected_output) + + # test fp16 + output_half = gather_points(features.half(), idx) + assert torch.allclose(output_half, expected_output.half()) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_group_points.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_group_points.py new file mode 100644 index 000000000..8109540ce --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_group_points.py @@ -0,0 +1,164 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import grouping_operation + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +@pytest.mark.parametrize('dtype', [torch.half, torch.float, torch.double]) +def test_grouping_points(dtype): + idx = torch.tensor([[[0, 0, 0], [3, 3, 3], [8, 8, 8], [0, 0, 0], [0, 0, 0], + [0, 0, 0]], + [[0, 0, 0], [6, 6, 6], [9, 9, 9], [0, 0, 0], [0, 0, 0], + [0, 0, 0]]]).int().cuda() + features = torch.tensor([[[ + 0.5798, -0.7981, -0.9280, -1.3311, 1.3687, 0.9277, -0.4164, -1.8274, + 0.9268, 0.8414 + ], + [ + 5.4247, 1.5113, 2.3944, 1.4740, 5.0300, + 5.1030, 1.9360, 2.1939, 2.1581, 3.4666 + ], + [ + -1.6266, -1.0281, -1.0393, -1.6931, -1.3982, + -0.5732, -1.0830, -1.7561, -1.6786, -1.6967 + ]], + [[ + -0.0380, -0.1880, -1.5724, 0.6905, -0.3190, + 0.7798, -0.3693, -0.9457, -0.2942, -1.8527 + ], + [ + 1.1773, 1.5009, 2.6399, 5.9242, 1.0962, + 2.7346, 6.0865, 1.5555, 4.3303, 2.8229 + ], + [ + -0.6646, -0.6870, -0.1125, -0.2224, -0.3445, + -1.4049, 0.4990, -0.7037, -0.9924, 0.0386 + ]]], + dtype=dtype).cuda() + + output = grouping_operation(features, idx) + expected_output = torch.tensor( + [[[[0.5798, 0.5798, 0.5798], [-1.3311, -1.3311, -1.3311], + [0.9268, 0.9268, 0.9268], [0.5798, 0.5798, 0.5798], + [0.5798, 0.5798, 0.5798], [0.5798, 0.5798, 0.5798]], + [[5.4247, 5.4247, 5.4247], [1.4740, 1.4740, 1.4740], + [2.1581, 2.1581, 2.1581], [5.4247, 5.4247, 5.4247], + [5.4247, 5.4247, 5.4247], [5.4247, 5.4247, 5.4247]], + [[-1.6266, -1.6266, -1.6266], [-1.6931, -1.6931, -1.6931], + [-1.6786, -1.6786, -1.6786], [-1.6266, -1.6266, -1.6266], + [-1.6266, -1.6266, -1.6266], [-1.6266, -1.6266, -1.6266]]], + [[[-0.0380, -0.0380, -0.0380], [-0.3693, -0.3693, -0.3693], + [-1.8527, -1.8527, -1.8527], [-0.0380, -0.0380, -0.0380], + [-0.0380, -0.0380, -0.0380], [-0.0380, -0.0380, -0.0380]], + [[1.1773, 1.1773, 1.1773], [6.0865, 6.0865, 6.0865], + [2.8229, 2.8229, 2.8229], [1.1773, 1.1773, 1.1773], + [1.1773, 1.1773, 1.1773], [1.1773, 1.1773, 1.1773]], + [[-0.6646, -0.6646, -0.6646], [0.4990, 0.4990, 0.4990], + [0.0386, 0.0386, 0.0386], [-0.6646, -0.6646, -0.6646], + [-0.6646, -0.6646, -0.6646], [-0.6646, -0.6646, -0.6646]]]], + dtype=dtype).cuda() + assert torch.allclose(output, expected_output) + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +@pytest.mark.parametrize('dtype', [torch.half, torch.float, torch.double]) +def test_stack_grouping_points(dtype): + idx = torch.tensor([[0, 0, 0], [3, 3, 3], [8, 8, 8], [1, 1, 1], [0, 0, 0], + [2, 2, 2], [0, 0, 0], [6, 6, 6], [9, 9, 9], [0, 0, 0], + [1, 1, 1], [0, 0, 0]]).int().cuda() + features = torch.tensor([[ + 0.5798, -0.7981, -0.9280, -1.3311, 1.3687, 0.9277, -0.4164, -1.8274, + 0.9268, 0.8414 + ], + [ + 5.4247, 1.5113, 2.3944, 1.4740, 5.0300, + 5.1030, 1.9360, 2.1939, 2.1581, 3.4666 + ], + [ + -1.6266, -1.0281, -1.0393, -1.6931, -1.3982, + -0.5732, -1.0830, -1.7561, -1.6786, -1.6967 + ], + [ + -0.0380, -0.1880, -1.5724, 0.6905, -0.3190, + 0.7798, -0.3693, -0.9457, -0.2942, -1.8527 + ], + [ + 1.1773, 1.5009, 2.6399, 5.9242, 1.0962, + 2.7346, 6.0865, 1.5555, 4.3303, 2.8229 + ], + [ + -0.6646, -0.6870, -0.1125, -0.2224, -0.3445, + -1.4049, 0.4990, -0.7037, -0.9924, 0.0386 + ]], + dtype=dtype).cuda() + features_batch_cnt = torch.tensor([3, 3]).int().cuda() + indices_batch_cnt = torch.tensor([6, 6]).int().cuda() + output = grouping_operation(features, idx, features_batch_cnt, + indices_batch_cnt) + expected_output = torch.tensor( + [[[0.5798, 0.5798, 0.5798], [-0.7981, -0.7981, -0.7981], + [-0.9280, -0.9280, -0.9280], [-1.3311, -1.3311, -1.3311], + [1.3687, 1.3687, 1.3687], [0.9277, 0.9277, 0.9277], + [-0.4164, -0.4164, -0.4164], [-1.8274, -1.8274, -1.8274], + [0.9268, 0.9268, 0.9268], [0.8414, 0.8414, 0.8414]], + [[0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000]], + [[0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000]], + [[5.4247, 5.4247, 5.4247], [1.5113, 1.5113, 1.5113], + [2.3944, 2.3944, 2.3944], [1.4740, 1.4740, 1.4740], + [5.0300, 5.0300, 5.0300], [5.1030, 5.1030, 5.1030], + [1.9360, 1.9360, 1.9360], [2.1939, 2.1939, 2.1939], + [2.1581, 2.1581, 2.1581], [3.4666, 3.4666, 3.4666]], + [[0.5798, 0.5798, 0.5798], [-0.7981, -0.7981, -0.7981], + [-0.9280, -0.9280, -0.9280], [-1.3311, -1.3311, -1.3311], + [1.3687, 1.3687, 1.3687], [0.9277, 0.9277, 0.9277], + [-0.4164, -0.4164, -0.4164], [-1.8274, -1.8274, -1.8274], + [0.9268, 0.9268, 0.9268], [0.8414, 0.8414, 0.8414]], + [[-1.6266, -1.6266, -1.6266], [-1.0281, -1.0281, -1.0281], + [-1.0393, -1.0393, -1.0393], [-1.6931, -1.6931, -1.6931], + [-1.3982, -1.3982, -1.3982], [-0.5732, -0.5732, -0.5732], + [-1.0830, -1.0830, -1.0830], [-1.7561, -1.7561, -1.7561], + [-1.6786, -1.6786, -1.6786], [-1.6967, -1.6967, -1.6967]], + [[-0.0380, -0.0380, -0.0380], [-0.1880, -0.1880, -0.1880], + [-1.5724, -1.5724, -1.5724], [0.6905, 0.6905, 0.6905], + [-0.3190, -0.3190, -0.3190], [0.7798, 0.7798, 0.7798], + [-0.3693, -0.3693, -0.3693], [-0.9457, -0.9457, -0.9457], + [-0.2942, -0.2942, -0.2942], [-1.8527, -1.8527, -1.8527]], + [[0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000]], + [[0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000], + [0.0000, 0.0000, 0.0000], [0.0000, 0.0000, 0.0000]], + [[-0.0380, -0.0380, -0.0380], [-0.1880, -0.1880, -0.1880], + [-1.5724, -1.5724, -1.5724], [0.6905, 0.6905, 0.6905], + [-0.3190, -0.3190, -0.3190], [0.7798, 0.7798, 0.7798], + [-0.3693, -0.3693, -0.3693], [-0.9457, -0.9457, -0.9457], + [-0.2942, -0.2942, -0.2942], [-1.8527, -1.8527, -1.8527]], + [[1.1773, 1.1773, 1.1773], [1.5009, 1.5009, 1.5009], + [2.6399, 2.6399, 2.6399], [5.9242, 5.9242, 5.9242], + [1.0962, 1.0962, 1.0962], [2.7346, 2.7346, 2.7346], + [6.0865, 6.0865, 6.0865], [1.5555, 1.5555, 1.5555], + [4.3303, 4.3303, 4.3303], [2.8229, 2.8229, 2.8229]], + [[-0.0380, -0.0380, -0.0380], [-0.1880, -0.1880, -0.1880], + [-1.5724, -1.5724, -1.5724], [0.6905, 0.6905, 0.6905], + [-0.3190, -0.3190, -0.3190], [0.7798, 0.7798, 0.7798], + [-0.3693, -0.3693, -0.3693], [-0.9457, -0.9457, -0.9457], + [-0.2942, -0.2942, -0.2942], [-1.8527, -1.8527, -1.8527]]], + dtype=dtype).cuda() + assert torch.allclose(output, expected_output) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_info.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_info.py new file mode 100644 index 000000000..e3c1722eb --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_info.py @@ -0,0 +1,14 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + + +class TestInfo: + + def test_info(self): + if not torch.cuda.is_available(): + return + from mmcv.ops import get_compiler_version, get_compiling_cuda_version + cv = get_compiler_version() + ccv = get_compiling_cuda_version() + assert cv is not None + assert ccv is not None diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_iou3d.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_iou3d.py new file mode 100644 index 000000000..6bb8c1ccc --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_iou3d.py @@ -0,0 +1,145 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.ops import boxes_iou3d, boxes_overlap_bev, nms3d, nms3d_normal +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE + + +@pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')) +]) +def test_boxes_overlap_bev(device): + np_boxes1 = np.asarray([[1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 0.0], + [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 0.0], + [3.0, 3.0, 3.0, 3.0, 2.0, 2.0, 0.0]], + dtype=np.float32) + np_boxes2 = np.asarray([[1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 0.0], + [1.0, 1.0, 1.0, 2.0, 2.0, 2.0, np.pi / 2], + [1.0, 1.0, 1.0, 2.0, 2.0, 2.0, np.pi / 4]], + dtype=np.float32) + np_expect_overlaps = np.asarray( + [[4.0, 4.0, (8 + 8 * 2**0.5) / + (3 + 2 * 2**0.5)], [1.0, 1.0, 1.0], [0.0, 0.0, 0.0]], + dtype=np.float32) + + boxes1 = torch.from_numpy(np_boxes1).to(device) + boxes2 = torch.from_numpy(np_boxes2).to(device) + + # test for 3 boxes + overlaps = boxes_overlap_bev(boxes1, boxes2) + assert np.allclose(overlaps.cpu().numpy(), np_expect_overlaps, atol=1e-4) + + # test for many boxes + boxes2 = boxes2.repeat_interleave(555, 0) + + overlaps = boxes_overlap_bev(boxes1, boxes2) + assert np.allclose( + overlaps.cpu().numpy(), np_expect_overlaps.repeat(555, 1), atol=1e-4) + + +@pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')) +]) +def test_boxes_iou3d(device): + np_boxes1 = np.asarray([[1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 0.0], + [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 0.0], + [3.0, 3.0, 3.0, 3.0, 2.0, 2.0, 0.0]], + dtype=np.float32) + np_boxes2 = np.asarray([[1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 0.0], + [1.0, 1.0, 1.0, 2.0, 2.0, 2.0, np.pi / 2], + [1.0, 1.0, 1.0, 2.0, 2.0, 2.0, np.pi / 4]], + dtype=np.float32) + np_expect_ious = np.asarray( + [[1.0, 1.0, 1.0 / 2**0.5], [1.0 / 15, 1.0 / 15, 1.0 / 15], + [0.0, 0.0, 0.0]], + dtype=np.float32) + + boxes1 = torch.from_numpy(np_boxes1).to(device) + boxes2 = torch.from_numpy(np_boxes2).to(device) + + ious = boxes_iou3d(boxes1, boxes2) + assert np.allclose(ious.cpu().numpy(), np_expect_ious, atol=1e-4) + + +@pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) +]) +def test_nms3d(device): + # test for 5 boxes + np_boxes = np.asarray([[1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 0.0], + [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 0.0], + [3.0, 3.0, 3.0, 3.0, 2.0, 2.0, 0.3], + [3.0, 3.0, 3.0, 3.0, 2.0, 2.0, 0.0], + [3.0, 3.2, 3.2, 3.0, 2.0, 2.0, 0.3]], + dtype=np.float32) + np_scores = np.array([0.6, 0.9, 0.1, 0.2, 0.15], dtype=np.float32) + np_inds = np.array([1, 0, 3]) + boxes = torch.from_numpy(np_boxes) + scores = torch.from_numpy(np_scores) + inds = nms3d(boxes.to(device), scores.to(device), iou_threshold=0.3) + + assert np.allclose(inds.cpu().numpy(), np_inds) + + # test for many boxes + # In the float data type calculation process, float will be converted to + # double in CUDA kernel (https://github.com/open-mmlab/mmcv/blob + # /master/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp#L61), + # always use float in MLU kernel. The difference between the mentioned + # above leads to different results. + if device != 'mlu': + np.random.seed(42) + np_boxes = np.random.rand(555, 7).astype(np.float32) + np_scores = np.random.rand(555).astype(np.float32) + boxes = torch.from_numpy(np_boxes) + scores = torch.from_numpy(np_scores) + inds = nms3d(boxes.to(device), scores.to(device), iou_threshold=0.3) + + assert len(inds.cpu().numpy()) == 176 + + +@pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')) +]) +def test_nms3d_normal(device): + # test for 5 boxes + np_boxes = np.asarray([[1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 0.0], + [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 0.0], + [3.0, 3.0, 3.0, 3.0, 2.0, 2.0, 0.3], + [3.0, 3.0, 3.0, 3.0, 2.0, 2.0, 0.0], + [3.0, 3.2, 3.2, 3.0, 2.0, 2.0, 0.3]], + dtype=np.float32) + np_scores = np.array([0.6, 0.9, 0.1, 0.2, 0.15], dtype=np.float32) + np_inds = np.array([1, 0, 3]) + boxes = torch.from_numpy(np_boxes) + scores = torch.from_numpy(np_scores) + inds = nms3d_normal(boxes.to(device), scores.to(device), iou_threshold=0.3) + + assert np.allclose(inds.cpu().numpy(), np_inds) + + # test for many boxes + np.random.seed(42) + np_boxes = np.random.rand(555, 7).astype(np.float32) + np_scores = np.random.rand(555).astype(np.float32) + boxes = torch.from_numpy(np_boxes) + scores = torch.from_numpy(np_scores) + inds = nms3d_normal(boxes.to(device), scores.to(device), iou_threshold=0.3) + + assert len(inds.cpu().numpy()) == 148 diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_knn.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_knn.py new file mode 100644 index 000000000..1236a5fcb --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_knn.py @@ -0,0 +1,55 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import knn + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_knn(): + new_xyz = torch.tensor([[[-0.0740, 1.3147, -1.3625], + [-2.2769, 2.7817, -0.2334], + [-0.4003, 2.4666, -0.5116], + [-0.0740, 1.3147, -1.3625], + [-0.0740, 1.3147, -1.3625]], + [[-2.0289, 2.4952, -0.1708], + [-2.0668, 6.0278, -0.4875], + [0.4066, 1.4211, -0.2947], + [-2.0289, 2.4952, -0.1708], + [-2.0289, 2.4952, -0.1708]]]).cuda() + + xyz = torch.tensor([[[-0.0740, 1.3147, -1.3625], [0.5555, 1.0399, -1.3634], + [-0.4003, 2.4666, + -0.5116], [-0.5251, 2.4379, -0.8466], + [-0.9691, 1.1418, + -1.3733], [-0.2232, 0.9561, -1.3626], + [-2.2769, 2.7817, -0.2334], + [-0.2822, 1.3192, -1.3645], [0.1533, 1.5024, -1.0432], + [0.4917, 1.1529, -1.3496]], + [[-2.0289, 2.4952, + -0.1708], [-0.7188, 0.9956, -0.5096], + [-2.0668, 6.0278, -0.4875], [-1.9304, 3.3092, 0.6610], + [0.0949, 1.4332, 0.3140], [-1.2879, 2.0008, -0.7791], + [-0.7252, 0.9611, -0.6371], [0.4066, 1.4211, -0.2947], + [0.3220, 1.4447, 0.3548], [-0.9744, 2.3856, + -1.2000]]]).cuda() + + idx = knn(5, xyz, new_xyz) + new_xyz_ = new_xyz.unsqueeze(2).repeat(1, 1, xyz.shape[1], 1) + xyz_ = xyz.unsqueeze(1).repeat(1, new_xyz.shape[1], 1, 1) + dist = ((new_xyz_ - xyz_) * (new_xyz_ - xyz_)).sum(-1) + expected_idx = dist.topk(k=5, dim=2, largest=False)[1].transpose(2, 1) + assert torch.all(idx == expected_idx) + + idx = knn(5, + xyz.transpose(1, 2).contiguous(), + new_xyz.transpose(1, 2).contiguous(), True) + assert torch.all(idx == expected_idx) + + idx = knn(5, xyz, xyz) + xyz_ = xyz.unsqueeze(2).repeat(1, 1, xyz.shape[1], 1) + xyz__ = xyz.unsqueeze(1).repeat(1, xyz.shape[1], 1, 1) + dist = ((xyz_ - xyz__) * (xyz_ - xyz__)).sum(-1) + expected_idx = dist.topk(k=5, dim=2, largest=False)[1].transpose(2, 1) + assert torch.all(idx == expected_idx) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_masked_conv2d.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_masked_conv2d.py new file mode 100644 index 000000000..a292f6a4f --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_masked_conv2d.py @@ -0,0 +1,41 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE + + +class TestMaskedConv2d: + + @pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) + ]) + def test_masked_conv2d_all_close(self, device): + from mmcv.ops import MaskedConv2d + np_input = np.load( + 'tests/data/for_masked_conv2d/masked_conv2d_for_input.npy') + np_mask = np.load( + 'tests/data/for_masked_conv2d/masked_conv2d_for_mask.npy') + np_weight = np.load( + 'tests/data/for_masked_conv2d/masked_conv2d_for_weight.npy') + np_bias = np.load( + 'tests/data/for_masked_conv2d/masked_conv2d_for_bias.npy') + np_output = np.load( + 'tests/data/for_masked_conv2d/masked_conv2d_for_output.npy') + input = torch.tensor(np_input, dtype=torch.float, device=device) + mask = torch.tensor(np_mask, dtype=torch.float, device=device) + weight = torch.tensor(np_weight, dtype=torch.float, device=device) + bias = torch.tensor(np_bias, dtype=torch.float, device=device) + conv = MaskedConv2d(3, 3, 3, 1, 1).to(device) + conv.weight = torch.nn.Parameter(weight) + conv.bias = torch.nn.Parameter(bias) + output = conv(input, mask) + assert np.allclose(output.data.cpu().numpy(), np_output, 1e-3) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_merge_cells.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_merge_cells.py new file mode 100644 index 000000000..51551c141 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_merge_cells.py @@ -0,0 +1,95 @@ +# Copyright (c) OpenMMLab. All rights reserved. +""" +CommandLine: + pytest tests/test_merge_cells.py +""" +import math + +import pytest +import torch +import torch.nn.functional as F + +from mmcv.ops.merge_cells import (BaseMergeCell, ConcatCell, GlobalPoolingCell, + SumCell) + + +# All size (14, 7) below is to test the situation that +# the input size can't be divisible by the target size. +@pytest.mark.parametrize( + 'inputs_x, inputs_y', + [(torch.randn([2, 256, 16, 16]), torch.randn([2, 256, 32, 32])), + (torch.randn([2, 256, 14, 7]), torch.randn([2, 256, 32, 32]))]) +def test_sum_cell(inputs_x, inputs_y): + sum_cell = SumCell(256, 256) + output = sum_cell(inputs_x, inputs_y, out_size=inputs_x.shape[-2:]) + assert output.size() == inputs_x.size() + output = sum_cell(inputs_x, inputs_y, out_size=inputs_y.shape[-2:]) + assert output.size() == inputs_y.size() + output = sum_cell(inputs_x, inputs_y) + assert output.size() == inputs_y.size() + + +@pytest.mark.parametrize( + 'inputs_x, inputs_y', + [(torch.randn([2, 256, 16, 16]), torch.randn([2, 256, 32, 32])), + (torch.randn([2, 256, 14, 7]), torch.randn([2, 256, 32, 32]))]) +def test_concat_cell(inputs_x, inputs_y): + concat_cell = ConcatCell(256, 256) + output = concat_cell(inputs_x, inputs_y, out_size=inputs_x.shape[-2:]) + assert output.size() == inputs_x.size() + output = concat_cell(inputs_x, inputs_y, out_size=inputs_y.shape[-2:]) + assert output.size() == inputs_y.size() + output = concat_cell(inputs_x, inputs_y) + assert output.size() == inputs_y.size() + + +@pytest.mark.parametrize( + 'inputs_x, inputs_y', + [(torch.randn([2, 256, 16, 16]), torch.randn([2, 256, 32, 32])), + (torch.randn([2, 256, 14, 7]), torch.randn([2, 256, 32, 32]))]) +def test_global_pool_cell(inputs_x, inputs_y): + gp_cell = GlobalPoolingCell(with_out_conv=False) + gp_cell_out = gp_cell(inputs_x, inputs_y, out_size=inputs_x.shape[-2:]) + assert (gp_cell_out.size() == inputs_x.size()) + gp_cell = GlobalPoolingCell(256, 256) + gp_cell_out = gp_cell(inputs_x, inputs_y, out_size=inputs_x.shape[-2:]) + assert (gp_cell_out.size() == inputs_x.size()) + + +@pytest.mark.parametrize('target_size', [(256, 256), (128, 128), (64, 64), + (14, 7)]) +def test_resize_methods(target_size): + inputs_x = torch.randn([2, 256, 128, 128]) + h, w = inputs_x.shape[-2:] + target_h, target_w = target_size + if (h <= target_h) or w <= target_w: + rs_mode = 'upsample' + else: + rs_mode = 'downsample' + + if rs_mode == 'upsample': + upsample_methods_list = ['nearest', 'bilinear'] + for method in upsample_methods_list: + merge_cell = BaseMergeCell(upsample_mode=method) + merge_cell_out = merge_cell._resize(inputs_x, target_size) + gt_out = F.interpolate(inputs_x, size=target_size, mode=method) + assert merge_cell_out.equal(gt_out) + elif rs_mode == 'downsample': + merge_cell = BaseMergeCell() + merge_cell_out = merge_cell._resize(inputs_x, target_size) + if h % target_h != 0 or w % target_w != 0: + pad_h = math.ceil(h / target_h) * target_h - h + pad_w = math.ceil(w / target_w) * target_w - w + pad_l = pad_w // 2 + pad_r = pad_w - pad_l + pad_t = pad_h // 2 + pad_b = pad_h - pad_t + pad = (pad_l, pad_r, pad_t, pad_b) + inputs_x = F.pad(inputs_x, pad, mode='constant', value=0.0) + kernel_size = (inputs_x.shape[-2] // target_h, + inputs_x.shape[-1] // target_w) + gt_out = F.max_pool2d( + inputs_x, kernel_size=kernel_size, stride=kernel_size) + print(merge_cell_out.shape, gt_out.shape) + assert (merge_cell_out == gt_out).all() + assert merge_cell_out.shape[-2:] == target_size diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_min_area_polygons.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_min_area_polygons.py new file mode 100644 index 000000000..649bdecfd --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_min_area_polygons.py @@ -0,0 +1,30 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.ops import min_area_polygons + +np_pointsets = np.asarray([[ + 1.0, 1.0, 2.0, 2.0, 1.0, 2.0, 2.0, 1.0, 1.0, 3.0, 3.0, 1.0, 2.0, 3.0, 3.0, + 2.0, 1.5, 1.5 +], + [ + 1.0, 1.0, 8.0, 8.0, 1.0, 2.0, 2.0, 1.0, 1.0, + 3.0, 3.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.5, 1.5 + ]]) + +expected_polygons = np.asarray( + [[3.0000, 1.0000, 1.0000, 1.0000, 1.0000, 3.0000, 3.0000, 3.0000], + [8.0, 8.0, 2.3243, 0.0541, 0.0541, 1.6757, 5.7297, 9.6216]]) + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_min_area_polygons(): + pointsets = torch.from_numpy(np_pointsets).cuda().float() + + assert np.allclose( + min_area_polygons(pointsets).cpu().numpy(), + expected_polygons, + atol=1e-4) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_modulated_deform_conv.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_modulated_deform_conv.py new file mode 100644 index 000000000..ee29e73eb --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_modulated_deform_conv.py @@ -0,0 +1,127 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os + +import numpy +import pytest +import torch +from mmengine.utils import digit_version +from mmengine.utils.dl_utils import TORCH_VERSION + +try: + # If PyTorch version >= 1.6.0 and fp16 is enabled, torch.cuda.amp.autocast + # would be imported and used; we should test if our modules support it. + from torch.cuda.amp import autocast +except ImportError: + pass + +cur_dir = os.path.dirname(os.path.abspath(__file__)) + +input_t = [[[[1., 2., 3.], [1., 2., 3.], [1., 2., 3.]]]] +output_t = [[[[0.5, 1.5, 2.5, 1.5], [1.0, 3.0, 5.0, 3.0], [1.0, 3.0, 5.0, 3.0], + [0.5, 1.5, 2.5, 1.5]]]] +input_grad = [[[[2., 2., 2.], [2., 2., 2.], [2., 2., 2.]]]] +dcn_w_grad = [[[[9., 9.], [9., 9.]]]] +dcn_offset_w_grad = [[[[-7.0, -4.0], [0.0, 0.0]]], [[[-9.0, 7.5], [-6.0, + 5.0]]], + [[[-4.0, -7.0], [0.0, 0.0]]], + [[[-7.5, -9.0], [-5.0, -6.0]]], + [[[-7.0, -4.0], [-7.0, -4.0]]], + [[[-6.0, 5.0], [-9.0, 7.5]]], + [[[-4.0, -7.0], [-4.0, -7.0]]], + [[[-5.0, -6.0], [-7.5, -9.0]]], [[[10.5, 6.0], [7.0, + 4.0]]], + [[[6.0, 10.5], [4.0, 7.0]]], [[[7.0, 4.0], [10.5, 6.0]]], + [[[4.0, 7.0], [6.0, 10.5]]]] +dcn_offset_b_grad = [ + -3.0, -1.5, -3.0, -1.5, -3.0, -1.5, -3.0, -1.5, 4.5, 4.5, 4.5, 4.5 +] + + +class TestMdconv: + + def _test_mdconv(self, dtype=torch.float, device='cuda'): + if not torch.cuda.is_available() and device == 'cuda': + pytest.skip('test requires GPU') + from mmcv.ops import ModulatedDeformConv2dPack + input = torch.tensor(input_t, dtype=dtype, device=device) + input.requires_grad = True + + dcn = ModulatedDeformConv2dPack( + 1, + 1, + kernel_size=(2, 2), + stride=1, + padding=1, + deform_groups=1, + bias=False) + + if device == 'cuda': + dcn.cuda() + + dcn.weight.data.fill_(1.) + dcn.type(dtype) + output = dcn(input) + output.sum().backward() + assert numpy.allclose(output.cpu().detach().numpy(), output_t, 1e-2) + assert numpy.allclose(input.grad.cpu().detach().numpy(), input_grad, + 1e-2) + assert numpy.allclose(dcn.weight.grad.cpu().detach().numpy(), + dcn_w_grad, 1e-2) + assert numpy.allclose( + dcn.conv_offset.weight.grad.cpu().detach().numpy(), + dcn_offset_w_grad, 1e-2) + assert numpy.allclose(dcn.conv_offset.bias.grad.cpu().detach().numpy(), + dcn_offset_b_grad, 1e-2) + + def _test_amp_mdconv(self, input_dtype=torch.float): + """The function to test amp released on pytorch 1.6.0. + + The type of input data might be torch.float or torch.half, + so we should test mdconv in both cases. With amp, the data + type of model will NOT be set manually. + + Args: + input_dtype: torch.float or torch.half. + """ + if not torch.cuda.is_available(): + return + from mmcv.ops import ModulatedDeformConv2dPack + input = torch.tensor(input_t).cuda().type(input_dtype) + input.requires_grad = True + + dcn = ModulatedDeformConv2dPack( + 1, + 1, + kernel_size=(2, 2), + stride=1, + padding=1, + deform_groups=1, + bias=False).cuda() + dcn.weight.data.fill_(1.) + output = dcn(input) + output.sum().backward() + assert numpy.allclose(output.cpu().detach().numpy(), output_t, 1e-2) + assert numpy.allclose(input.grad.cpu().detach().numpy(), input_grad, + 1e-2) + assert numpy.allclose(dcn.weight.grad.cpu().detach().numpy(), + dcn_w_grad, 1e-2) + assert numpy.allclose( + dcn.conv_offset.weight.grad.cpu().detach().numpy(), + dcn_offset_w_grad, 1e-2) + assert numpy.allclose(dcn.conv_offset.bias.grad.cpu().detach().numpy(), + dcn_offset_b_grad, 1e-2) + + def test_mdconv(self): + self._test_mdconv(torch.double, device='cpu') + self._test_mdconv(torch.float, device='cpu') + self._test_mdconv(torch.double) + self._test_mdconv(torch.float) + self._test_mdconv(torch.half) + + # test amp when torch version >= '1.6.0', the type of + # input data for mdconv might be torch.float or torch.half + if (TORCH_VERSION != 'parrots' + and digit_version(TORCH_VERSION) >= digit_version('1.6.0')): + with autocast(enabled=True): + self._test_amp_mdconv(torch.float) + self._test_amp_mdconv(torch.half) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_ms_deformable_attn.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_ms_deformable_attn.py new file mode 100644 index 000000000..a29380552 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_ms_deformable_attn.py @@ -0,0 +1,244 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops.multi_scale_deform_attn import ( + MultiScaleDeformableAttention, MultiScaleDeformableAttnFunction, + multi_scale_deformable_attn_pytorch) +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE + +_USING_PARROTS = True +try: + from parrots.autograd import gradcheck +except ImportError: + from torch.autograd import gradcheck + _USING_PARROTS = False + + +@pytest.mark.parametrize('device', [ + 'cpu', + pytest.param( + 'cuda:0', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) +]) +def test_multiscale_deformable_attention(device): + with pytest.raises(ValueError): + # embed_dims must be divisible by num_heads, + MultiScaleDeformableAttention( + embed_dims=256, + num_heads=7, + ) + device = torch.device(device) + msda = MultiScaleDeformableAttention( + embed_dims=3, num_levels=2, num_heads=3) + msda.init_weights() + num_query = 5 + bs = 1 + embed_dims = 3 + query = torch.rand(num_query, bs, embed_dims).to(device) + key = torch.rand(num_query, bs, embed_dims).to(device) + spatial_shapes = torch.Tensor([[2, 2], [1, 1]]).long().to(device) + level_start_index = torch.Tensor([0, 4]).long().to(device) + reference_points = torch.rand(bs, num_query, 2, 2).to(device) + msda.to(device) + msda( + query, + key, + key, + reference_points=reference_points, + spatial_shapes=spatial_shapes, + level_start_index=level_start_index) + + # test with value_proj_ratio + embed_dims = 6 + value_proj_ratio = 0.5 + query = torch.rand(num_query, bs, embed_dims).to(device) + key = torch.rand(num_query, bs, embed_dims).to(device) + msda = MultiScaleDeformableAttention( + embed_dims=embed_dims, + num_levels=2, + num_heads=3, + value_proj_ratio=value_proj_ratio) + msda.init_weights() + msda.to(device) + msda( + query, + key, + key, + reference_points=reference_points, + spatial_shapes=spatial_shapes, + level_start_index=level_start_index) + + +def test_forward_multi_scale_deformable_attn_pytorch(): + N, M, D = 1, 2, 2 + Lq, L, P = 2, 2, 2 + shapes = torch.as_tensor([(6, 4), (3, 2)], dtype=torch.long) + S = sum((H * W).item() for H, W in shapes) + + torch.manual_seed(3) + value = torch.rand(N, S, M, D) * 0.01 + sampling_locations = torch.rand(N, Lq, M, L, P, 2) + attention_weights = torch.rand(N, Lq, M, L, P) + 1e-5 + attention_weights /= attention_weights.sum( + -1, keepdim=True).sum( + -2, keepdim=True) + + multi_scale_deformable_attn_pytorch(value.double(), shapes, + sampling_locations.double(), + attention_weights.double()).detach() + + +@pytest.mark.skipif(not IS_CUDA_AVAILABLE, reason='requires CUDA support') +def test_forward_equal_with_pytorch_double(): + N, M, D = 1, 2, 2 + Lq, L, P = 2, 2, 2 + shapes = torch.as_tensor([(6, 4), (3, 2)], dtype=torch.long) + level_start_index = torch.cat((shapes.new_zeros( + (1, )), shapes.prod(1).cumsum(0)[:-1])) + S = sum((H * W).item() for H, W in shapes) + + torch.manual_seed(3) + value = torch.rand(N, S, M, D) * 0.01 + sampling_locations = torch.rand(N, Lq, M, L, P, 2) + attention_weights = torch.rand(N, Lq, M, L, P) + 1e-5 + attention_weights /= attention_weights.sum( + -1, keepdim=True).sum( + -2, keepdim=True) + im2col_step = 2 + output_pytorch = multi_scale_deformable_attn_pytorch( + value.double(), shapes, sampling_locations.double(), + attention_weights.double()).detach().cpu() + + output_cuda = MultiScaleDeformableAttnFunction.apply( + value.cuda().double(), shapes.cuda(), level_start_index.cuda(), + sampling_locations.cuda().double(), + attention_weights.cuda().double(), im2col_step).detach().cpu() + assert torch.allclose(output_cuda, output_pytorch) + max_abs_err = (output_cuda - output_pytorch).abs().max() + max_rel_err = ((output_cuda - output_pytorch).abs() / + output_pytorch.abs()).max() + assert max_abs_err < 1e-18 + assert max_rel_err < 1e-15 + + +@pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) +]) +def test_forward_equal_with_pytorch_float(device): + N, M, D = 1, 2, 2 + Lq, L, P = 2, 2, 2 + shapes = torch.as_tensor([(6, 4), (3, 2)], dtype=torch.long) + level_start_index = torch.cat((shapes.new_zeros( + (1, )), shapes.prod(1).cumsum(0)[:-1])) + S = sum((H * W).item() for H, W in shapes) + + torch.manual_seed(3) + value = torch.rand(N, S, M, D) * 0.01 + sampling_locations = torch.rand(N, Lq, M, L, P, 2) + attention_weights = torch.rand(N, Lq, M, L, P) + 1e-5 + attention_weights /= attention_weights.sum( + -1, keepdim=True).sum( + -2, keepdim=True) + im2col_step = 2 + output_pytorch = multi_scale_deformable_attn_pytorch( + value, shapes, sampling_locations, attention_weights).detach().cpu() + + output_device = MultiScaleDeformableAttnFunction.apply( + value.to(device), shapes.to(device), level_start_index.to(device), + sampling_locations.to(device), attention_weights.to(device), + im2col_step).detach().cpu() + assert torch.allclose(output_device, output_pytorch, rtol=1e-2, atol=1e-3) + max_abs_err = (output_device - output_pytorch).abs().max() + max_rel_err = ((output_device - output_pytorch).abs() / + output_pytorch.abs()).max() + assert max_abs_err < 1e-9 + assert max_rel_err < 1e-6 + + +@pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) +]) +@pytest.mark.parametrize('dtype', [ + torch.float, + pytest.param( + torch.double, + marks=pytest.mark.skipif( + IS_MLU_AVAILABLE, + reason='MLU does not support for 64-bit floating point')), + torch.half +]) +@pytest.mark.parametrize('channels', [ + 4, + 30, + 32, + 64, + 71, + 1025, +]) +def test_gradient_numerical(channels, + device, + dtype, + grad_value=True, + grad_sampling_loc=True, + grad_attn_weight=True): + + N, M, _ = 1, 2, 2 + Lq, L, P = 2, 2, 2 + shapes = torch.as_tensor([(3, 2), (2, 1)], dtype=torch.long).to(device) + level_start_index = torch.cat((shapes.new_zeros( + (1, )), shapes.prod(1).cumsum(0)[:-1])) + S = sum((H * W).item() for H, W in shapes) + + value = torch.rand(N, S, M, channels).to(device) * 0.01 + sampling_locations = torch.rand(N, Lq, M, L, P, 2).to(device) + attention_weights = torch.rand(N, Lq, M, L, P).to(device) + 1e-5 + attention_weights /= attention_weights.sum( + -1, keepdim=True).sum( + -2, keepdim=True) + im2col_step = 2 + + func = MultiScaleDeformableAttnFunction.apply + + value.requires_grad = grad_value + sampling_locations.requires_grad = grad_sampling_loc + attention_weights.requires_grad = grad_attn_weight + if device == 'cuda': + dtype = torch.double + eps = 1e-6 + elif device == 'mlu': + dtype = torch.float + eps = 1e-4 + if _USING_PARROTS: + assert gradcheck( + func, (value.to(dtype), shapes, level_start_index, + sampling_locations.to(dtype), attention_weights.to(dtype), + im2col_step), + no_grads=[shapes, level_start_index], + eps=eps) + else: + assert gradcheck( + func, (value.to(dtype), shapes, level_start_index, + sampling_locations.to(dtype), attention_weights.to(dtype), + im2col_step), + eps=eps, + atol=1e-2) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_nms.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_nms.py new file mode 100644 index 000000000..9f1ac65d6 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_nms.py @@ -0,0 +1,205 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import mmengine +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE + + +class Testnms: + + @pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) + ]) + def test_nms_allclose(self, device): + from mmcv.ops import nms + np_boxes = np.array([[6.0, 3.0, 8.0, 7.0], [3.0, 6.0, 9.0, 11.0], + [3.0, 7.0, 10.0, 12.0], [1.0, 4.0, 13.0, 7.0]], + dtype=np.float32) + np_scores = np.array([0.6, 0.9, 0.7, 0.2], dtype=np.float32) + np_inds = np.array([1, 0, 3]) + np_dets = np.array([[3.0, 6.0, 9.0, 11.0, 0.9], + [6.0, 3.0, 8.0, 7.0, 0.6], + [1.0, 4.0, 13.0, 7.0, 0.2]]) + boxes = torch.from_numpy(np_boxes) + scores = torch.from_numpy(np_scores) + dets, inds = nms(boxes, scores, iou_threshold=0.3, offset=0) + assert np.allclose(dets, np_dets) # test cpu + assert np.allclose(inds, np_inds) # test cpu + dets, inds = nms( + boxes.to(device), scores.to(device), iou_threshold=0.3, offset=0) + assert np.allclose(dets.cpu().numpy(), np_dets) # test gpu + assert np.allclose(inds.cpu().numpy(), np_inds) # test gpu + + def test_softnms_allclose(self): + if not torch.cuda.is_available(): + return + from mmcv.ops import soft_nms + np_boxes = np.array([[6.0, 3.0, 8.0, 7.0], [3.0, 6.0, 9.0, 11.0], + [3.0, 7.0, 10.0, 12.0], [1.0, 4.0, 13.0, 7.0]], + dtype=np.float32) + np_scores = np.array([0.6, 0.9, 0.7, 0.2], dtype=np.float32) + + np_output = { + 'linear': { + 'dets': + np.array( + [[3., 6., 9., 11., 0.9], [6., 3., 8., 7., 0.6], + [3., 7., 10., 12., 0.29024392], [1., 4., 13., 7., 0.2]], + dtype=np.float32), + 'inds': + np.array([1, 0, 2, 3], dtype=np.int64) + }, + 'gaussian': { + 'dets': + np.array([[3., 6., 9., 11., 0.9], [6., 3., 8., 7., 0.59630775], + [3., 7., 10., 12., 0.35275510], + [1., 4., 13., 7., 0.18650459]], + dtype=np.float32), + 'inds': + np.array([1, 0, 2, 3], dtype=np.int64) + }, + 'naive': { + 'dets': + np.array([[3., 6., 9., 11., 0.9], [6., 3., 8., 7., 0.6], + [1., 4., 13., 7., 0.2]], + dtype=np.float32), + 'inds': + np.array([1, 0, 3], dtype=np.int64) + } + } + + boxes = torch.from_numpy(np_boxes) + scores = torch.from_numpy(np_scores) + + configs = [[0.3, 0.5, 0.01, 'linear'], [0.3, 0.5, 0.01, 'gaussian'], + [0.3, 0.5, 0.01, 'naive']] + + for iou, sig, mscore, m in configs: + dets, inds = soft_nms( + boxes, + scores, + iou_threshold=iou, + sigma=sig, + min_score=mscore, + method=m) + assert np.allclose(dets.cpu().numpy(), np_output[m]['dets']) + assert np.allclose(inds.cpu().numpy(), np_output[m]['inds']) + + if torch.__version__ != 'parrots': + boxes = boxes.cuda() + scores = scores.cuda() + for iou, sig, mscore, m in configs: + dets, inds = soft_nms( + boxes, + scores, + iou_threshold=iou, + sigma=sig, + min_score=mscore, + method=m) + assert np.allclose(dets.cpu().numpy(), np_output[m]['dets']) + assert np.allclose(inds.cpu().numpy(), np_output[m]['inds']) + + def test_nms_match(self): + if not torch.cuda.is_available(): + return + from mmcv.ops import nms, nms_match + iou_thr = 0.6 + # empty input + empty_dets = np.array([]) + assert len(nms_match(empty_dets, iou_thr)) == 0 + + # non empty ndarray input + np_dets = np.array( + [[49.1, 32.4, 51.0, 35.9, 0.9], [49.3, 32.9, 51.0, 35.3, 0.9], + [35.3, 11.5, 39.9, 14.5, 0.4], [35.2, 11.7, 39.7, 15.7, 0.3]], + dtype=np.float32) + np_groups = nms_match(np_dets, iou_thr) + assert isinstance(np_groups[0], np.ndarray) + assert len(np_groups) == 2 + tensor_dets = torch.from_numpy(np_dets) + boxes = tensor_dets[:, :4] + scores = tensor_dets[:, 4] + nms_keep_inds = nms(boxes.contiguous(), scores.contiguous(), + iou_thr)[1] + assert {g[0].item() for g in np_groups} == set(nms_keep_inds.tolist()) + + # non empty tensor input + tensor_dets = torch.from_numpy(np_dets) + tensor_groups = nms_match(tensor_dets, iou_thr) + assert isinstance(tensor_groups[0], torch.Tensor) + for i in range(len(tensor_groups)): + assert np.equal(tensor_groups[i].numpy(), np_groups[i]).all() + + # input of wrong shape + wrong_dets = np.zeros((2, 3)) + with pytest.raises(AssertionError): + nms_match(wrong_dets, iou_thr) + + def test_batched_nms(self): + from mmcv.ops import batched_nms + results = mmengine.load('./tests/data/batched_nms_data.pkl') + + nms_max_num = 100 + nms_cfg = dict( + type='nms', + iou_threshold=0.7, + score_threshold=0.5, + max_num=nms_max_num) + boxes, keep = batched_nms( + torch.from_numpy(results['boxes']), + torch.from_numpy(results['scores']), + torch.from_numpy(results['idxs']), + nms_cfg, + class_agnostic=False) + + nms_cfg.update(split_thr=100) + seq_boxes, seq_keep = batched_nms( + torch.from_numpy(results['boxes']), + torch.from_numpy(results['scores']), + torch.from_numpy(results['idxs']), + nms_cfg, + class_agnostic=False) + + assert torch.equal(keep, seq_keep) + assert torch.equal(boxes, seq_boxes) + assert torch.equal(keep, + torch.from_numpy(results['keep'][:nms_max_num])) + + nms_cfg = dict(type='soft_nms', iou_threshold=0.7) + boxes, keep = batched_nms( + torch.from_numpy(results['boxes']), + torch.from_numpy(results['scores']), + torch.from_numpy(results['idxs']), + nms_cfg, + class_agnostic=False) + + nms_cfg.update(split_thr=100) + seq_boxes, seq_keep = batched_nms( + torch.from_numpy(results['boxes']), + torch.from_numpy(results['scores']), + torch.from_numpy(results['idxs']), + nms_cfg, + class_agnostic=False) + + assert torch.equal(keep, seq_keep) + assert torch.equal(boxes, seq_boxes) + + # test skip nms when `nms_cfg` is None + seq_boxes, seq_keep = batched_nms( + torch.from_numpy(results['boxes']), + torch.from_numpy(results['scores']), + torch.from_numpy(results['idxs']), + None, + class_agnostic=False) + assert len(seq_keep) == len(results['boxes']) + # assert score is descending order + assert ((seq_boxes[:, -1][1:] - seq_boxes[:, -1][:-1]) < 0).all() diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_nms_quadri.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_nms_quadri.py new file mode 100644 index 000000000..51f91f062 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_nms_quadri.py @@ -0,0 +1,119 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE + + +class TestNMSQuadri: + + @pytest.mark.parametrize('device', [ + 'cpu', + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + ]) + def test_ml_nms_quadri(self, device): + from mmcv.ops import nms_quadri + np_boxes = np.array([[1.0, 1.0, 3.0, 4.0, 4.0, 4.0, 4.0, 1.0, 0.7], + [2.0, 2.0, 3.0, 4.0, 4.0, 2.0, 3.0, 1.0, 0.8], + [7.0, 7.0, 8.0, 8.0, 9.0, 7.0, 8.0, 6.0, 0.5], + [0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 2.0, 0.0, 0.9]], + dtype=np.float32) + np_labels = np.array([1, 0, 1, 0], dtype=np.float32) + + np_expect_dets = np.array([[0., 0., 0., 2., 2., 2., 2., 0.], + [2., 2., 3., 4., 4., 2., 3., 1.], + [7., 7., 8., 8., 9., 7., 8., 6.]], + dtype=np.float32) + np_expect_keep_inds = np.array([3, 1, 2], dtype=np.int64) + + boxes = torch.from_numpy(np_boxes).to(device) + labels = torch.from_numpy(np_labels).to(device) + + dets, keep_inds = nms_quadri(boxes[:, :8], boxes[:, -1], 0.3, labels) + + assert np.allclose(dets.cpu().numpy()[:, :8], np_expect_dets) + assert np.allclose(keep_inds.cpu().numpy(), np_expect_keep_inds) + + @pytest.mark.parametrize('device', [ + 'cpu', + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + ]) + def test_nms_quadri(self, device): + from mmcv.ops import nms_quadri + np_boxes = np.array([[1.0, 1.0, 3.0, 4.0, 4.0, 4.0, 4.0, 1.0, 0.7], + [2.0, 2.0, 3.0, 4.0, 4.0, 2.0, 3.0, 1.0, 0.8], + [7.0, 7.0, 8.0, 8.0, 9.0, 7.0, 8.0, 6.0, 0.5], + [0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 2.0, 0.0, 0.9]], + dtype=np.float32) + + np_expect_dets = np.array([[0., 0., 0., 2., 2., 2., 2., 0.], + [2., 2., 3., 4., 4., 2., 3., 1.], + [7., 7., 8., 8., 9., 7., 8., 6.]], + dtype=np.float32) + np_expect_keep_inds = np.array([3, 1, 2], dtype=np.int64) + + boxes = torch.from_numpy(np_boxes).to(device) + + dets, keep_inds = nms_quadri(boxes[:, :8], boxes[:, -1], 0.3) + assert np.allclose(dets.cpu().numpy()[:, :8], np_expect_dets) + assert np.allclose(keep_inds.cpu().numpy(), np_expect_keep_inds) + + @pytest.mark.parametrize('device', [ + 'cpu', + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + ]) + def test_batched_nms(self, device): + # test batched_nms with nms_quadri + from mmcv.ops import batched_nms + + np_boxes = np.array([[1.0, 1.0, 3.0, 4.0, 4.0, 4.0, 4.0, 1.0, 0.7], + [2.0, 2.0, 3.0, 4.0, 4.0, 2.0, 3.0, 1.0, 0.8], + [7.0, 7.0, 8.0, 8.0, 9.0, 7.0, 8.0, 6.0, 0.5], + [0.0, 0.0, 0.0, 2.0, 2.0, 2.0, 2.0, 0.0, 0.9]], + dtype=np.float32) + np_labels = np.array([1, 0, 1, 0], dtype=np.float32) + + np_expect_agnostic_dets = np.array([[0., 0., 0., 2., 2., 2., 2., 0.], + [2., 2., 3., 4., 4., 2., 3., 1.], + [7., 7., 8., 8., 9., 7., 8., 6.]], + dtype=np.float32) + np_expect_agnostic_keep_inds = np.array([3, 1, 2], dtype=np.int64) + + np_expect_dets = np.array([[0., 0., 0., 2., 2., 2., 2., 0.], + [2., 2., 3., 4., 4., 2., 3., 1.], + [1., 1., 3., 4., 4., 4., 4., 1.], + [7., 7., 8., 8., 9., 7., 8., 6.]], + dtype=np.float32) + np_expect_keep_inds = np.array([3, 1, 0, 2], dtype=np.int64) + + nms_cfg = dict(type='nms_quadri', iou_threshold=0.3) + + # test class_agnostic is True + boxes, keep = batched_nms( + torch.from_numpy(np_boxes[:, :8]).to(device), + torch.from_numpy(np_boxes[:, -1]).to(device), + torch.from_numpy(np_labels).to(device), + nms_cfg, + class_agnostic=True) + assert np.allclose(boxes.cpu().numpy()[:, :8], np_expect_agnostic_dets) + assert np.allclose(keep.cpu().numpy(), np_expect_agnostic_keep_inds) + + # test class_agnostic is False + boxes, keep = batched_nms( + torch.from_numpy(np_boxes[:, :8]).to(device), + torch.from_numpy(np_boxes[:, -1]).to(device), + torch.from_numpy(np_labels).to(device), + nms_cfg, + class_agnostic=False) + assert np.allclose(boxes.cpu().numpy()[:, :8], np_expect_dets) + assert np.allclose(keep.cpu().numpy(), np_expect_keep_inds) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_nms_rotated.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_nms_rotated.py new file mode 100644 index 000000000..1b7f3607b --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_nms_rotated.py @@ -0,0 +1,116 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + + +@pytest.mark.skipif( + not torch.cuda.is_available(), + reason='GPU is required to test NMSRotated op') +class TestNmsRotated: + + def test_ml_nms_rotated(self): + from mmcv.ops import nms_rotated + np_boxes = np.array( + [[6.0, 3.0, 8.0, 7.0, 0.5, 0.7], [3.0, 6.0, 9.0, 11.0, 0.6, 0.8], + [3.0, 7.0, 10.0, 12.0, 0.3, 0.5], [1.0, 4.0, 13.0, 7.0, 0.6, 0.9] + ], + dtype=np.float32) + np_labels = np.array([1, 0, 1, 0], dtype=np.float32) + + np_expect_dets = np.array( + [[1.0, 4.0, 13.0, 7.0, 0.6], [3.0, 6.0, 9.0, 11.0, 0.6], + [6.0, 3.0, 8.0, 7.0, 0.5]], + dtype=np.float32) + np_expect_keep_inds = np.array([3, 1, 0], dtype=np.int64) + + boxes = torch.from_numpy(np_boxes).cuda() + labels = torch.from_numpy(np_labels).cuda() + + # test cw angle definition + dets, keep_inds = nms_rotated(boxes[:, :5], boxes[:, -1], 0.5, labels) + + assert np.allclose(dets.cpu().numpy()[:, :5], np_expect_dets) + assert np.allclose(keep_inds.cpu().numpy(), np_expect_keep_inds) + + # test ccw angle definition + boxes[..., -2] *= -1 + dets, keep_inds = nms_rotated( + boxes[:, :5], boxes[:, -1], 0.5, labels, clockwise=False) + dets[..., -2] *= -1 + assert np.allclose(dets.cpu().numpy()[:, :5], np_expect_dets) + assert np.allclose(keep_inds.cpu().numpy(), np_expect_keep_inds) + + def test_nms_rotated(self): + from mmcv.ops import nms_rotated + np_boxes = np.array( + [[6.0, 3.0, 8.0, 7.0, 0.5, 0.7], [3.0, 6.0, 9.0, 11.0, 0.6, 0.8], + [3.0, 7.0, 10.0, 12.0, 0.3, 0.5], [1.0, 4.0, 13.0, 7.0, 0.6, 0.9] + ], + dtype=np.float32) + + np_expect_dets = np.array( + [[1.0, 4.0, 13.0, 7.0, 0.6], [3.0, 6.0, 9.0, 11.0, 0.6], + [6.0, 3.0, 8.0, 7.0, 0.5]], + dtype=np.float32) + np_expect_keep_inds = np.array([3, 1, 0], dtype=np.int64) + + boxes = torch.from_numpy(np_boxes).cuda() + + # test cw angle definition + dets, keep_inds = nms_rotated(boxes[:, :5], boxes[:, -1], 0.5) + assert np.allclose(dets.cpu().numpy()[:, :5], np_expect_dets) + assert np.allclose(keep_inds.cpu().numpy(), np_expect_keep_inds) + + # test ccw angle definition + boxes[..., -2] *= -1 + dets, keep_inds = nms_rotated( + boxes[:, :5], boxes[:, -1], 0.5, clockwise=False) + dets[..., -2] *= -1 + assert np.allclose(dets.cpu().numpy()[:, :5], np_expect_dets) + assert np.allclose(keep_inds.cpu().numpy(), np_expect_keep_inds) + + def test_batched_nms(self): + # test batched_nms with nms_rotated + from mmcv.ops import batched_nms + + np_boxes = np.array( + [[6.0, 3.0, 8.0, 7.0, 0.5, 0.7], [3.0, 6.0, 9.0, 11.0, 0.6, 0.8], + [3.0, 7.0, 10.0, 12.0, 0.3, 0.5], [1.0, 4.0, 13.0, 7.0, 0.6, 0.9] + ], + dtype=np.float32) + np_labels = np.array([1, 0, 1, 0], dtype=np.float32) + + np_expect_agnostic_dets = np.array( + [[1.0, 4.0, 13.0, 7.0, 0.6], [3.0, 6.0, 9.0, 11.0, 0.6], + [6.0, 3.0, 8.0, 7.0, 0.5]], + dtype=np.float32) + np_expect_agnostic_keep_inds = np.array([3, 1, 0], dtype=np.int64) + + np_expect_dets = np.array( + [[1.0, 4.0, 13.0, 7.0, 0.6], [3.0, 6.0, 9.0, 11.0, 0.6], + [6.0, 3.0, 8.0, 7.0, 0.5], [3.0, 7.0, 10.0, 12.0, 0.3]], + dtype=np.float32) + np_expect_keep_inds = np.array([3, 1, 0, 2], dtype=np.int64) + + nms_cfg = dict(type='nms_rotated', iou_threshold=0.5) + + # test class_agnostic is True + boxes, keep = batched_nms( + torch.from_numpy(np_boxes[:, :5]), + torch.from_numpy(np_boxes[:, -1]), + torch.from_numpy(np_labels), + nms_cfg, + class_agnostic=True) + assert np.allclose(boxes.cpu().numpy()[:, :5], np_expect_agnostic_dets) + assert np.allclose(keep.cpu().numpy(), np_expect_agnostic_keep_inds) + + # test class_agnostic is False + boxes, keep = batched_nms( + torch.from_numpy(np_boxes[:, :5]), + torch.from_numpy(np_boxes[:, -1]), + torch.from_numpy(np_labels), + nms_cfg, + class_agnostic=False) + assert np.allclose(boxes.cpu().numpy()[:, :5], np_expect_dets) + assert np.allclose(keep.cpu().numpy(), np_expect_keep_inds) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_onnx.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_onnx.py new file mode 100644 index 000000000..719721752 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_onnx.py @@ -0,0 +1,286 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os + +import numpy as np +import onnx +import onnxruntime as rt +import pytest +import torch +import torch.nn as nn + +onnx_file = 'tmp.onnx' +if torch.__version__ == 'parrots': + pytest.skip('not supported in parrots now', allow_module_level=True) + + +@pytest.fixture(autouse=True) +def run_before_and_after_test(): + # clear onnx_file before test + if os.path.exists(onnx_file): + os.remove(onnx_file) + + yield + + # clear onnx_file after test + if os.path.exists(onnx_file): + os.remove(onnx_file) + + +class WrapFunction(nn.Module): + + def __init__(self, wrapped_function): + super().__init__() + self.wrapped_function = wrapped_function + + def forward(self, *args, **kwargs): + return self.wrapped_function(*args, **kwargs) + + +def test_roialign(): + try: + from mmcv.ops import roi_align + except (ImportError, ModuleNotFoundError): + pytest.skip('roi_align op is not successfully compiled') + + # roi align config + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + sampling_ratio = 2 + + inputs = [([[[[1., 2.], [3., 4.]]]], [[0., 0., 0., 1., 1.]]), + ([[[[1., 2.], [3., 4.]], [[4., 3.], + [2., 1.]]]], [[0., 0., 0., 1., 1.]]), + ([[[[1., 2., 5., 6.], [3., 4., 7., 8.], [9., 10., 13., 14.], + [11., 12., 15., 16.]]]], [[0., 0., 0., 3., 3.]])] + + def warpped_function(torch_input, torch_rois): + return roi_align(torch_input, torch_rois, (pool_w, pool_h), + spatial_scale, sampling_ratio, 'avg', True) + + for case in inputs: + np_input = np.array(case[0], dtype=np.float32) + np_rois = np.array(case[1], dtype=np.float32) + input = torch.from_numpy(np_input) + rois = torch.from_numpy(np_rois) + + # compute pytorch_output + with torch.no_grad(): + pytorch_output = roi_align(input, rois, (pool_w, pool_h), + spatial_scale, sampling_ratio, 'avg', + True) + + # export and load onnx model + wrapped_model = WrapFunction(warpped_function) + with torch.no_grad(): + torch.onnx.export( + wrapped_model, (input, rois), + onnx_file, + export_params=True, + keep_initializers_as_inputs=True, + input_names=['input', 'rois'], + opset_version=11) + + onnx_model = onnx.load(onnx_file) + session_options = rt.SessionOptions() + + # compute onnx_output + input_all = [node.name for node in onnx_model.graph.input] + input_initializer = [ + node.name for node in onnx_model.graph.initializer + ] + net_feed_input = list(set(input_all) - set(input_initializer)) + assert (len(net_feed_input) == 2) + sess = rt.InferenceSession( + onnx_file, session_options, providers=['CPUExecutionProvider']) + onnx_output = sess.run(None, { + 'input': input.detach().numpy(), + 'rois': rois.detach().numpy() + }) + onnx_output = onnx_output[0] + + # allclose + + assert np.allclose(pytorch_output, onnx_output, atol=1e-3) + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') +def test_roipool(): + from mmcv.ops import roi_pool + + # roi pool config + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + + inputs = [([[[[1., 2.], [3., 4.]]]], [[0., 0., 0., 1., 1.]]), + ([[[[1., 2.], [3., 4.]], [[4., 3.], + [2., 1.]]]], [[0., 0., 0., 1., 1.]]), + ([[[[1., 2., 5., 6.], [3., 4., 7., 8.], [9., 10., 13., 14.], + [11., 12., 15., 16.]]]], [[0., 0., 0., 3., 3.]])] + + def warpped_function(torch_input, torch_rois): + return roi_pool(torch_input, torch_rois, (pool_w, pool_h), + spatial_scale) + + for case in inputs: + np_input = np.array(case[0], dtype=np.float32) + np_rois = np.array(case[1], dtype=np.float32) + input = torch.from_numpy(np_input).cuda() + rois = torch.from_numpy(np_rois).cuda() + + # compute pytorch_output + with torch.no_grad(): + pytorch_output = roi_pool(input, rois, (pool_w, pool_h), + spatial_scale) + pytorch_output = pytorch_output.cpu() + + # export and load onnx model + wrapped_model = WrapFunction(warpped_function) + with torch.no_grad(): + torch.onnx.export( + wrapped_model, (input, rois), + onnx_file, + export_params=True, + keep_initializers_as_inputs=True, + input_names=['input', 'rois'], + opset_version=11) + onnx_model = onnx.load(onnx_file) + + # compute onnx_output + input_all = [node.name for node in onnx_model.graph.input] + input_initializer = [ + node.name for node in onnx_model.graph.initializer + ] + net_feed_input = list(set(input_all) - set(input_initializer)) + assert (len(net_feed_input) == 2) + sess = rt.InferenceSession( + onnx_file, providers=['CPUExecutionProvider']) + onnx_output = sess.run( + None, { + 'input': input.detach().cpu().numpy(), + 'rois': rois.detach().cpu().numpy() + }) + onnx_output = onnx_output[0] + + # allclose + assert np.allclose(pytorch_output, onnx_output, atol=1e-3) + + +def _test_symbolic(model, inputs, symbol_name): + with torch.no_grad(): + torch.onnx.export(model, inputs, onnx_file, opset_version=11) + + import onnx + model = onnx.load(onnx_file) + nodes = model.graph.node + + symbol_exist = False + for n in nodes: + if n.op_type == symbol_name: + symbol_exist = True + assert symbol_exist + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') +def test_border_align(): + from mmcv.ops import BorderAlign + model = BorderAlign(2) + input = torch.rand(1, 8, 2, 2).cuda() + boxes = torch.rand(1, 4, 4).cuda() + _test_symbolic(model, (input, boxes), 'MMCVBorderAlign') + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') +def test_carafe(): + from mmcv.ops import CARAFENaive + feat = torch.randn(2, 64, 3, 3, device='cuda').double() + mask = torch.randn(2, 100, 6, 6, device='cuda').sigmoid().double() + _test_symbolic(CARAFENaive(5, 4, 2), (feat, mask), 'MMCVCARAFENaive') + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') +def test_deform_conv(): + from mmcv.ops import DeformConv2dPack + x = torch.randn(1, 2, 4, 4, device='cuda') + _test_symbolic( + DeformConv2dPack(2, 4, 3, 1, 1).cuda(), x, 'MMCVDeformConv2d') + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') +def test_modulated_deform_conv(): + from mmcv.ops import ModulatedDeformConv2dPack + x = torch.randn(1, 2, 4, 4, device='cuda') + _test_symbolic( + ModulatedDeformConv2dPack(2, 4, 3, 1, 1).cuda(), x, + 'MMCVModulatedDeformConv2d') + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') +def test_deform_roi_pool(): + from mmcv.ops import DeformRoIPoolPack + x = torch.tensor([[[[1., 2.], [3., 4.]]]], device='cuda') + rois = torch.tensor([[0., 0., 0., 1., 1.]], device='cuda') + output_c = x.size(1) + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + sampling_ratio = 2 + model = DeformRoIPoolPack((pool_h, pool_w), + output_c, + spatial_scale=spatial_scale, + sampling_ratio=sampling_ratio).cuda() + + _test_symbolic(model, (x, rois), 'MMCVDeformRoIPool') + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') +def test_masked_conv(): + from mmcv.ops import MaskedConv2d + x = torch.rand(1, 2, 4, 4, device='cuda') + mask = torch.rand(1, 4, 4, device='cuda') + _test_symbolic( + MaskedConv2d(2, 4, 3, 1, 1).cuda(), (x, mask), 'MMCVMaskedConv2d') + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') +def test_pr_roi_pool(): + from mmcv.ops import PrRoIPool + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + x = torch.tensor([[[[1., 2.], [3., 4.]]]], device='cuda') + rois = torch.tensor([[0., 0., 0., 1., 1.]], device='cuda') + model = PrRoIPool((pool_h, pool_w), spatial_scale).cuda() + _test_symbolic(model, (x, rois), 'PrRoIPool') + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') +def test_psa_mask(): + from mmcv.ops import PSAMask + input = torch.rand(4, 16, 8, 8).cuda() + model = PSAMask('collect', (4, 4)).cuda() + _test_symbolic(model, input, 'MMCVPSAMask') + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') +def test_roi_align_rotated(): + from mmcv.ops import RoIAlignRotated + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + sampling_ratio = 2 + x = torch.tensor([[[[1., 2.], [3., 4.]]]], device='cuda') + rois = torch.tensor([[0., 0.5, 0.5, 1., 1., 0]], device='cuda') + model = RoIAlignRotated((pool_h, pool_w), spatial_scale, + sampling_ratio).cuda() + _test_symbolic(model, (x, rois), 'MMCVRoIAlignRotated') + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') +def test_roi_feaeture_align(): + from mmcv.ops import rotated_feature_align + wrapped_model = WrapFunction(rotated_feature_align) + feature = torch.rand(1, 1, 2, 2, device='cuda') + bbox = torch.rand(1, 2, 2, 5, device='cuda') + _test_symbolic(wrapped_model, (feature, bbox), 'MMCVRotatedFeatureAlign') diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_pixel_group.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_pixel_group.py new file mode 100644 index 000000000..ceb257365 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_pixel_group.py @@ -0,0 +1,78 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import torch + + +def test_pixel_group(): + from mmcv.ops import pixel_group + np_score = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0], + [0, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0], + [0, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0], + [0, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]).astype(np.float32) + np_mask = (np_score > 0.5) + np_embedding = np.zeros((10, 10, 8)).astype(np.float32) + np_embedding[:, :7] = 0.9 + np_embedding[:, 7:] = 10.0 + np_kernel_label = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 0, 0, 0, 2, 0], + [0, 0, 1, 1, 1, 0, 0, 0, 2, 0], + [0, 0, 1, 1, 1, 0, 0, 0, 2, 0], + [0, 0, 1, 1, 1, 0, 0, 0, 2, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, + 0]]).astype(np.int32) + np_kernel_contour = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 1, 1, 0, 0, 0, 1, 0], + [0, 0, 1, 0, 1, 0, 0, 0, 1, 0], + [0, 0, 1, 0, 1, 0, 0, 0, 1, 0], + [0, 0, 1, 1, 1, 0, 0, 0, 1, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, + 0]]).astype(np.uint8) + kernel_region_num = 3 + distance_threshold = float(0.8) + result = pixel_group(np_score, np_mask, np_embedding, np_kernel_label, + np_kernel_contour, kernel_region_num, + distance_threshold) + gt_1 = [ + 0.8999997973442078, 24.0, 1.0, 3.0, 2.0, 3.0, 3.0, 3.0, 4.0, 3.0, 5.0, + 3.0, 6.0, 3.0, 1.0, 4.0, 2.0, 4.0, 3.0, 4.0, 4.0, 4.0, 5.0, 4.0, 6.0, + 4.0, 1.0, 5.0, 2.0, 5.0, 3.0, 5.0, 4.0, 5.0, 5.0, 5.0, 6.0, 5.0, 1.0, + 6.0, 2.0, 6.0, 3.0, 6.0, 4.0, 6.0, 5.0, 6.0, 6.0, 6.0 + ] + + gt_2 = [ + 0.9000000357627869, 8.0, 7.0, 3.0, 8.0, 3.0, 7.0, 4.0, 8.0, 4.0, 7.0, + 5.0, 8.0, 5.0, 7.0, 6.0, 8.0, 6.0 + ] + + assert np.allclose(result[0], [0, 0]) + assert np.allclose(result[1], gt_1) + assert np.allclose(result[2], gt_2) + + # test torch Tensor + np_score_t = torch.from_numpy(np_score) + np_mask_t = torch.from_numpy(np_mask) + np_embedding_t = torch.from_numpy(np_embedding) + np_kernel_label_t = torch.from_numpy(np_kernel_label) + np_kernel_contour_t = torch.from_numpy(np_kernel_contour) + + result = pixel_group(np_score_t, np_mask_t, np_embedding_t, + np_kernel_label_t, np_kernel_contour_t, + kernel_region_num, distance_threshold) + + assert np.allclose(result[0], [0, 0]) + assert np.allclose(result[1], gt_1) + assert np.allclose(result[2], gt_2) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_points_in_polygons.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_points_in_polygons.py new file mode 100644 index 000000000..dde8ab023 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_points_in_polygons.py @@ -0,0 +1,23 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.ops import points_in_polygons + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_points_in_polygons(): + points = np.array([[300., 300.], [400., 400.], [100., 100], [300, 250], + [100, 0]]) + polygons = np.array([[200., 200., 400., 400., 500., 200., 400., 100.], + [400., 400., 500., 500., 600., 300., 500., 200.], + [300., 300., 600., 700., 700., 700., 700., 100.]]) + expected_output = np.array([[0., 0., 0.], [0., 0., 1.], [0., 0., 0.], + [1., 0., 0.], [0., 0., 0.]]) + points = torch.from_numpy(points).cuda().float() + polygons = torch.from_numpy(polygons).cuda().float() + expected_output = torch.from_numpy(expected_output).cuda().float() + assert torch.allclose( + points_in_polygons(points, polygons), expected_output, 1e-3) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_prroi_pool.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_prroi_pool.py new file mode 100644 index 000000000..0535dfbe2 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_prroi_pool.py @@ -0,0 +1,98 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE + +_USING_PARROTS = True +try: + from parrots.autograd import gradcheck +except ImportError: + from torch.autograd import gradcheck + + _USING_PARROTS = False + +inputs = [([[[[1., 2.], [3., 4.]]]], [[0., 0., 0., 1., 1.]]), + ([[[[1., 2.], [3., 4.]], [[4., 3.], [2., + 1.]]]], [[0., 0., 0., 1., 1.]]), + ([[[[1., 2., 5., 6.], [3., 4., 7., 8.], [9., 10., 13., 14.], + [11., 12., 15., 16.]]]], [[0., 0., 0., 3., 3.]])] +outputs = [ + ([[[[1.75, 2.25], [2.75, 3.25]]]], [[[[1., 1.], + [1., 1.]]]], [[0., 2., 4., 2., 4.]]), + ([[[[1.75, 2.25], [2.75, 3.25]], + [[3.25, 2.75], [2.25, 1.75]]]], [[[[1., 1.], [1., 1.]], + [[1., 1.], + [1., 1.]]]], [[0., 0., 0., 0., 0.]]), + ([[[[3.75, 6.91666651], + [10.08333302, + 13.25]]]], [[[[0.11111111, 0.22222224, 0.22222222, 0.11111111], + [0.22222224, 0.444444448, 0.44444448, 0.22222224], + [0.22222224, 0.44444448, 0.44444448, 0.22222224], + [0.11111111, 0.22222224, 0.22222224, 0.11111111]]]], + [[0.0, 3.33333302, 6.66666603, 3.33333349, 6.66666698]]) +] + + +class TestPrRoiPool: + + @pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')) + ]) + def test_roipool_gradcheck(self, device): + from mmcv.ops import PrRoIPool + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + + for case in inputs: + np_input = np.array(case[0], dtype=np.float32) + np_rois = np.array(case[1], dtype=np.float32) + + x = torch.tensor(np_input, device=device, requires_grad=True) + rois = torch.tensor(np_rois, device=device) + + froipool = PrRoIPool((pool_h, pool_w), spatial_scale) + + if _USING_PARROTS: + gradcheck(froipool, (x, rois), no_grads=[rois]) + else: + gradcheck(froipool, (x, rois), eps=1e-2, atol=1e-2) + + def _test_roipool_allclose(self, device, dtype=torch.float): + from mmcv.ops import prroi_pool + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + + for case, output in zip(inputs, outputs): + np_input = np.array(case[0], dtype=np.float32) + np_rois = np.array(case[1], dtype=np.float32) + np_output = np.array(output[0], dtype=np.float32) + np_input_grad = np.array(output[1], dtype=np.float32) + np_rois_grad = np.array(output[2], dtype=np.float32) + + x = torch.tensor( + np_input, dtype=dtype, device=device, requires_grad=True) + rois = torch.tensor( + np_rois, dtype=dtype, device=device, requires_grad=True) + + output = prroi_pool(x, rois, (pool_h, pool_w), spatial_scale) + output.backward(torch.ones_like(output)) + assert np.allclose(output.data.cpu().numpy(), np_output, 1e-3) + assert np.allclose(x.grad.data.cpu().numpy(), np_input_grad, 1e-3) + assert np.allclose(rois.grad.data.cpu().numpy(), np_rois_grad, + 1e-3) + + @pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')) + ]) + def test_roipool_allclose_float(self, device): + self._test_roipool_allclose(device, dtype=torch.float) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_psa_mask.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_psa_mask.py new file mode 100644 index 000000000..b0fd86e8f --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_psa_mask.py @@ -0,0 +1,126 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch +import torch.nn as nn + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE, IS_NPU_AVAILABLE + + +class Loss(nn.Module): + + def __init__(self): + super().__init__() + + def forward(self, input, target): + input = input.view(-1) + target = target.view(-1) + return torch.mean(input - target) + + +class TestPSAMask: + + @pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')), + pytest.param( + 'npu', + marks=pytest.mark.skipif( + not IS_NPU_AVAILABLE, reason='requires NPU support')) + ]) + def test_psa_mask_collect(self, device): + from mmcv.ops import PSAMask + test_loss = Loss() + + input = np.fromfile( + 'tests/data/for_psa_mask/psa_input.bin', dtype=np.float32) + output_collect = np.fromfile( + 'tests/data/for_psa_mask/psa_output_collect.bin', dtype=np.float32) + + input = input.reshape((4, 16, 8, 8)) + output_collect = output_collect.reshape((4, 64, 8, 8)) + label = torch.ones((4, 64, 8, 8)) + + input = torch.FloatTensor(input) + input.requires_grad = True + + psamask_collect = PSAMask('collect', (4, 4)) + + # test collect cpu + test_output = psamask_collect(input) + loss = test_loss(test_output, label) + loss.backward() + test_output = test_output.detach().numpy() + assert np.allclose(test_output, output_collect) + assert test_output.shape == output_collect.shape + + psamask_collect.to(device) + input = input.to(device) + label = label.to(device) + + # test collect on device + test_output = psamask_collect(input) + loss = test_loss(test_output, label) + loss.backward() + test_output = test_output.detach().cpu().numpy() + assert np.allclose(test_output, output_collect) + assert test_output.shape == output_collect.shape + + @pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')), + pytest.param( + 'npu', + marks=pytest.mark.skipif( + not IS_NPU_AVAILABLE, reason='requires NPU support')) + ]) + def test_psa_mask_distribute(self, device): + from mmcv.ops import PSAMask + test_loss = Loss() + + input = np.fromfile( + 'tests/data/for_psa_mask/psa_input.bin', dtype=np.float32) + output_distribute = np.fromfile( + 'tests/data/for_psa_mask/psa_output_distribute.bin', + dtype=np.float32) + + input = input.reshape((4, 16, 8, 8)) + output_distribute = output_distribute.reshape((4, 64, 8, 8)) + label = torch.ones((4, 64, 8, 8)) + + input = torch.FloatTensor(input) + input.requires_grad = True + + psamask_distribute = PSAMask('distribute', (4, 4)) + + # test distribute cpu + test_output = psamask_distribute(input) + loss = test_loss(test_output, label) + loss.backward() + test_output = test_output.detach().numpy() + assert np.allclose(test_output, output_distribute) + assert test_output.shape == output_distribute.shape + + psamask_distribute.to(device) + input = input.to(device) + label = label.to(device) + + # test distribute on device + test_output = psamask_distribute(input) + loss = test_loss(test_output, label) + loss.backward() + test_output = test_output.detach().cpu().numpy() + assert np.allclose(test_output, output_distribute) + assert test_output.shape == output_distribute.shape diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_riroi_align_rotated.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_riroi_align_rotated.py new file mode 100644 index 000000000..c7b501cf4 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_riroi_align_rotated.py @@ -0,0 +1,84 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.ops import RiRoIAlignRotated + +if torch.__version__ == 'parrots': + from parrots.autograd import gradcheck + _USING_PARROTS = True +else: + from torch.autograd import gradcheck + _USING_PARROTS = False + +np_feature = np.array([[[[1, 2], [3, 4]], [[1, 2], [4, 3]], [[4, 3], [2, 1]], + [[1, 2], [5, 6]], [[3, 4], [7, 8]], [[9, 10], [13, + 14]], + [[11, 12], [15, 16]], [[1, 1], [2, 2]]]]) +np_rois = np.array([[0., 0.5, 0.5, 1., 1., np.pi / 3], + [0., 1., 1., 3., 3., np.pi / 2]]) +expect_output = np.array([[[[1.8425, 1.3516], [2.3151, 1.8241]], + [[2.4779, 1.7416], [3.2173, 2.5632]], + [[2.7149, 2.2638], [2.6540, 2.3673]], + [[2.9461, 2.8638], [2.8028, 2.7205]], + [[4.1943, 2.7214], [5.6119, 4.1391]], + [[7.5276, 6.0547], [8.9453, 7.4724]], + [[12.1943, 10.7214], [13.6119, 12.1391]], + [[9.5489, 8.4237], [10.5763, 9.4511]]], + [[[7.6562, 12.5625], [4.0000, 6.6250]], + [[1.0000, 1.3125], [0.5000, 0.6562]], + [[1.6562, 1.9375], [1.0000, 1.3125]], + [[1.8438, 2.0547], [0.7500, 1.1562]], + [[0.8438, 3.0625], [0.2500, 1.1875]], + [[2.6562, 2.5625], [1.5000, 1.6250]], + [[3.6562, 4.5625], [2.0000, 2.6250]], + [[6.6562, 10.5625], [3.5000, 5.6250]]]]) + +expect_grad = np.array([[[[1.4727, 1.5586], [1.5586, 1.6602]], + [[1.4727, 1.5586], [1.5586, 1.6602]], + [[1.4727, 1.5586], [1.5586, 1.6602]], + [[1.4727, 1.5586], [1.5586, 1.6602]], + [[1.4727, 1.5586], [1.5586, 1.6602]], + [[1.4727, 1.5586], [1.5586, 1.6602]], + [[1.4727, 1.5586], [1.5586, 1.6602]], + [[1.4727, 1.5586], [1.5586, 1.6602]]]]) + +pool_h = 2 +pool_w = 2 +spatial_scale = 1.0 +num_samples = 2 +sampling_ratio = 2 +num_orientations = 8 +clockwise = False + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_roialign_rotated_gradcheck(): + x = torch.tensor( + np_feature, dtype=torch.float, device='cuda', requires_grad=True) + rois = torch.tensor(np_rois, dtype=torch.float, device='cuda') + froipool = RiRoIAlignRotated((pool_h, pool_w), spatial_scale, num_samples, + num_orientations, clockwise) + if _USING_PARROTS: + gradcheck( + froipool, (x, rois), no_grads=[rois], delta=1e-3, pt_atol=1e-3) + else: + gradcheck(froipool, (x, rois), eps=1e-3, atol=1e-3) + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_roialign_rotated_allclose(): + x = torch.tensor( + np_feature, dtype=torch.float, device='cuda', requires_grad=True) + rois = torch.tensor(np_rois, dtype=torch.float, device='cuda') + froipool = RiRoIAlignRotated((pool_h, pool_w), spatial_scale, num_samples, + num_orientations, clockwise) + output = froipool(x, rois) + output.backward(torch.ones_like(output)) + assert np.allclose( + output.data.type(torch.float).cpu().numpy(), expect_output, atol=1e-3) + assert np.allclose( + x.grad.data.type(torch.float).cpu().numpy(), expect_grad, atol=1e-3) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align.py new file mode 100644 index 000000000..6caf5c535 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align.py @@ -0,0 +1,120 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE + +_USING_PARROTS = True +try: + from parrots.autograd import gradcheck +except ImportError: + from torch.autograd import gradcheck + _USING_PARROTS = False + +# yapf:disable + +inputs = [([[[[1., 2.], [3., 4.]]]], + [[0., 0., 0., 1., 1.]]), + ([[[[1., 2.], [3., 4.]], + [[4., 3.], [2., 1.]]]], + [[0., 0., 0., 1., 1.]]), + ([[[[1., 2., 5., 6.], [3., 4., 7., 8.], + [9., 10., 13., 14.], [11., 12., 15., 16.]]]], + [[0., 0., 0., 3., 3.]])] +outputs = [([[[[1.0, 1.25], [1.5, 1.75]]]], + [[[[3.0625, 0.4375], [0.4375, 0.0625]]]]), + ([[[[1.0, 1.25], [1.5, 1.75]], + [[4.0, 3.75], [3.5, 3.25]]]], + [[[[3.0625, 0.4375], [0.4375, 0.0625]], + [[3.0625, 0.4375], [0.4375, 0.0625]]]]), + ([[[[1.9375, 4.75], [7.5625, 10.375]]]], + [[[[0.47265625, 0.42968750, 0.42968750, 0.04296875], + [0.42968750, 0.39062500, 0.39062500, 0.03906250], + [0.42968750, 0.39062500, 0.39062500, 0.03906250], + [0.04296875, 0.03906250, 0.03906250, 0.00390625]]]])] +# yapf:enable + +pool_h = 2 +pool_w = 2 +spatial_scale = 1.0 +sampling_ratio = 2 + + +def _test_roialign_gradcheck(device, dtype): + try: + from mmcv.ops import RoIAlign + except ModuleNotFoundError: + pytest.skip('RoIAlign op is not successfully compiled') + if dtype is torch.half: + pytest.skip('grad check does not support fp16') + for case in inputs: + np_input = np.array(case[0]) + np_rois = np.array(case[1]) + + x = torch.tensor( + np_input, dtype=dtype, device=device, requires_grad=True) + rois = torch.tensor(np_rois, dtype=dtype, device=device) + + froipool = RoIAlign((pool_h, pool_w), spatial_scale, sampling_ratio) + + if torch.__version__ == 'parrots': + gradcheck( + froipool, (x, rois), no_grads=[rois], delta=1e-5, pt_atol=1e-5) + else: + gradcheck(froipool, (x, rois), eps=1e-5, atol=1e-5) + + +def _test_roialign_allclose(device, dtype): + try: + from mmcv.ops import roi_align + except ModuleNotFoundError: + pytest.skip('test requires compilation') + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + sampling_ratio = 2 + for case, output in zip(inputs, outputs): + np_input = np.array(case[0]) + np_rois = np.array(case[1]) + np_output = np.array(output[0]) + np_grad = np.array(output[1]) + + x = torch.tensor( + np_input, dtype=dtype, device=device, requires_grad=True) + rois = torch.tensor(np_rois, dtype=dtype, device=device) + + output = roi_align(x, rois, (pool_h, pool_w), spatial_scale, + sampling_ratio, 'avg', True) + output.backward(torch.ones_like(output)) + assert np.allclose( + output.data.type(torch.float).cpu().numpy(), np_output, atol=1e-3) + assert np.allclose( + x.grad.data.type(torch.float).cpu().numpy(), np_grad, atol=1e-3) + + +@pytest.mark.parametrize('device', [ + 'cpu', + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) +]) +@pytest.mark.parametrize('dtype', [ + torch.float, + pytest.param( + torch.double, + marks=pytest.mark.skipif( + IS_MLU_AVAILABLE, + reason='MLU does not support for 64-bit floating point')), + torch.half +]) +def test_roialign(device, dtype): + # check double only + if dtype is torch.double: + _test_roialign_gradcheck(device=device, dtype=dtype) + _test_roialign_allclose(device=device, dtype=dtype) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align_rotated.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align_rotated.py new file mode 100644 index 000000000..1ad6b6e92 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align_rotated.py @@ -0,0 +1,151 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE + +_USING_PARROTS = True +try: + from parrots.autograd import gradcheck +except ImportError: + from torch.autograd import gradcheck + _USING_PARROTS = False + +# yapf:disable +inputs = [([[[[1., 2.], [3., 4.]]]], + [[0., 0.5, 0.5, 1., 1., 0]]), + ([[[[1., 2.], [3., 4.]]]], + [[0., 0.5, 0.5, 1., 1., np.pi / 2]]), + ([[[[1., 2.], [3., 4.]], + [[4., 3.], [2., 1.]]]], + [[0., 0.5, 0.5, 1., 1., 0]]), + ([[[[1., 2., 5., 6.], [3., 4., 7., 8.], + [9., 10., 13., 14.], [11., 12., 15., 16.]]]], + [[0., 1.5, 1.5, 3., 3., 0]]), + ([[[[1., 2., 5., 6.], [3., 4., 7., 8.], + [9., 10., 13., 14.], [11., 12., 15., 16.]]]], + [[0., 1.5, 1.5, 3., 3., np.pi / 2]])] +outputs = [([[[[1.0, 1.25], [1.5, 1.75]]]], + [[[[3.0625, 0.4375], [0.4375, 0.0625]]]]), + ([[[[1.5, 1], [1.75, 1.25]]]], + [[[[3.0625, 0.4375], [0.4375, 0.0625]]]]), + ([[[[1.0, 1.25], [1.5, 1.75]], + [[4.0, 3.75], [3.5, 3.25]]]], + [[[[3.0625, 0.4375], [0.4375, 0.0625]], + [[3.0625, 0.4375], [0.4375, 0.0625]]]]), + ([[[[1.9375, 4.75], [7.5625, 10.375]]]], + [[[[0.47265625, 0.42968750, 0.42968750, 0.04296875], + [0.42968750, 0.39062500, 0.39062500, 0.03906250], + [0.42968750, 0.39062500, 0.39062500, 0.03906250], + [0.04296875, 0.03906250, 0.03906250, 0.00390625]]]]), + ([[[[7.5625, 1.9375], [10.375, 4.75]]]], + [[[[0.47265625, 0.42968750, 0.42968750, 0.04296875], + [0.42968750, 0.39062500, 0.39062500, 0.03906250], + [0.42968750, 0.39062500, 0.39062500, 0.03906250], + [0.04296875, 0.03906250, 0.03906250, 0.00390625]]]])] +# yapf:enable + +pool_h = 2 +pool_w = 2 +spatial_scale = 1.0 +sampling_ratio = 2 + + +def _test_roialign_rotated_gradcheck(device, dtype): + try: + from mmcv.ops import RoIAlignRotated + except ModuleNotFoundError: + pytest.skip('RoIAlignRotated op is not successfully compiled') + if dtype is torch.half: + pytest.skip('grad check does not support fp16') + for case in inputs: + np_input = np.array(case[0]) + np_rois = np.array(case[1]) + + x = torch.tensor( + np_input, dtype=dtype, device=device, requires_grad=True) + rois = torch.tensor(np_rois, dtype=dtype, device=device) + + froipool = RoIAlignRotated((pool_h, pool_w), spatial_scale, + sampling_ratio) + if torch.__version__ == 'parrots': + gradcheck( + froipool, (x, rois), no_grads=[rois], delta=1e-5, pt_atol=1e-5) + else: + gradcheck(froipool, (x, rois), eps=1e-5, atol=1e-5) + + +def _test_roialign_rotated_allclose(device, dtype): + try: + from mmcv.ops import RoIAlignRotated, roi_align_rotated + except ModuleNotFoundError: + pytest.skip('test requires compilation') + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + sampling_ratio = 2 + + for case, output in zip(inputs, outputs): + np_input = np.array(case[0]) + np_rois = np.array(case[1]) + np_output = np.array(output[0]) + np_grad = np.array(output[1]) + + x = torch.tensor( + np_input, dtype=dtype, device=device, requires_grad=True) + rois = torch.tensor(np_rois, dtype=dtype, device=device) + + output = roi_align_rotated(x, rois, (pool_h, pool_w), spatial_scale, + sampling_ratio, True) + output.backward(torch.ones_like(output)) + assert np.allclose( + output.data.type(torch.float).cpu().numpy(), np_output, atol=1e-3) + assert np.allclose( + x.grad.data.type(torch.float).cpu().numpy(), np_grad, atol=1e-3) + + # Test deprecated parameters + roi_align_rotated_module_deprecated = RoIAlignRotated( + out_size=(pool_h, pool_w), + spatial_scale=spatial_scale, + sample_num=sampling_ratio) + + output_1 = roi_align_rotated_module_deprecated(x, rois) + + roi_align_rotated_module_new = RoIAlignRotated( + output_size=(pool_h, pool_w), + spatial_scale=spatial_scale, + sampling_ratio=sampling_ratio) + + output_2 = roi_align_rotated_module_new(x, rois) + + assert np.allclose( + output_1.data.type(torch.float).cpu().numpy(), + output_2.data.type(torch.float).cpu().numpy()) + + +@pytest.mark.parametrize('device', [ + 'cpu', + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) +]) +@pytest.mark.parametrize('dtype', [ + torch.float, + pytest.param( + torch.double, + marks=pytest.mark.skipif( + IS_MLU_AVAILABLE, + reason='MLU does not support for 64-bit floating point')), + torch.half +]) +def test_roialign_rotated(device, dtype): + # check double only + if dtype is torch.double: + _test_roialign_rotated_gradcheck(device=device, dtype=dtype) + _test_roialign_rotated_allclose(device=device, dtype=dtype) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_pool.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_pool.py new file mode 100644 index 000000000..c935c8114 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_pool.py @@ -0,0 +1,105 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os + +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE, IS_NPU_AVAILABLE + +_USING_PARROTS = True +try: + from parrots.autograd import gradcheck +except ImportError: + from torch.autograd import gradcheck + + _USING_PARROTS = False + +cur_dir = os.path.dirname(os.path.abspath(__file__)) + +inputs = [([[[[1., 2.], [3., 4.]]]], [[0., 0., 0., 1., 1.]]), + ([[[[1., 2.], [3., 4.]], [[4., 3.], [2., + 1.]]]], [[0., 0., 0., 1., 1.]]), + ([[[[1., 2., 5., 6.], [3., 4., 7., 8.], [9., 10., 13., 14.], + [11., 12., 15., 16.]]]], [[0., 0., 0., 3., 3.]])] +outputs = [([[[[1., 2.], [3., 4.]]]], [[[[1., 1.], [1., 1.]]]]), + ([[[[1., 2.], [3., 4.]], [[4., 3.], [2., 1.]]]], [[[[1., 1.], + [1., 1.]], + [[1., 1.], + [1., 1.]]]]), + ([[[[4., 8.], [12., 16.]]]], [[[[0., 0., 0., 0.], [0., 1., 0., 1.], + [0., 0., 0., 0.], [0., 1., 0., + 1.]]]])] + + +class TestRoiPool: + + def test_roipool_gradcheck(self): + if not torch.cuda.is_available(): + return + from mmcv.ops import RoIPool + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + + for case in inputs: + np_input = np.array(case[0]) + np_rois = np.array(case[1]) + + x = torch.tensor(np_input, device='cuda', requires_grad=True) + rois = torch.tensor(np_rois, device='cuda') + + froipool = RoIPool((pool_h, pool_w), spatial_scale) + + if _USING_PARROTS: + pass + # gradcheck(froipool, (x, rois), no_grads=[rois]) + else: + gradcheck(froipool, (x, rois), eps=1e-2, atol=1e-2) + + def _test_roipool_allclose(self, device, dtype=torch.float): + from mmcv.ops import roi_pool + pool_h = 2 + pool_w = 2 + spatial_scale = 1.0 + + for case, output in zip(inputs, outputs): + np_input = np.array(case[0]) + np_rois = np.array(case[1]) + np_output = np.array(output[0]) + np_grad = np.array(output[1]) + + x = torch.tensor( + np_input, dtype=dtype, device=device, requires_grad=True) + rois = torch.tensor(np_rois, dtype=dtype, device=device) + + output = roi_pool(x, rois, (pool_h, pool_w), spatial_scale) + output.backward(torch.ones_like(output)) + assert np.allclose(output.data.cpu().numpy(), np_output, 1e-3) + assert np.allclose(x.grad.data.cpu().numpy(), np_grad, 1e-3) + + @pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')), + pytest.param( + 'npu', + marks=pytest.mark.skipif( + not IS_NPU_AVAILABLE, reason='requires NPU support')) + ]) + @pytest.mark.parametrize('dtype', [ + torch.float, + pytest.param( + torch.double, + marks=pytest.mark.skipif( + IS_MLU_AVAILABLE, + reason='MLU does not support for 64-bit floating point')), + torch.half + ]) + def test_roipool_allclose(self, device, dtype): + self._test_roipool_allclose(device, dtype) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roiaware_pool3d.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_roiaware_pool3d.py new file mode 100644 index 000000000..2a9cbfd32 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_roiaware_pool3d.py @@ -0,0 +1,159 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.ops import (RoIAwarePool3d, points_in_boxes_all, points_in_boxes_cpu, + points_in_boxes_part) +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE + + +@pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) +]) +@pytest.mark.parametrize('dtype', [ + torch.float, torch.half, + pytest.param( + torch.double, + marks=pytest.mark.skipif( + IS_MLU_AVAILABLE, reason='MLU does not support for double')) +]) +def test_RoIAwarePool3d(device, dtype): + roiaware_pool3d_max = RoIAwarePool3d( + out_size=4, max_pts_per_voxel=128, mode='max') + roiaware_pool3d_avg = RoIAwarePool3d( + out_size=4, max_pts_per_voxel=128, mode='avg') + rois = torch.tensor( + [[1.0, 2.0, 3.0, 5.0, 4.0, 6.0, -0.3 - np.pi / 2], + [-10.0, 23.0, 16.0, 20.0, 10.0, 20.0, -0.5 - np.pi / 2]], + dtype=dtype).to(device) + # boxes (m, 7) with bottom center in lidar coordinate + pts = torch.tensor( + [[1, 2, 3.3], [1.2, 2.5, 3.0], [0.8, 2.1, 3.5], [1.6, 2.6, 3.6], + [0.8, 1.2, 3.9], [-9.2, 21.0, 18.2], [3.8, 7.9, 6.3], + [4.7, 3.5, -12.2], [3.8, 7.6, -2], [-10.6, -12.9, -20], [-16, -18, 9], + [-21.3, -52, -5], [0, 0, 0], [6, 7, 8], [-2, -3, -4]], + dtype=dtype).to(device) # points (n, 3) in lidar coordinate + pts_feature = pts.clone() + + pooled_features_max = roiaware_pool3d_max( + rois=rois, pts=pts, pts_feature=pts_feature) + assert pooled_features_max.shape == torch.Size([2, 4, 4, 4, 3]) + assert torch.allclose(pooled_features_max.sum(), + torch.tensor(51.100, dtype=dtype).to(device), 1e-3) + + pooled_features_avg = roiaware_pool3d_avg( + rois=rois, pts=pts, pts_feature=pts_feature) + assert pooled_features_avg.shape == torch.Size([2, 4, 4, 4, 3]) + assert torch.allclose(pooled_features_avg.sum(), + torch.tensor(49.750, dtype=dtype).to(device), 1e-3) + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_points_in_boxes_part(): + boxes = torch.tensor( + [[[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.3]], + [[-10.0, 23.0, 16.0, 10, 20, 20, 0.5]]], + dtype=torch.float32).cuda( + ) # boxes (b, t, 7) with bottom center in lidar coordinate + pts = torch.tensor( + [[[1, 2, 3.3], [1.2, 2.5, 3.0], [0.8, 2.1, 3.5], [1.6, 2.6, 3.6], + [0.8, 1.2, 3.9], [-9.2, 21.0, 18.2], [3.8, 7.9, 6.3], + [4.7, 3.5, -12.2]], + [[3.8, 7.6, -2], [-10.6, -12.9, -20], [-16, -18, 9], [-21.3, -52, -5], + [0, 0, 0], [6, 7, 8], [-2, -3, -4], [6, 4, 9]]], + dtype=torch.float32).cuda() # points (b, m, 3) in lidar coordinate + + point_indices = points_in_boxes_part(points=pts, boxes=boxes) + expected_point_indices = torch.tensor( + [[0, 0, 0, 0, 0, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1]], + dtype=torch.int32).cuda() + assert point_indices.shape == torch.Size([2, 8]) + assert (point_indices == expected_point_indices).all() + + boxes = torch.tensor([[[0.0, 0.0, 0.0, 1.0, 20.0, 1.0, 0.523598]]], + dtype=torch.float32).cuda() # 30 degrees + pts = torch.tensor( + [[[4, 6.928, 0], [6.928, 4, 0], [4, -6.928, 0], [6.928, -4, 0], + [-4, 6.928, 0], [-6.928, 4, 0], [-4, -6.928, 0], [-6.928, -4, 0]]], + dtype=torch.float32).cuda() + point_indices = points_in_boxes_part(points=pts, boxes=boxes) + expected_point_indices = torch.tensor([[-1, -1, 0, -1, 0, -1, -1, -1]], + dtype=torch.int32).cuda() + assert (point_indices == expected_point_indices).all() + + +def test_points_in_boxes_cpu(): + boxes = torch.tensor( + [[[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.3], + [-10.0, 23.0, 16.0, 10, 20, 20, 0.5]]], + dtype=torch.float32 + ) # boxes (m, 7) with bottom center in lidar coordinate + pts = torch.tensor( + [[[1, 2, 3.3], [1.2, 2.5, 3.0], [0.8, 2.1, 3.5], [1.6, 2.6, 3.6], + [0.8, 1.2, 3.9], [-9.2, 21.0, 18.2], [3.8, 7.9, 6.3], + [4.7, 3.5, -12.2], [3.8, 7.6, -2], [-10.6, -12.9, -20], [ + -16, -18, 9 + ], [-21.3, -52, -5], [0, 0, 0], [6, 7, 8], [-2, -3, -4]]], + dtype=torch.float32) # points (n, 3) in lidar coordinate + + point_indices = points_in_boxes_cpu(points=pts, boxes=boxes) + expected_point_indices = torch.tensor( + [[[1, 0], [1, 0], [1, 0], [1, 0], [1, 0], [0, 1], [0, 0], [0, 0], + [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]], + dtype=torch.int32) + assert point_indices.shape == torch.Size([1, 15, 2]) + assert (point_indices == expected_point_indices).all() + + boxes = torch.tensor([[[0.0, 0.0, 0.0, 1.0, 20.0, 1.0, 0.523598]]], + dtype=torch.float32) # 30 degrees + pts = torch.tensor( + [[[4, 6.928, 0], [6.928, 4, 0], [4, -6.928, 0], [6.928, -4, 0], + [-4, 6.928, 0], [-6.928, 4, 0], [-4, -6.928, 0], [-6.928, -4, 0]]], + dtype=torch.float32) + point_indices = points_in_boxes_cpu(points=pts, boxes=boxes) + expected_point_indices = torch.tensor( + [[[0], [0], [1], [0], [1], [0], [0], [0]]], dtype=torch.int32) + assert (point_indices == expected_point_indices).all() + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_points_in_boxes_all(): + + boxes = torch.tensor( + [[[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.3], + [-10.0, 23.0, 16.0, 10, 20, 20, 0.5]]], + dtype=torch.float32).cuda( + ) # boxes (m, 7) with bottom center in lidar coordinate + pts = torch.tensor( + [[[1, 2, 3.3], [1.2, 2.5, 3.0], [0.8, 2.1, 3.5], [1.6, 2.6, 3.6], + [0.8, 1.2, 3.9], [-9.2, 21.0, 18.2], [3.8, 7.9, 6.3], + [4.7, 3.5, -12.2], [3.8, 7.6, -2], [-10.6, -12.9, -20], [ + -16, -18, 9 + ], [-21.3, -52, -5], [0, 0, 0], [6, 7, 8], [-2, -3, -4]]], + dtype=torch.float32).cuda() # points (n, 3) in lidar coordinate + + point_indices = points_in_boxes_all(points=pts, boxes=boxes) + expected_point_indices = torch.tensor( + [[[1, 0], [1, 0], [1, 0], [1, 0], [1, 0], [0, 1], [0, 0], [0, 0], + [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]], + dtype=torch.int32).cuda() + assert point_indices.shape == torch.Size([1, 15, 2]) + assert (point_indices == expected_point_indices).all() + + if torch.cuda.device_count() > 1: + pts = pts.to('cuda:1') + boxes = boxes.to('cuda:1') + expected_point_indices = expected_point_indices.to('cuda:1') + point_indices = points_in_boxes_all(points=pts, boxes=boxes) + assert point_indices.shape == torch.Size([1, 15, 2]) + assert (point_indices == expected_point_indices).all() diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roipoint_pool3d.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_roipoint_pool3d.py new file mode 100644 index 000000000..391a0bf3a --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_roipoint_pool3d.py @@ -0,0 +1,50 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import RoIPointPool3d +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE + + +@pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) +]) +@pytest.mark.parametrize('dtype', [ + torch.float, torch.half, + pytest.param( + torch.double, + marks=pytest.mark.skipif( + IS_MLU_AVAILABLE, reason='MLU does not support for double')) +]) +def test_roipoint(device, dtype): + points = torch.tensor( + [[1, 2, 3.3], [1.2, 2.5, 3.0], [0.8, 2.1, 3.5], [1.6, 2.6, 3.6], + [0.8, 1.2, 3.9], [-9.2, 21.0, 18.2], [3.8, 7.9, 6.3], + [4.7, 3.5, -12.2], [3.8, 7.6, -2], [-10.6, -12.9, -20], [-16, -18, 9], + [-21.3, -52, -5], [0, 0, 0], [6, 7, 8], [-2, -3, -4]], + dtype=dtype).unsqueeze(0).to(device) + feats = points.clone() + rois = torch.tensor([[[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.3], + [-10.0, 23.0, 16.0, 10, 20, 20, 0.5]]], + dtype=dtype).to(device) + + roipoint_pool3d = RoIPointPool3d(num_sampled_points=4) + roi_feat, empty_flag = roipoint_pool3d(points, feats, rois) + expected_roi_feat = torch.tensor( + [[[[1, 2, 3.3, 1, 2, 3.3], [1.2, 2.5, 3, 1.2, 2.5, 3], + [0.8, 2.1, 3.5, 0.8, 2.1, 3.5], [1.6, 2.6, 3.6, 1.6, 2.6, 3.6]], + [[-9.2, 21, 18.2, -9.2, 21, 18.2], [-9.2, 21, 18.2, -9.2, 21, 18.2], + [-9.2, 21, 18.2, -9.2, 21, 18.2], [-9.2, 21, 18.2, -9.2, 21, 18.2]]] + ], + dtype=dtype).to(device) + expected_empty_flag = torch.tensor([[0, 0]]).int().to(device) + + assert torch.allclose(roi_feat, expected_roi_feat) + assert torch.allclose(empty_flag, expected_empty_flag) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_rotated_feature_align.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_rotated_feature_align.py new file mode 100644 index 000000000..e7422a310 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_rotated_feature_align.py @@ -0,0 +1,131 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import rotated_feature_align +from mmcv.utils import IS_CUDA_AVAILABLE + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +@pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'cpu', + marks=pytest.mark.skipif( + torch.__version__ == 'parrots', reason='requires PyTorch support')) +]) +def test_rotated_feature_align(device): + feature = torch.tensor([[[[1.2924, -0.2172, -0.5222, 0.1172], + [0.9144, 1.2248, 1.3115, -0.9690], + [-0.8949, -1.1797, -0.9093, -0.3961], + [-0.4586, 0.5062, -0.7947, -0.7397]], + [[-1.0943, -0.7495, 1.3461, -1.1652], + [0.2034, 0.6763, -1.2357, 0.5231], + [-1.0062, 1.2592, 1.4225, -0.3951], + [-0.1242, -1.6240, 0.1932, 2.7181]], + [[-1.6271, -1.0276, 0.0578, -0.2997], + [-0.9684, -1.6946, -1.3188, -1.1938], + [-1.6744, -0.8917, -0.6556, + 1.0073], [-0.1205, 0.3671, -0.3731, -0.5347]]], + [[[0.7035, 0.2089, -0.1774, 3.4670], + [-0.8505, -0.9278, 1.4714, 0.1644], + [0.0898, 0.3531, -0.4007, 0.1927], + [1.2569, -0.2636, -0.5223, 0.0616]], + [[0.1760, -0.7639, -0.4600, -1.3260], + [-0.9921, -0.2970, -0.8955, 1.0508], + [1.3515, -0.1641, 1.9679, 1.1986], + [-0.3616, 0.6287, 0.4933, 0.3360]], + [[-0.5860, 0.2124, -0.8700, 2.4200], + [-0.0551, -1.5103, -1.6779, 0.8399], + [0.8431, 1.2414, -1.1243, -0.3887], + [-2.1254, 0.6047, -0.3515, 0.7254]]]], + device=device, + requires_grad=True) + + bbox = torch.tensor( + [[[[1.3080e+01, 1.2688e+01, 1.1214e+01, 9.3944e+01, -9.1905e-01], + [3.8104e+01, 1.0134e+01, 1.4659e+02, 9.0306e+01, -9.8211e-01], + [-5.3213e+01, 4.9508e+01, 5.1513e+01, 3.2055e+01, -3.1954e-01], + [2.6974e+01, 2.5248e+01, 5.4495e+01, 3.1083e+00, -6.2127e-01]], + [[-1.5604e+01, -5.1908e+01, 2.3998e+02, 1.5008e+01, -1.2546e+00], + [3.1354e+01, -7.3635e+00, 6.7879e+01, 3.5081e+01, -3.3851e-01], + [-5.3292e+00, 9.1946e+00, 1.2834e+01, 1.0485e+01, -1.3039e+00], + [-2.3925e+01, 3.6623e+01, 3.9875e+01, 7.2009e+01, -6.5934e-01]], + [[7.2114e+01, -2.3781e+01, 2.9106e+01, 8.4501e+01, -1.1340e+00], + [2.6258e+01, -7.7034e+00, 1.7629e+02, 1.0615e+02, -1.2156e+00], + [3.8057e+01, 4.6016e+01, 1.2965e+01, 6.9384e+00, -1.0855e+00], + [2.4428e+01, -1.6189e+01, 2.0572e+02, 3.1622e+01, -1.5719e-01]], + [[3.8226e+00, 2.9608e+01, 1.4457e+01, 6.8179e+01, -9.1997e-01], + [2.5003e+01, -4.2490e+01, 9.6007e+01, 4.9086e+01, -1.4786e+00], + [8.5983e+01, 5.4980e+01, 7.8080e+01, 1.0003e+02, -1.0926e+00], + [9.9065e+00, 4.1457e+01, 5.9799e+00, 1.7973e+01, -5.6313e-01]]], + [[[-1.8244e+01, 4.6309e+00, 5.3010e+01, 2.4310e+01, -7.0345e-01], + [1.9419e+01, 3.6704e+01, 5.2390e+01, 5.4133e+01, -3.7730e-01], + [5.6387e+01, 2.3752e+01, 9.0441e+00, 1.7792e+01, -1.5583e+00], + [3.6303e+01, 1.6396e+01, 2.0283e+01, 1.9148e+01, -8.3419e-01]], + [[3.2169e+01, 3.0521e+01, 2.6283e+01, 1.9680e+02, -3.0454e-01], + [2.5788e+01, -3.2189e+01, 8.8882e+01, 1.0207e+02, -1.5328e+00], + [8.4676e+00, -1.6668e+01, 2.4657e+01, 1.1275e+02, -4.0388e-01], + [-1.0799e+01, 6.0422e+00, 9.5807e+00, 3.3677e+01, -3.5438e-01]], + [[6.9363e+01, 1.0850e+01, 2.5968e+01, 2.2311e+01, -1.6408e-01], + [2.8140e+00, 4.6843e+00, 3.1289e+00, 2.1480e+01, -6.7583e-01], + [2.6661e+01, 4.5290e+01, 6.1679e+00, 3.0005e+01, -8.9806e-01], + [5.0871e+00, 1.3234e+01, 9.2087e+01, 4.9622e+01, -2.8020e-01]], + [[-1.2643e+01, 2.5176e+01, 5.0488e+01, 5.4246e+01, -4.4840e-01], + [-3.4521e+01, 9.8435e-01, 5.2413e+01, 9.7996e+00, -8.4218e-01], + [4.9829e+01, -1.0808e+01, 2.9848e+01, 7.3579e+01, -6.2672e-01], + [8.0446e+01, 2.8064e+01, 4.5273e+01, 5.3809e+01, -1.2359e+00]]]], + device=device, + requires_grad=True) + + expected_output = torch.tensor([[[[1.1095, -0.2172, -0.5222, -0.6225], + [0.9144, 0.7662, 1.0487, -0.9690], + [-0.8949, -1.6384, -0.9093, -0.3961], + [-0.8604, 0.5062, -0.7947, -0.7397]], + [[-0.3961, -0.7495, 1.3461, 1.5528], + [0.2034, 0.5522, -1.6722, 0.5231], + [-1.0062, 1.1350, 1.4225, -0.3951], + [-0.4826, -1.6240, 0.1932, 2.7181]], + [[-2.6436, -1.0276, 0.0578, -0.8344], + [-0.9684, -1.8151, -2.1843, -1.1938], + [-1.6744, -1.0121, -0.6556, 1.0073], + [-0.8474, 0.3671, -0.3731, -0.5347]]], + [[[0.7035, 0.2089, -0.1774, 3.4670], + [-0.8505, -0.9278, 1.4714, 0.1644], + [0.0898, 0.3064, -0.4007, 0.5849], + [1.2569, -0.2636, -0.5223, 0.0616]], + [[0.1760, -0.7639, -0.4600, -1.3260], + [-0.9921, -0.2970, -0.8955, 1.0508], + [1.3515, -0.6125, 1.9679, 0.5550], + [-0.3616, 0.6287, 0.4933, 0.3360]], + [[-0.5860, 0.2124, -0.8700, 2.4200], + [-0.0551, -1.5103, -1.6779, 0.8399], + [0.8431, 0.8455, -1.1243, -1.5994], + [-2.1254, 0.6047, -0.3515, 0.7254]]]], + device=device) + + expected_grad = torch.tensor([ + [[[1.0000, 1.8507, 1.1493, 1.5222], [1.0000, 1.1511, 1.2139, 1.4778], + [1.0000, 1.2629, 1.3721, 1.0000], [3.0000, 1.0000, 1.0000, 2.0000]], + [[1.0000, 1.8507, 1.1493, 1.5222], [1.0000, 1.1511, 1.2139, 1.4778], + [1.0000, 1.2629, 1.3721, 1.0000], [3.0000, 1.0000, 1.0000, 2.0000]], + [[1.0000, 1.8507, 1.1493, 1.5222], [1.0000, 1.1511, 1.2139, 1.4778], + [1.0000, 1.2629, 1.3721, 1.0000], [3.0000, 1.0000, 1.0000, 2.0000]]], + [[[1.2687, 1.5055, 1.2382, 1.0000], [1.1458, 1.4258, 1.4160, 1.0000], + [1.0000, 1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000, 1.0000]], + [[1.2687, 1.5055, 1.2382, 1.0000], [1.1458, 1.4258, 1.4160, 1.0000], + [1.0000, 1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000, 1.0000]], + [[1.2687, 1.5055, 1.2382, 1.0000], [1.1458, 1.4258, 1.4160, 1.0000], + [1.0000, 1.0000, 1.0000, 1.0000], [1.0000, 1.0000, 1.0000, 1.0000]]] + ], + device=device) + + output = rotated_feature_align( + feature, bbox, spatial_scale=1 / 8, points=1) + output.backward(torch.ones_like(output)) + assert torch.allclose(output, expected_output, 1e-2) + assert torch.allclose(feature.grad, expected_grad, 1e-2) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_saconv.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_saconv.py new file mode 100644 index 000000000..607775c38 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_saconv.py @@ -0,0 +1,47 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn + +from mmcv.ops import SAConv2d + + +def test_sacconv(): + + # test with normal cast + x = torch.rand(1, 3, 256, 256) + saconv = SAConv2d(3, 5, kernel_size=3, padding=1) + sac_out = saconv(x) + refer_conv = nn.Conv2d(3, 5, kernel_size=3, padding=1) + refer_out = refer_conv(x) + assert sac_out.shape == refer_out.shape + + # test with dilation >= 2 + dalited_saconv = SAConv2d(3, 5, kernel_size=3, padding=2, dilation=2) + dalited_sac_out = dalited_saconv(x) + refer_conv = nn.Conv2d(3, 5, kernel_size=3, padding=2, dilation=2) + refer_out = refer_conv(x) + assert dalited_sac_out.shape == refer_out.shape + + # test with deform + deform_saconv = SAConv2d(3, 5, kernel_size=3, padding=1, use_deform=True) + if torch.cuda.is_available(): + x = torch.rand(1, 3, 256, 256).cuda() + deform_saconv = SAConv2d( + 3, 5, kernel_size=3, padding=1, use_deform=True).cuda() + deform_sac_out = deform_saconv(x).cuda() + refer_conv = nn.Conv2d(3, 5, kernel_size=3, padding=1).cuda() + refer_out = refer_conv(x) + assert deform_sac_out.shape == refer_out.shape + else: + deform_sac_out = deform_saconv(x) + refer_conv = nn.Conv2d(3, 5, kernel_size=3, padding=1) + refer_out = refer_conv(x) + assert deform_sac_out.shape == refer_out.shape + + # test with groups >= 2 + x = torch.rand(1, 4, 256, 256) + group_saconv = SAConv2d(4, 4, kernel_size=3, padding=1, groups=2) + group_sac_out = group_saconv(x) + refer_conv = nn.Conv2d(4, 4, kernel_size=3, padding=1, groups=2) + refer_out = refer_conv(x) + assert group_sac_out.shape == refer_out.shape diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_scatter_points.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_scatter_points.py new file mode 100644 index 000000000..cf4516047 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_scatter_points.py @@ -0,0 +1,132 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch +from torch.autograd import gradcheck + +from mmcv.ops import DynamicScatter + +if torch.__version__ == 'parrots': + pytest.skip('not supported in parrots now', allow_module_level=True) + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_dynamic_scatter(): + dsmean = DynamicScatter([0.32, 0.32, 6], + [-74.88, -74.88, -2, 74.88, 74.88, 4], True) + dsmax = DynamicScatter([0.32, 0.32, 6], + [-74.88, -74.88, -2, 74.88, 74.88, 4], False) + + # test empty input + empty_feats = torch.empty(size=(0, 3), dtype=torch.float32, device='cuda') + empty_coors = torch.empty(size=(0, 3), dtype=torch.int32, device='cuda') + + empty_feats.requires_grad_() + empty_feats_out_mean, empty_coors_out_mean = dsmean( + empty_feats, empty_coors) + empty_feats_out_mean.sum().backward() + empty_feats_out_max, empty_coors_out_max = dsmax(empty_feats, empty_coors) + empty_feats_out_max.sum().backward() + + assert empty_feats_out_mean.shape == empty_feats.shape + assert empty_feats_out_max.shape == empty_feats.shape + assert empty_coors_out_mean.shape == empty_coors.shape + assert empty_coors_out_max.shape == empty_coors.shape + + # test empty reduced output + empty_o_feats = torch.rand( + size=(200000, 3), dtype=torch.float32, device='cuda') * 100 - 50 + empty_o_coors = torch.randint( + low=-1, high=0, size=(200000, 3), dtype=torch.int32, device='cuda') + + empty_o_feats.requires_grad_() + empty_o_feats_out_mean, empty_o_coors_out_mean = dsmean( + empty_o_feats, empty_o_coors) + empty_o_feats_out_mean.sum().backward() + assert (empty_o_feats.grad == 0).all() + + empty_o_feats_out_max, empty_o_coors_out_max = dsmax( + empty_o_feats, empty_o_coors) + empty_o_feats_out_max.sum().backward() + assert (empty_o_feats.grad == 0).all() + + # test non-empty input + feats = torch.rand( + size=(200000, 3), dtype=torch.float32, device='cuda') * 100 - 50 + coors = torch.randint( + low=-1, high=20, size=(200000, 3), dtype=torch.int32, device='cuda') + + ref_voxel_coors = coors.unique(dim=0, sorted=True) + ref_voxel_coors = ref_voxel_coors[ref_voxel_coors.min(dim=-1).values >= 0] + ref_voxel_feats_mean = [] + ref_voxel_feats_max = [] + for ref_voxel_coor in ref_voxel_coors: + voxel_mask = (coors == ref_voxel_coor).all(dim=-1) + ref_voxel_feats_mean.append(feats[voxel_mask].mean(dim=0)) + ref_voxel_feats_max.append(feats[voxel_mask].max(dim=0).values) + ref_voxel_feats_mean = torch.stack(ref_voxel_feats_mean) + ref_voxel_feats_max = torch.stack(ref_voxel_feats_max) + + feats_out_mean, coors_out_mean = dsmean(feats, coors) + seq_mean = (coors_out_mean[:, 0] * 400 + coors_out_mean[:, 1] * 20 + + coors_out_mean[:, 2]).argsort() + feats_out_mean = feats_out_mean[seq_mean] + coors_out_mean = coors_out_mean[seq_mean] + + feats_out_max, coors_out_max = dsmax(feats, coors) + seq_max = (coors_out_max[:, 0] * 400 + coors_out_max[:, 1] * 20 + + coors_out_max[:, 2]).argsort() + feats_out_max = feats_out_max[seq_max] + coors_cout_max = coors_out_max[seq_max] + + assert (coors_out_mean == ref_voxel_coors).all() + assert torch.allclose( + feats_out_mean, ref_voxel_feats_mean, atol=1e-2, rtol=1e-5) + assert (coors_cout_max == ref_voxel_coors).all() + assert torch.allclose( + feats_out_max, ref_voxel_feats_max, atol=1e-2, rtol=1e-5) + + # test non-empty input without any point out of bound + feats = torch.rand( + size=(200000, 3), dtype=torch.float32, device='cuda') * 100 - 50 + coors = torch.randint( + low=0, high=20, size=(200000, 3), dtype=torch.int32, device='cuda') + + ref_voxel_coors = coors.unique(dim=0, sorted=True) + ref_voxel_coors = ref_voxel_coors[ref_voxel_coors.min(dim=-1).values >= 0] + ref_voxel_feats_mean = [] + ref_voxel_feats_max = [] + for ref_voxel_coor in ref_voxel_coors: + voxel_mask = (coors == ref_voxel_coor).all(dim=-1) + ref_voxel_feats_mean.append(feats[voxel_mask].mean(dim=0)) + ref_voxel_feats_max.append(feats[voxel_mask].max(dim=0).values) + ref_voxel_feats_mean = torch.stack(ref_voxel_feats_mean) + ref_voxel_feats_max = torch.stack(ref_voxel_feats_max) + + feats_out_mean, coors_out_mean = dsmean(feats, coors) + seq_mean = (coors_out_mean[:, 0] * 400 + coors_out_mean[:, 1] * 20 + + coors_out_mean[:, 2]).argsort() + feats_out_mean = feats_out_mean[seq_mean] + coors_out_mean = coors_out_mean[seq_mean] + + feats_out_max, coors_out_max = dsmax(feats, coors) + seq_max = (coors_out_max[:, 0] * 400 + coors_out_max[:, 1] * 20 + + coors_out_max[:, 2]).argsort() + feats_out_max = feats_out_max[seq_max] + coors_cout_max = coors_out_max[seq_max] + + assert (coors_out_mean == ref_voxel_coors).all() + assert torch.allclose( + feats_out_mean, ref_voxel_feats_mean, atol=1e-2, rtol=1e-5) + assert (coors_cout_max == ref_voxel_coors).all() + assert torch.allclose( + feats_out_max, ref_voxel_feats_max, atol=1e-2, rtol=1e-5) + + # test grad # + feats = torch.rand( + size=(100, 4), dtype=torch.float32, device='cuda') * 100 - 50 + coors = torch.randint( + low=-1, high=3, size=(100, 3), dtype=torch.int32, device='cuda') + feats.requires_grad_() + gradcheck(dsmean, (feats, coors), eps=1e-2, atol=1e-2, rtol=1e-5) + gradcheck(dsmax, (feats, coors), eps=1e-2, atol=1e-2, rtol=1e-5) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_spconv.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_spconv.py new file mode 100644 index 000000000..098ff2189 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_spconv.py @@ -0,0 +1,133 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch +from torch import nn + +from mmcv.cnn import build_conv_layer, build_norm_layer +from mmcv.ops import (SparseConvTensor, SparseInverseConv3d, SparseSequential, + SubMConv3d) + +if torch.__version__ == 'parrots': + pytest.skip('not supported in parrots now', allow_module_level=True) + + +def make_sparse_convmodule(in_channels, + out_channels, + kernel_size, + indice_key, + stride=1, + padding=0, + conv_type='SubMConv3d', + norm_cfg=None, + order=('conv', 'norm', 'act')): + """Make sparse convolution module. + + Args: + in_channels (int): the number of input channels + out_channels (int): the number of out channels + kernel_size (int|tuple(int)): kernel size of convolution + indice_key (str): the indice key used for sparse tensor + stride (int|tuple(int)): the stride of convolution + padding (int or list[int]): the padding number of input + conv_type (str): sparse conv type in spconv + norm_cfg (dict[str]): config of normalization layer + order (tuple[str]): The order of conv/norm/activation layers. It is a + sequence of "conv", "norm" and "act". Common examples are + ("conv", "norm", "act") and ("act", "conv", "norm"). + + Returns: + spconv.SparseSequential: sparse convolution module. + """ + assert isinstance(order, tuple) and len(order) <= 3 + assert set(order) | {'conv', 'norm', 'act'} == {'conv', 'norm', 'act'} + + conv_cfg = dict(type=conv_type, indice_key=indice_key) + + layers = list() + for layer in order: + if layer == 'conv': + if conv_type not in [ + 'SparseInverseConv3d', 'SparseInverseConv2d', + 'SparseInverseConv1d' + ]: + layers.append( + build_conv_layer( + conv_cfg, + in_channels, + out_channels, + kernel_size, + stride=stride, + padding=padding, + bias=False)) + else: + layers.append( + build_conv_layer( + conv_cfg, + in_channels, + out_channels, + kernel_size, + bias=False)) + elif layer == 'norm': + layers.append(build_norm_layer(norm_cfg, out_channels)[1]) + elif layer == 'act': + layers.append(nn.ReLU(inplace=True)) + + layers = SparseSequential(*layers) + return layers + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_make_sparse_convmodule(): + torch.cuda.empty_cache() + voxel_features = torch.tensor([[6.56126, 0.9648336, -1.7339306, 0.315], + [6.8162713, -2.480431, -1.3616394, 0.36], + [11.643568, -4.744306, -1.3580885, 0.16], + [23.482342, 6.5036807, 0.5806964, 0.35]], + dtype=torch.float32, + device='cuda') # n, point_features + coordinates = torch.tensor( + [[0, 12, 819, 131], [0, 16, 750, 136], [1, 16, 705, 232], + [1, 35, 930, 469]], + dtype=torch.int32, + device='cuda') # n, 4(batch, ind_x, ind_y, ind_z) + + # test + input_sp_tensor = SparseConvTensor(voxel_features, coordinates, + [41, 1600, 1408], 2) + + sparse_block0 = make_sparse_convmodule( + 4, + 16, + 3, + 'test0', + stride=1, + padding=0, + conv_type='SubMConv3d', + norm_cfg=dict(type='BN1d', eps=1e-3, momentum=0.01), + order=('conv', 'norm', 'act')).cuda() + assert isinstance(sparse_block0[0], SubMConv3d) + assert sparse_block0[0].in_channels == 4 + assert sparse_block0[0].out_channels == 16 + assert isinstance(sparse_block0[1], torch.nn.BatchNorm1d) + assert sparse_block0[1].eps == 0.001 + assert sparse_block0[1].momentum == 0.01 + assert isinstance(sparse_block0[2], torch.nn.ReLU) + + # test forward + out_features = sparse_block0(input_sp_tensor) + assert out_features.features.shape == torch.Size([4, 16]) + + sparse_block1 = make_sparse_convmodule( + 4, + 16, + 3, + 'test1', + stride=1, + padding=0, + conv_type='SparseInverseConv3d', + norm_cfg=dict(type='BN1d', eps=1e-3, momentum=0.01), + order=('norm', 'act', 'conv')).cuda() + assert isinstance(sparse_block1[0], torch.nn.BatchNorm1d) + assert isinstance(sparse_block1[1], torch.nn.ReLU) + assert isinstance(sparse_block1[2], SparseInverseConv3d) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_syncbn.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_syncbn.py new file mode 100644 index 000000000..d1c1605ad --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_syncbn.py @@ -0,0 +1,295 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import platform + +import numpy as np +import pytest +import torch +import torch.distributed as dist +import torch.nn as nn + +if platform.system() == 'Windows': + import regex as re +else: + import re + + +class TestSyncBN: + + def dist_init(self): + rank = int(os.environ['SLURM_PROCID']) + world_size = int(os.environ['SLURM_NTASKS']) + local_rank = int(os.environ['SLURM_LOCALID']) + node_list = str(os.environ['SLURM_NODELIST']) + + node_parts = re.findall('[0-9]+', node_list) + os.environ['MASTER_ADDR'] = (f'{node_parts[1]}.{node_parts[2]}' + + f'.{node_parts[3]}.{node_parts[4]}') + os.environ['MASTER_PORT'] = '12341' + os.environ['WORLD_SIZE'] = str(world_size) + os.environ['RANK'] = str(rank) + + dist.init_process_group('nccl') + torch.cuda.set_device(local_rank) + + def _test_syncbn_train(self, size=1, half=False): + + if 'SLURM_NTASKS' not in os.environ or int( + os.environ['SLURM_NTASKS']) != 4: + print('must run with slurm has 4 processes!\n' + 'srun -p test --gres=gpu:4 -n4') + return + else: + print('Running syncbn test') + from mmcv.ops import SyncBatchNorm + + assert size in (1, 2, 4) + if not dist.is_initialized(): + self.dist_init() + rank = dist.get_rank() + + torch.manual_seed(9) + torch.cuda.manual_seed(9) + + self.x = torch.rand(16, 3, 2, 3).cuda() + self.y_bp = torch.rand(16, 3, 2, 3).cuda() + + if half: + self.x = self.x.half() + self.y_bp = self.y_bp.half() + dist.broadcast(self.x, src=0) + dist.broadcast(self.y_bp, src=0) + + torch.cuda.synchronize() + if size == 1: + groups = [None, None, None, None] + groups[0] = dist.new_group([0]) + groups[1] = dist.new_group([1]) + groups[2] = dist.new_group([2]) + groups[3] = dist.new_group([3]) + group = groups[rank] + elif size == 2: + groups = [None, None, None, None] + groups[0] = groups[1] = dist.new_group([0, 1]) + groups[2] = groups[3] = dist.new_group([2, 3]) + group = groups[rank] + elif size == 4: + group = dist.group.WORLD + syncbn = SyncBatchNorm(3, group=group).cuda() + syncbn.weight.data[0] = 0.2 + syncbn.weight.data[1] = 0.5 + syncbn.weight.data[2] = 0.7 + syncbn.train() + + bn = nn.BatchNorm2d(3).cuda() + bn.weight.data[0] = 0.2 + bn.weight.data[1] = 0.5 + bn.weight.data[2] = 0.7 + bn.train() + + sx = self.x[rank * 4:rank * 4 + 4] + sx.requires_grad_() + sy = syncbn(sx) + sy.backward(self.y_bp[rank * 4:rank * 4 + 4]) + + smean = syncbn.running_mean + svar = syncbn.running_var + sx_grad = sx.grad + sw_grad = syncbn.weight.grad + sb_grad = syncbn.bias.grad + + if size == 1: + x = self.x[rank * 4:rank * 4 + 4] + y_bp = self.y_bp[rank * 4:rank * 4 + 4] + elif size == 2: + x = self.x[rank // 2 * 8:rank // 2 * 8 + 8] + y_bp = self.y_bp[rank // 2 * 8:rank // 2 * 8 + 8] + elif size == 4: + x = self.x + y_bp = self.y_bp + x.requires_grad_() + y = bn(x) + y.backward(y_bp) + + if size == 2: + y = y[rank % 2 * 4:rank % 2 * 4 + 4] + elif size == 4: + y = y[rank * 4:rank * 4 + 4] + + mean = bn.running_mean + var = bn.running_var + if size == 1: + x_grad = x.grad + w_grad = bn.weight.grad + b_grad = bn.bias.grad + elif size == 2: + x_grad = x.grad[rank % 2 * 4:rank % 2 * 4 + 4] + w_grad = bn.weight.grad / 2 + b_grad = bn.bias.grad / 2 + elif size == 4: + x_grad = x.grad[rank * 4:rank * 4 + 4] + w_grad = bn.weight.grad / 4 + b_grad = bn.bias.grad / 4 + + assert np.allclose(mean.data.cpu().numpy(), + smean.data.cpu().numpy(), 1e-3) + assert np.allclose(var.data.cpu().numpy(), + svar.data.cpu().numpy(), 1e-3) + assert np.allclose(y.data.cpu().numpy(), sy.data.cpu().numpy(), 1e-3) + assert np.allclose(w_grad.data.cpu().numpy(), + sw_grad.data.cpu().numpy(), 1e-3) + assert np.allclose(b_grad.data.cpu().numpy(), + sb_grad.data.cpu().numpy(), 1e-3) + assert np.allclose(x_grad.data.cpu().numpy(), + sx_grad.data.cpu().numpy(), 1e-2) + + def _test_syncbn_empty_train(self, size=1, half=False): + + if 'SLURM_NTASKS' not in os.environ or int( + os.environ['SLURM_NTASKS']) != 4: + print('must run with slurm has 4 processes!\n' + 'srun -p test --gres=gpu:4 -n4') + return + else: + print('Running syncbn test') + from mmcv.ops import SyncBatchNorm + + assert size in (1, 2, 4) + if not dist.is_initialized(): + self.dist_init() + rank = dist.get_rank() + + torch.manual_seed(9) + torch.cuda.manual_seed(9) + + self.x = torch.rand(0, 3, 2, 3).cuda() + self.y_bp = torch.rand(0, 3, 2, 3).cuda() + + if half: + self.x = self.x.half() + self.y_bp = self.y_bp.half() + dist.broadcast(self.x, src=0) + dist.broadcast(self.y_bp, src=0) + + torch.cuda.synchronize() + if size == 1: + groups = [None, None, None, None] + groups[0] = dist.new_group([0]) + groups[1] = dist.new_group([1]) + groups[2] = dist.new_group([2]) + groups[3] = dist.new_group([3]) + group = groups[rank] + elif size == 2: + groups = [None, None, None, None] + groups[0] = groups[1] = dist.new_group([0, 1]) + groups[2] = groups[3] = dist.new_group([2, 3]) + group = groups[rank] + elif size == 4: + group = dist.group.WORLD + + syncbn = SyncBatchNorm(3, group=group, stats_mode='N').cuda() + syncbn.weight.data[0] = 0.2 + syncbn.weight.data[1] = 0.5 + syncbn.weight.data[2] = 0.7 + syncbn.train() + + bn = nn.BatchNorm2d(3).cuda() + bn.weight.data[0] = 0.2 + bn.weight.data[1] = 0.5 + bn.weight.data[2] = 0.7 + bn.train() + + sx = self.x[rank * 4:rank * 4 + 4] + sx.requires_grad_() + sy = syncbn(sx) + sy.backward(self.y_bp[rank * 4:rank * 4 + 4]) + smean = syncbn.running_mean + svar = syncbn.running_var + sx_grad = sx.grad + sw_grad = syncbn.weight.grad + sb_grad = syncbn.bias.grad + + if size == 1: + x = self.x[rank * 4:rank * 4 + 4] + y_bp = self.y_bp[rank * 4:rank * 4 + 4] + elif size == 2: + x = self.x[rank // 2 * 8:rank // 2 * 8 + 8] + y_bp = self.y_bp[rank // 2 * 8:rank // 2 * 8 + 8] + elif size == 4: + x = self.x + y_bp = self.y_bp + x.requires_grad_() + y = bn(x) + y.backward(y_bp) + + if size == 2: + y = y[rank % 2 * 4:rank % 2 * 4 + 4] + elif size == 4: + y = y[rank * 4:rank * 4 + 4] + + mean = bn.running_mean + var = bn.running_var + if size == 1: + x_grad = x.grad + w_grad = bn.weight.grad + b_grad = bn.bias.grad + elif size == 2: + x_grad = x.grad[rank % 2 * 4:rank % 2 * 4 + 4] + w_grad = bn.weight.grad / 2 + b_grad = bn.bias.grad / 2 + elif size == 4: + x_grad = x.grad[rank * 4:rank * 4 + 4] + w_grad = bn.weight.grad / 4 + b_grad = bn.bias.grad / 4 + + assert np.allclose(mean.data.cpu().numpy(), + smean.data.cpu().numpy(), 1e-3) + assert np.allclose(var.data.cpu().numpy(), + svar.data.cpu().numpy(), 1e-3) + assert np.allclose(y.data.cpu().numpy(), sy.data.cpu().numpy(), 1e-3) + assert np.allclose(w_grad.data.cpu().numpy(), + sw_grad.data.cpu().numpy(), 1e-3) + assert np.allclose(b_grad.data.cpu().numpy(), + sb_grad.data.cpu().numpy(), 1e-3) + assert np.allclose(x_grad.data.cpu().numpy(), + sx_grad.data.cpu().numpy(), 1e-2) + + # 'stats_mode' only allows 'default' and 'N' + with pytest.raises(AssertionError): + SyncBatchNorm(3, group=group, stats_mode='X') + + def test_syncbn_1(self): + self._test_syncbn_train(size=1) + + def test_syncbn_2(self): + self._test_syncbn_train(size=2) + + def test_syncbn_4(self): + self._test_syncbn_train(size=4) + + def test_syncbn_1_half(self): + self._test_syncbn_train(size=1, half=True) + + def test_syncbn_2_half(self): + self._test_syncbn_train(size=2, half=True) + + def test_syncbn_4_half(self): + self._test_syncbn_train(size=4, half=True) + + def test_syncbn_empty_1(self): + self._test_syncbn_empty_train(size=1) + + def test_syncbn_empty_2(self): + self._test_syncbn_empty_train(size=2) + + def test_syncbn_empty_4(self): + self._test_syncbn_empty_train(size=4) + + def test_syncbn_empty_1_half(self): + self._test_syncbn_empty_train(size=1, half=True) + + def test_syncbn_empty_2_half(self): + self._test_syncbn_empty_train(size=2, half=True) + + def test_syncbn_empty_4_half(self): + self._test_syncbn_empty_train(size=4, half=True) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_three_interpolate.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_three_interpolate.py new file mode 100644 index 000000000..51a6b8732 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_three_interpolate.py @@ -0,0 +1,78 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import three_interpolate + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +@pytest.mark.parametrize('dtype', [torch.half, torch.float, torch.double]) +def test_three_interpolate(dtype): + features = torch.tensor( + [[[2.4350, 4.7516, 4.4995, 2.4350, 2.4350, 2.4350], + [3.1236, 2.6278, 3.0447, 3.1236, 3.1236, 3.1236], + [2.6732, 2.8677, 2.6436, 2.6732, 2.6732, 2.6732], + [0.0124, 7.0150, 7.0199, 0.0124, 0.0124, 0.0124], + [0.3207, 0.0000, 0.3411, 0.3207, 0.3207, 0.3207]], + [[0.0000, 0.9544, 2.4532, 0.0000, 0.0000, 0.0000], + [0.5346, 1.9176, 1.4715, 0.5346, 0.5346, 0.5346], + [0.0000, 0.2744, 2.0842, 0.0000, 0.0000, 0.0000], + [0.3414, 1.5063, 1.6209, 0.3414, 0.3414, 0.3414], + [0.5814, 0.0103, 0.0000, 0.5814, 0.5814, 0.5814]]], + dtype=dtype).cuda() + + idx = torch.tensor([[[0, 1, 2], [2, 3, 4], [2, 3, 4], [0, 1, 2], [0, 1, 2], + [0, 1, 3]], + [[0, 2, 3], [1, 3, 4], [2, 1, 4], [0, 2, 4], [0, 2, 4], + [0, 1, 2]]]).int().cuda() + + weight = torch.tensor([[[3.3333e-01, 3.3333e-01, 3.3333e-01], + [1.0000e+00, 5.8155e-08, 2.2373e-08], + [1.0000e+00, 1.7737e-08, 1.7356e-08], + [3.3333e-01, 3.3333e-01, 3.3333e-01], + [3.3333e-01, 3.3333e-01, 3.3333e-01], + [3.3333e-01, 3.3333e-01, 3.3333e-01]], + [[3.3333e-01, 3.3333e-01, 3.3333e-01], + [1.0000e+00, 1.3651e-08, 7.7312e-09], + [1.0000e+00, 1.7148e-08, 1.4070e-08], + [3.3333e-01, 3.3333e-01, 3.3333e-01], + [3.3333e-01, 3.3333e-01, 3.3333e-01], + [3.3333e-01, 3.3333e-01, 3.3333e-01]]], + dtype=dtype).cuda() + + output = three_interpolate(features, idx, weight) + expected_output = torch.tensor([[[ + 3.8953e+00, 4.4995e+00, 4.4995e+00, 3.8953e+00, 3.8953e+00, 3.2072e+00 + ], [ + 2.9320e+00, 3.0447e+00, 3.0447e+00, 2.9320e+00, 2.9320e+00, 2.9583e+00 + ], [ + 2.7281e+00, 2.6436e+00, 2.6436e+00, 2.7281e+00, 2.7281e+00, 2.7380e+00 + ], [ + 4.6824e+00, 7.0199e+00, 7.0199e+00, 4.6824e+00, 4.6824e+00, 2.3466e+00 + ], [ + 2.2060e-01, 3.4110e-01, 3.4110e-01, 2.2060e-01, 2.2060e-01, 2.1380e-01 + ]], + [[ + 8.1773e-01, 9.5440e-01, 2.4532e+00, + 8.1773e-01, 8.1773e-01, 1.1359e+00 + ], + [ + 8.4689e-01, 1.9176e+00, 1.4715e+00, + 8.4689e-01, 8.4689e-01, 1.3079e+00 + ], + [ + 6.9473e-01, 2.7440e-01, 2.0842e+00, + 6.9473e-01, 6.9473e-01, 7.8619e-01 + ], + [ + 7.6789e-01, 1.5063e+00, 1.6209e+00, + 7.6789e-01, 7.6789e-01, 1.1562e+00 + ], + [ + 3.8760e-01, 1.0300e-02, 8.3569e-09, + 3.8760e-01, 3.8760e-01, 1.9723e-01 + ]]], + dtype=dtype).cuda() + + assert torch.allclose(output, expected_output, 1e-3, 1e-4) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_three_nn.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_three_nn.py new file mode 100644 index 000000000..456188b91 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_three_nn.py @@ -0,0 +1,65 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmcv.ops import three_nn +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE + +known = [[[-1.8373, 3.5605, -0.7867], [0.7615, 2.9420, 0.2314], + [-0.6503, 3.6637, -1.0622], [-1.8373, 3.5605, -0.7867], + [-1.8373, 3.5605, -0.7867]], + [[-1.3399, 1.9991, -0.3698], [-0.0799, 0.9698, -0.8457], + [0.0858, 2.4721, -0.1928], [-1.3399, 1.9991, -0.3698], + [-1.3399, 1.9991, -0.3698]]] + +unknown = [[[-1.8373, 3.5605, -0.7867], [0.7615, 2.9420, 0.2314], + [-0.6503, 3.6637, -1.0622], [-1.5237, 2.3976, -0.8097], + [-0.0722, 3.4017, -0.2880], [0.5198, 3.0661, -0.4605], + [-2.0185, 3.5019, -0.3236], [0.5098, 3.1020, 0.5799], + [-1.6137, 3.8443, -0.5269], [0.7341, 2.9626, -0.3189]], + [[-1.3399, 1.9991, -0.3698], [-0.0799, 0.9698, -0.8457], + [0.0858, 2.4721, -0.1928], [-0.9022, 1.6560, -1.3090], + [0.1156, 1.6901, -0.4366], [-0.6477, 2.3576, -0.1563], + [-0.8482, 1.1466, -1.2704], [-0.8753, 2.0845, -0.3460], + [-0.5621, 1.4233, -1.2858], [-0.5883, 1.3114, -1.2899]]] + +expected_dist = [[[0.0000, 0.0000, 0.0000], [0.0000, 2.0463, 2.8588], + [0.0000, 1.2229, 1.2229], [1.2047, 1.2047, 1.2047], + [1.0011, 1.0845, 1.8411], [0.7433, 1.4451, 2.4304], + [0.5007, 0.5007, 0.5007], [0.4587, 2.0875, 2.7544], + [0.4450, 0.4450, 0.4450], [0.5514, 1.7206, 2.6811]], + [[0.0000, 0.0000, 0.0000], [0.0000, 1.6464, 1.6952], + [0.0000, 1.5125, 1.5125], [1.0915, 1.0915, 1.0915], + [0.8197, 0.8511, 1.4894], [0.7433, 0.8082, 0.8082], + [0.8955, 1.3340, 1.3340], [0.4730, 0.4730, 0.4730], + [0.7949, 1.3325, 1.3325], [0.7566, 1.3727, 1.3727]]] + +expected_idx = [[[0, 3, 4], [1, 2, 0], [2, 0, 3], [0, 3, 4], [2, 1, 0], + [1, 2, 0], [0, 3, 4], [1, 2, 0], [0, 3, 4], [1, 2, 0]], + [[0, 3, 4], [1, 2, 0], [2, 0, 3], [0, 3, 4], [2, 1, 0], + [2, 0, 3], [1, 0, 3], [0, 3, 4], [1, 0, 3], [1, 0, 3]]] + + +@pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) +]) +@pytest.mark.parametrize('dtype,rtol', [(torch.float, 1e-8), + (torch.half, 1e-3)]) +def test_three_nn(device, dtype, rtol): + dtype = torch.float + known_t = torch.tensor(known, dtype=dtype, device=device) + unknown_t = torch.tensor(unknown, dtype=dtype, device=device) + + dist_t, idx_t = three_nn(unknown_t, known_t) + expected_dist_t = torch.tensor(expected_dist, dtype=dtype, device=device) + expected_idx_t = torch.tensor(expected_idx, device=device) + + assert torch.allclose(dist_t, expected_dist_t, atol=1e-4, rtol=rtol) + assert torch.all(idx_t == expected_idx_t) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_tin_shift.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_tin_shift.py new file mode 100644 index 000000000..c8ce14465 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_tin_shift.py @@ -0,0 +1,226 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os + +import numpy as np +import pytest +import torch + +from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE + +_USING_PARROTS = True +try: + from parrots.autograd import gradcheck +except ImportError: + from torch.autograd import gradcheck + + _USING_PARROTS = False + +cur_dir = os.path.dirname(os.path.abspath(__file__)) + +inputs = ([[[[0.88572276, 0.46422583], [0.97408265, 0.59547687], + [0.030812204, 0.96236038], [0.75418317, 0.44058233], + [0.33279222, 0.00084149837], [0.7069388, 0.23255438], + [0.13547045, 0.81549376], [0.40174931, 0.36317211]], + [[0.57444429, 0.15905505], [0.39897251, 0.25790238], + [0.93282568, 0.18451685], [0.92526674, 0.18283755], + [0.31664443, 0.59323865], [0.1957739, 0.42505842], + [0.081158757, 0.81340349], [0.43456328, 0.30195212]], + [[0.8198145, 0.05990988], [0.98062474, 0.34803438], + [0.10412294, 0.37183142], [0.15021622, 0.038857818], + [0.40985721, 0.42253625], [0.71150124, 0.59778064], + [0.83851069, 0.15194464], [0.097513378, 0.74820143]], + [[0.80680406, 0.49327564], [0.17821097, 0.12980539], + [0.50657678, 0.14446253], [0.04178369, 0.53071898], + [0.84983683, 0.3826949], [0.32193625, 0.91275406], + [0.75628334, 0.52934098], [0.27994192, 0.3053292]]], + [[[0.082397044, 0.4210068], [0.23563534, 0.7938987], + [0.63669145, 0.69397897], [0.8844561, 0.97854084], + [0.79027033, 0.60640401], [0.63528901, 0.72172403], + [0.0097346902, 0.70800996], [0.87891227, 0.13674974]], + [[0.74329448, 0.0243572], [0.82178867, 0.85750699], + [0.7568835, 0.73146772], [0.5031184, 0.30479157], + [0.28713053, 0.47414285], [0.4682079, 0.067471564], + [0.48368263, 0.14590704], [0.25397325, 0.19946373]], + [[0.4291026, 0.068739474], [0.7159555, 0.79903615], + [0.76412082, 0.85348046], [0.081224024, 0.82264912], + [0.97173303, 0.24291694], [0.48957139, 0.43488795], + [0.67382395, 0.21889746], [0.36712623, 0.67127824]], + [[0.12054044, 0.18096751], [0.86675781, 0.54755616], + [0.68208277, 0.15164375], [0.79991871, 0.80811197], + [0.85256428, 0.68253738], [0.185983, 0.95642138], + [0.48102546, 0.28009653], [0.35726011, 0.58168036]]]]) + +shifts = [([[1, 0, 1, -2], [-2, 1, -1, 1]]), ([[2, 1, 2, -1], [-1, 2, 0, 2]])] + +outputs = [([[[[0.0, 0.0], [0.0, 0.0], [0.030812, 0.96236], [0.75418, 0.44058], + [0.0, 0.0], [0.0, 0.0], [0.83851, 0.15194], [0.097513, 0.7482]], + [[0.88572, 0.46423], [0.97408, 0.59548], [0.93283, 0.18452], + [0.92527, 0.18284], [0.33279, 0.0008415], [0.70694, 0.23255], + [0.75628, 0.52934], [0.27994, 0.30533]], + [[0.57444, 0.15906], [0.39897, 0.2579], [0.10412, 0.37183], + [0.15022, 0.038858], [0.31664, 0.59324], [0.19577, 0.42506], + [0.0, 0.0], [0.0, 0.0]], + [[0.81981, 0.05991], [0.98062, 0.34803], [0.50658, 0.14446], + [0.041784, 0.53072], [0.40986, 0.42254], [0.7115, 0.59778], + [0.0, 0.0], [0.0, 0.0]]], + [[[0.4291, 0.068739], [0.71596, 0.79904], [0.0, 0.0], [0.0, 0.0], + [0.28713, 0.47414], [0.46821, 0.067472], [0.0, 0.0], [0.0, + 0.0]], + [[0.12054, 0.18097], [0.86676, 0.54756], [0.63669, 0.69398], + [0.88446, 0.97854], [0.97173, 0.24292], [0.48957, 0.43489], + [0.0097347, 0.70801], [0.87891, 0.13675]], + [[0.0, 0.0], [0.0, 0.0], [0.75688, 0.73147], [0.50312, 0.30479], + [0.85256, 0.68254], [0.18598, 0.95642], [0.48368, 0.14591], + [0.25397, 0.19946]], + [[0.0, 0.0], [0.0, 0.0], [0.76412, 0.85348], [0.081224, 0.82265], + [0.0, 0.0], [0.0, 0.0], [0.67382, 0.2189], [0.36713, + 0.67128]]]]), + ([[[[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], + [0.0, 0.0], [0.081159, 0.8134], [0.43456, 0.30195]], + [[0.0, 0.0], [0.0, 0.0], [0.030812, 0.96236], [0.75418, 0.44058], + [0.0, 0.0], [0.0, 0.0], [0.83851, 0.15194], [0.097513, 0.7482]], + [[0.88572, 0.46423], [0.97408, 0.59548], [0.93283, 0.18452], + [0.92527, 0.18284], [0.33279, 0.0008415], [0.70694, 0.23255], + [0.75628, 0.52934], [0.27994, 0.30533]], + [[0.57444, 0.15906], [0.39897, 0.2579], [0.10412, 0.37183], + [0.15022, 0.038858], [0.31664, 0.59324], [0.19577, 0.42506], + [0.0, 0.0], [0.0, 0.0]]], + [[[0.74329, 0.024357], [0.82179, 0.85751], [0.0, 0.0], [0.0, 0.0], + [0.79027, 0.6064], [0.63529, 0.72172], [0.0, 0.0], [0.0, 0.0]], + [[0.4291, 0.068739], [0.71596, 0.79904], [0.0, 0.0], [0.0, 0.0], + [0.28713, 0.47414], [0.46821, 0.067472], [0.0, 0.0], [0.0, + 0.0]], + [[0.12054, 0.18097], [0.86676, 0.54756], [0.63669, 0.69398], + [0.88446, 0.97854], [0.97173, 0.24292], [0.48957, 0.43489], + [0.0097347, 0.70801], [0.87891, 0.13675]], + [[0.0, 0.0], [0.0, 0.0], [0.75688, 0.73147], [0.50312, 0.30479], + [0.85256, 0.68254], [0.18598, 0.95642], [0.48368, 0.14591], + [0.25397, 0.19946]]]])] + +grads = [ + [[[[0., 0.], [0., 0.], [1., 1.], [1., 1.], [0., 0.], [0., 0.], [1., 1.], + [1., 1.]], + [[1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], + [1., 1.]], + [[1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [0., 0.], + [0., 0.]], + [[1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [0., 0.], + [0., 0.]]], + [[[1., 1.], [1., 1.], [0., 0.], [0., 0.], [1., 1.], [1., 1.], [0., 0.], + [0., 0.]], + [[1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], + [1., 1.]], + [[0., 0.], [0., 0.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], + [1., 1.]], + [[0., 0.], [0., 0.], [1., 1.], [1., 1.], [0., 0.], [0., 0.], [1., 1.], + [1., 1.]]]], + [[[[0., 0.], [0., 0.], [0., 0.], [0., 0.], [0., 0.], [0., 0.], [1., 1.], + [1., 1.]], + [[0., 0.], [0., 0.], [1., 1.], [1., 1.], [0., 0.], [0., 0.], [1., 1.], + [1., 1.]], + [[1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], + [1., 1.]], + [[1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [0., 0.], + [0., 0.]]], + [[[1., 1.], [1., 1.], [0., 0.], [0., 0.], [1., 1.], [1., 1.], [0., 0.], + [0., 0.]], + [[1., 1.], [1., 1.], [0., 0.], [0., 0.], [1., 1.], [1., 1.], [0., 0.], + [0., 0.]], + [[1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], + [1., 1.]], + [[0., 0.], [0., 0.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.], + [1., 1.]]]] +] + + +def _test_tinshift_gradcheck(device, dtype): + try: + from mmcv.ops import tin_shift + except ModuleNotFoundError: + pytest.skip('TINShift op is not successfully compiled') + + if dtype == torch.half: + pytest.skip('"add_cpu/sub_cpu" not implemented for Half') + + for shift in shifts: + np_input = np.array(inputs) + np_shift = np.array(shift) + + x = torch.tensor( + np_input, dtype=dtype, device=device, requires_grad=True) + shift = torch.tensor(np_shift, device=device).int() + if torch.__version__ == 'parrots': + gradcheck(tin_shift, (x, shift)) + else: + gradcheck(tin_shift, (x, shift), atol=1, rtol=0.1) + + +def _test_tinshift_allclose(device, dtype): + try: + from mmcv.ops import tin_shift + except ModuleNotFoundError: + pytest.skip('TINShift op is not successfully compiled') + + for shift, output, grad in zip(shifts, outputs, grads): + np_input = np.array(inputs) + np_shift = np.array(shift) + np_output = np.array(output) + np_grad = np.array(grad) + + x = torch.tensor( + np_input, dtype=dtype, device=device, requires_grad=True) + shift = torch.tensor(np_shift, device=device).int() + + output = tin_shift(x, shift) + output.backward(torch.ones_like(output)) + assert np.allclose( + output.data.type(torch.float).cpu().numpy(), np_output, 1e-3) + assert np.allclose( + x.grad.data.type(torch.float).cpu().numpy(), np_grad, 1e-3) + + +def _test_tinshift_assert(device, dtype): + try: + from mmcv.ops import tin_shift + except ModuleNotFoundError: + pytest.skip('TINShift op is not successfully compiled') + + inputs = [ + torch.rand(2, 3, 4, 2), + torch.rand(2, 3, 4, 2), + torch.rand(1, 3, 4, 2) + ] + shifts = [torch.rand(2, 3), torch.rand(2, 5)] + + for x, shift in zip(inputs, shifts): + x = x.to(device).type(dtype) + shift = shift.to(device).type(dtype) + + # A ValueError should be raised if ops get inputs with wrong shapes. + with pytest.raises(ValueError): + tin_shift(x, shift) + + +@pytest.mark.parametrize('device', [ + pytest.param( + 'cuda', + marks=pytest.mark.skipif( + not IS_CUDA_AVAILABLE, reason='requires CUDA support')), + pytest.param( + 'mlu', + marks=pytest.mark.skipif( + not IS_MLU_AVAILABLE, reason='requires MLU support')) +]) +@pytest.mark.parametrize('dtype', [ + torch.float, + pytest.param( + torch.double, + marks=pytest.mark.skipif( + IS_MLU_AVAILABLE, + reason='MLU does not support for 64-bit floating point')), + torch.half +]) +def test_tinshift(device, dtype): + _test_tinshift_allclose(device=device, dtype=dtype) + _test_tinshift_gradcheck(device=device, dtype=dtype) + _test_tinshift_assert(device=device, dtype=dtype) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_upfirdn2d.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_upfirdn2d.py new file mode 100644 index 000000000..6037a51c2 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_upfirdn2d.py @@ -0,0 +1,58 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +_USING_PARROTS = True +try: + from parrots.autograd import gradcheck +except ImportError: + from torch.autograd import gradcheck, gradgradcheck + _USING_PARROTS = False + + +class TestUpFirDn2d: + """Unit test for UpFirDn2d. + + Here, we just test the basic case of upsample version. More gerneal tests + will be included in other unit test for UpFirDnUpsample and + UpFirDnDownSample modules. + """ + + @classmethod + def setup_class(cls): + kernel_1d = torch.tensor([1., 3., 3., 1.]) + cls.kernel = kernel_1d[:, None] * kernel_1d[None, :] + cls.kernel = cls.kernel / cls.kernel.sum() + cls.factor = 2 + pad = cls.kernel.shape[0] - cls.factor + cls.pad = ((pad + 1) // 2 + cls.factor - 1, pad // 2) + + cls.input_tensor = torch.randn((2, 3, 4, 4), requires_grad=True) + + @pytest.mark.skipif(not torch.cuda.is_available(), reason='requires cuda') + def test_upfirdn2d(self): + from mmcv.ops import upfirdn2d + if _USING_PARROTS: + gradcheck( + upfirdn2d, + (self.input_tensor.cuda(), + self.kernel.type_as( + self.input_tensor).cuda(), self.factor, 1, self.pad), + delta=1e-4, + pt_atol=1e-3) + else: + gradcheck( + upfirdn2d, + (self.input_tensor.cuda(), + self.kernel.type_as( + self.input_tensor).cuda(), self.factor, 1, self.pad), + eps=1e-4, + atol=1e-3) + + gradgradcheck( + upfirdn2d, + (self.input_tensor.cuda(), + self.kernel.type_as( + self.input_tensor).cuda(), self.factor, 1, self.pad), + eps=1e-4, + atol=1e-3) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_voxelization.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_voxelization.py new file mode 100644 index 000000000..d3555ac69 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_voxelization.py @@ -0,0 +1,139 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest +import torch + +from mmcv.ops import Voxelization + + +def _get_voxel_points_indices(points, coors, voxel): + result_form = np.equal(coors, voxel) + return result_form[:, 0] & result_form[:, 1] & result_form[:, 2] + + +@pytest.mark.parametrize('device_type', [ + 'cpu', + pytest.param( + 'cuda:0', + marks=pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support')) +]) +def test_voxelization(device_type): + voxel_size = [0.5, 0.5, 0.5] + point_cloud_range = [0, -40, -3, 70.4, 40, 1] + + voxel_dict = np.load( + 'tests/data/for_3d_ops/test_voxel.npy', allow_pickle=True).item() + expected_coors = voxel_dict['coors'] + expected_voxels = voxel_dict['voxels'] + expected_num_points_per_voxel = voxel_dict['num_points_per_voxel'] + points = voxel_dict['points'] + + points = torch.tensor(points) + max_num_points = -1 + dynamic_voxelization = Voxelization(voxel_size, point_cloud_range, + max_num_points) + max_num_points = 1000 + hard_voxelization = Voxelization(voxel_size, point_cloud_range, + max_num_points) + + device = torch.device(device_type) + + # test hard_voxelization on cpu/gpu + points = points.contiguous().to(device) + coors, voxels, num_points_per_voxel = hard_voxelization.forward(points) + coors = coors.cpu().detach().numpy() + voxels = voxels.cpu().detach().numpy() + num_points_per_voxel = num_points_per_voxel.cpu().detach().numpy() + assert np.all(coors == expected_coors) + assert np.all(voxels == expected_voxels) + assert np.all(num_points_per_voxel == expected_num_points_per_voxel) + + # test dynamic_voxelization on cpu/gpu + coors = dynamic_voxelization.forward(points) + coors = coors.cpu().detach().numpy() + points = points.cpu().detach().numpy() + for i in range(expected_voxels.shape[0]): + indices = _get_voxel_points_indices(points, coors, expected_voxels[i]) + num_points_current_voxel = points[indices].shape[0] + assert num_points_current_voxel > 0 + assert np.all( + points[indices] == expected_coors[i][:num_points_current_voxel]) + assert num_points_current_voxel == expected_num_points_per_voxel[i] + + +@pytest.mark.skipif( + not torch.cuda.is_available(), reason='requires CUDA support') +def test_voxelization_nondeterministic(): + voxel_size = [0.5, 0.5, 0.5] + point_cloud_range = [0, -40, -3, 70.4, 40, 1] + + voxel_dict = np.load( + 'tests/data/for_3d_ops/test_voxel.npy', allow_pickle=True).item() + points = voxel_dict['points'] + + points = torch.tensor(points) + max_num_points = -1 + dynamic_voxelization = Voxelization(voxel_size, point_cloud_range, + max_num_points) + + max_num_points = 10 + max_voxels = 50 + hard_voxelization = Voxelization( + voxel_size, + point_cloud_range, + max_num_points, + max_voxels, + deterministic=False) + + # test hard_voxelization (non-deterministic version) on gpu + points = torch.tensor(points).contiguous().to(device='cuda:0') + voxels, coors, num_points_per_voxel = hard_voxelization.forward(points) + coors = coors.cpu().detach().numpy().tolist() + voxels = voxels.cpu().detach().numpy().tolist() + num_points_per_voxel = num_points_per_voxel.cpu().detach().numpy().tolist() + + coors_all = dynamic_voxelization.forward(points) + coors_all = coors_all.cpu().detach().numpy().tolist() + + coors_set = {tuple(c) for c in coors} + coors_all_set = {tuple(c) for c in coors_all} + + assert len(coors_set) == len(coors) + assert len(coors_set - coors_all_set) == 0 + + points = points.cpu().detach().numpy().tolist() + + coors_points_dict = {} + for c, ps in zip(coors_all, points): + if tuple(c) not in coors_points_dict: + coors_points_dict[tuple(c)] = set() + coors_points_dict[tuple(c)].add(tuple(ps)) + + for c, ps, n in zip(coors, voxels, num_points_per_voxel): + ideal_voxel_points_set = coors_points_dict[tuple(c)] + voxel_points_set = {tuple(p) for p in ps[:n]} + assert len(voxel_points_set) == n + if n < max_num_points: + assert voxel_points_set == ideal_voxel_points_set + for p in ps[n:]: + assert max(p) == min(p) == 0 + else: + assert len(voxel_points_set - ideal_voxel_points_set) == 0 + + # test hard_voxelization (non-deterministic version) on gpu + # with all input point in range + points = torch.tensor(points).contiguous().to(device='cuda:0')[:max_voxels] + coors_all = dynamic_voxelization.forward(points) + valid_mask = coors_all.ge(0).all(-1) + points = points[valid_mask] + coors_all = coors_all[valid_mask] + coors_all = coors_all.cpu().detach().numpy().tolist() + + voxels, coors, num_points_per_voxel = hard_voxelization.forward(points) + coors = coors.cpu().detach().numpy().tolist() + + coors_set = {tuple(c) for c in coors} + coors_all_set = {tuple(c) for c in coors_all} + + assert len(coors_set) == len(coors) == len(coors_all_set) diff --git a/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_formatting.py b/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_formatting.py new file mode 100644 index 000000000..96abc8c22 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_formatting.py @@ -0,0 +1,101 @@ +# Copyright (c) OpenMMLab. All rights reserved. +try: + import torch +except ModuleNotFoundError: + torch = None +else: + from mmcv.transforms import ToTensor, to_tensor, ImageToTensor + +import copy + +import numpy as np +import pytest + + +@pytest.mark.skipif(condition=torch is None, reason='No torch in current env') +def test_to_tensor(): + + # The type of the input object is torch.Tensor + data_tensor = torch.tensor([1, 2, 3]) + tensor_from_tensor = to_tensor(data_tensor) + assert isinstance(tensor_from_tensor, torch.Tensor) + + # The type of the input object is numpy.ndarray + data_numpy = np.array([1, 2, 3]) + tensor_from_numpy = to_tensor(data_numpy) + assert isinstance(tensor_from_numpy, torch.Tensor) + + # The type of the input object is list + data_list = [1, 2, 3] + tensor_from_list = to_tensor(data_list) + assert isinstance(tensor_from_list, torch.Tensor) + + # The type of the input object is int + data_int = 1 + tensor_from_int = to_tensor(data_int) + assert isinstance(tensor_from_int, torch.Tensor) + + # The type of the input object is float + data_float = 1.0 + tensor_from_float = to_tensor(data_float) + assert isinstance(tensor_from_float, torch.Tensor) + + # The type of the input object is invalid + with pytest.raises(TypeError): + data_str = '123' + _ = to_tensor(data_str) + + +@pytest.mark.skipif(condition=torch is None, reason='No torch in current env') +class TestToTensor: + + def test_init(self): + TRANSFORM = ToTensor(keys=['img_label']) + assert TRANSFORM.keys == ['img_label'] + + def test_transform(self): + TRANSFORMS = ToTensor(['instances.bbox', 'img_label']) + + # Test multi-level key and single-level key (multi-level key is + # not in results) + with pytest.raises(KeyError): + results = {'instances': {'label': [1]}, 'img_label': [1]} + results_tensor = TRANSFORMS.transform(copy.deepcopy(results)) + assert isinstance(results_tensor['instances']['label'], list) + assert isinstance(results_tensor['img_label'], torch.Tensor) + + # Test multi-level key (multi-level key is in results) + results = {'instances': {'bbox': [[0, 0, 10, 10]]}, 'img_label': [1]} + results_tensor = TRANSFORMS.transform(copy.deepcopy(results)) + assert isinstance(results_tensor['instances']['bbox'], torch.Tensor) + + def test_repr(self): + TRANSFORMS = ToTensor(['instances.bbox', 'img_label']) + TRANSFORMS_str = str(TRANSFORMS) + isinstance(TRANSFORMS_str, str) + + +@pytest.mark.skipif(condition=torch is None, reason='No torch in current env') +class TestImageToTensor: + + def test_init(self): + TRANSFORMS = ImageToTensor(['img']) + assert TRANSFORMS.keys == ['img'] + + def test_transform(self): + TRANSFORMS = ImageToTensor(['img']) + + # image only has one channel + results = {'img': np.zeros((224, 224))} + results = TRANSFORMS.transform(results) + assert results['img'].shape == (1, 224, 224) + + # image has three channels + results = {'img': np.zeros((224, 224, 3))} + results = TRANSFORMS.transform(results) + assert results['img'].shape == (3, 224, 224) + + def test_repr(self): + TRANSFORMS = ImageToTensor(['img']) + TRANSFORMS_str = str(TRANSFORMS) + assert isinstance(TRANSFORMS_str, str) diff --git a/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_loading.py b/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_loading.py new file mode 100644 index 000000000..918783c99 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_loading.py @@ -0,0 +1,151 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os.path as osp + +import numpy as np +import pytest + +from mmcv.transforms import LoadAnnotations, LoadImageFromFile + + +class TestLoadImageFromFile: + + def test_load_img(self): + # file_client_args and backend_args can not be both set + with pytest.raises( + ValueError, + match='"file_client_args" and "backend_args" cannot be set'): + LoadImageFromFile( + file_client_args={'backend': 'disk'}, + backend_args={'backend': 'disk'}) + data_prefix = osp.join(osp.dirname(__file__), '../data') + + results = dict(img_path=osp.join(data_prefix, 'color.jpg')) + transform = LoadImageFromFile() + results = transform(copy.deepcopy(results)) + assert results['img_path'] == osp.join(data_prefix, 'color.jpg') + assert results['img'].shape == (300, 400, 3) + assert results['img'].dtype == np.uint8 + assert results['img_shape'] == (300, 400) + assert results['ori_shape'] == (300, 400) + assert repr(transform) == transform.__class__.__name__ + \ + "(ignore_empty=False, to_float32=False, color_type='color', " + \ + "imdecode_backend='cv2', backend_args=None)" + + # to_float32 + transform = LoadImageFromFile(to_float32=True) + results = transform(copy.deepcopy(results)) + assert results['img'].dtype == np.float32 + + # gray image + results = dict(img_path=osp.join(data_prefix, 'grayscale.jpg')) + transform = LoadImageFromFile() + results = transform(copy.deepcopy(results)) + assert results['img'].shape == (300, 400, 3) + assert results['img'].dtype == np.uint8 + + transform = LoadImageFromFile(color_type='unchanged') + results = transform(copy.deepcopy(results)) + assert results['img'].shape == (300, 400) + assert results['img'].dtype == np.uint8 + + # test load empty + fake_img_path = osp.join(data_prefix, 'fake.jpg') + results['img_path'] = fake_img_path + transform = LoadImageFromFile(ignore_empty=False) + with pytest.raises(FileNotFoundError): + transform(copy.deepcopy(results)) + transform = LoadImageFromFile(ignore_empty=True) + assert transform(copy.deepcopy(results)) is None + + +class TestLoadAnnotations: + + def setup_class(cls): + data_prefix = osp.join(osp.dirname(__file__), '../data') + seg_map = osp.join(data_prefix, 'grayscale.jpg') + cls.results = { + 'seg_map_path': + seg_map, + 'instances': [{ + 'bbox': [0, 0, 10, 20], + 'bbox_label': 1, + 'keypoints': [1, 2, 3] + }, { + 'bbox': [10, 10, 110, 120], + 'bbox_label': 2, + 'keypoints': [4, 5, 6] + }] + } + + def test_init(self): + # file_client_args and backend_args can not be both set + with pytest.raises( + ValueError, + match='"file_client_args" and "backend_args" cannot be set'): + LoadAnnotations( + file_client_args={'backend': 'disk'}, + backend_args={'backend': 'disk'}) + + def test_load_bboxes(self): + transform = LoadAnnotations( + with_bbox=True, + with_label=False, + with_seg=False, + with_keypoints=False, + ) + results = transform(copy.deepcopy(self.results)) + assert 'gt_bboxes' in results + assert (results['gt_bboxes'] == np.array([[0, 0, 10, 20], + [10, 10, 110, 120]])).all() + assert results['gt_bboxes'].dtype == np.float32 + + def test_load_labels(self): + transform = LoadAnnotations( + with_bbox=False, + with_label=True, + with_seg=False, + with_keypoints=False, + ) + results = transform(copy.deepcopy(self.results)) + assert 'gt_bboxes_labels' in results + assert (results['gt_bboxes_labels'] == np.array([1, 2])).all() + assert results['gt_bboxes_labels'].dtype == np.int64 + + def test_load_kps(self): + transform = LoadAnnotations( + with_bbox=False, + with_label=False, + with_seg=False, + with_keypoints=True, + ) + results = transform(copy.deepcopy(self.results)) + assert 'gt_keypoints' in results + assert (results['gt_keypoints'] == np.array([[[1, 2, 3]], + [[4, 5, 6]]])).all() + assert results['gt_keypoints'].dtype == np.float32 + + def test_load_seg_map(self): + transform = LoadAnnotations( + with_bbox=False, + with_label=False, + with_seg=True, + with_keypoints=False, + ) + results = transform(copy.deepcopy(self.results)) + assert 'gt_seg_map' in results + assert results['gt_seg_map'].shape[:2] == (300, 400) + assert results['gt_seg_map'].dtype == np.uint8 + + def test_repr(self): + transform = LoadAnnotations( + with_bbox=True, + with_label=False, + with_seg=False, + with_keypoints=False, + ) + assert repr(transform) == ( + 'LoadAnnotations(with_bbox=True, ' + 'with_label=False, with_seg=False, ' + "with_keypoints=False, imdecode_backend='cv2', " + 'backend_args=None)') diff --git a/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_processing.py b/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_processing.py new file mode 100644 index 000000000..716b9cf26 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_processing.py @@ -0,0 +1,1014 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os.path as osp +from unittest.mock import Mock + +import numpy as np +import pytest + +import mmcv +from mmcv.transforms import (TRANSFORMS, Normalize, Pad, RandomFlip, + RandomResize, Resize, TestTimeAug) +from mmcv.transforms.base import BaseTransform + +try: + import torch +except ModuleNotFoundError: + torch = None +else: + import torchvision + +from numpy.testing import assert_array_almost_equal, assert_array_equal +from PIL import Image + + +class TestNormalize: + + def test_normalize(self): + img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + to_rgb=True) + transform = Normalize(**img_norm_cfg) + results = dict() + img = mmcv.imread( + osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color') + original_img = copy.deepcopy(img) + results['img'] = img + results = transform(results) + mean = np.array(img_norm_cfg['mean']) + std = np.array(img_norm_cfg['std']) + converted_img = (original_img[..., ::-1] - mean) / std + assert np.allclose(results['img'], converted_img) + + def test_repr(self): + img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + to_rgb=True) + transform = Normalize(**img_norm_cfg) + assert repr(transform) == ('Normalize(mean=[123.675 116.28 103.53 ], ' + 'std=[58.395 57.12 57.375], to_rgb=True)') + + +class TestResize: + + def test_resize(self): + data_info = dict( + img=np.random.random((1333, 800, 3)), + gt_seg_map=np.random.random((1333, 800, 3)), + gt_bboxes=np.array([[0, 0, 112, 112]]), + gt_keypoints=np.array([[[20, 50, 1]]])) + + with pytest.raises(AssertionError): + transform = Resize(scale=None, scale_factor=None) + with pytest.raises(TypeError): + transform = Resize(scale_factor=[]) + # test scale is int + transform = Resize(scale=2000) + results = transform(copy.deepcopy(data_info)) + assert results['img'].shape[:2] == (2000, 2000) + assert results['scale_factor'] == (2000 / 800, 2000 / 1333) + + # test scale is tuple + transform = Resize(scale=(2000, 2000)) + results = transform(copy.deepcopy(data_info)) + assert results['img'].shape[:2] == (2000, 2000) + assert results['scale_factor'] == (2000 / 800, 2000 / 1333) + + # test scale_factor is float + transform = Resize(scale_factor=2.0) + results = transform(copy.deepcopy(data_info)) + assert results['img'].shape[:2] == (2666, 1600) + assert results['scale_factor'] == (2.0, 2.0) + + # test scale_factor is tuple + transform = Resize(scale_factor=(1.5, 2)) + results = transform(copy.deepcopy(data_info)) + assert results['img'].shape[:2] == (2666, 1200) + assert results['scale_factor'] == (1.5, 2) + + # test keep_ratio is True + transform = Resize(scale=(2000, 2000), keep_ratio=True) + results = transform(copy.deepcopy(data_info)) + assert results['img'].shape[:2] == (2000, 1200) + assert results['scale_factor'] == (1200 / 800, 2000 / 1333) + + # test resize_bboxes/seg/kps + transform = Resize(scale_factor=(1.5, 2)) + results = transform(copy.deepcopy(data_info)) + assert (results['gt_bboxes'] == np.array([[0, 0, 168, 224]])).all() + assert (results['gt_keypoints'] == np.array([[[30, 100, 1]]])).all() + assert results['gt_seg_map'].shape[:2] == (2666, 1200) + + # test clip_object_border = False + data_info = dict( + img=np.random.random((300, 400, 3)), + gt_bboxes=np.array([[200, 150, 600, 450]])) + transform = Resize(scale=(200, 150), clip_object_border=False) + results = transform(data_info) + assert (results['gt_bboxes'] == np.array([100, 75, 300, 225])).all() + + def test_repr(self): + transform = Resize(scale=(2000, 2000), keep_ratio=True) + assert repr(transform) == ('Resize(scale=(2000, 2000), ' + 'scale_factor=None, keep_ratio=True, ' + 'clip_object_border=True), backend=cv2), ' + 'interpolation=bilinear)') + + +class TestPad: + + def test_pad(self): + # test size and size_divisor are both set + with pytest.raises(AssertionError): + Pad(size=(10, 10), size_divisor=2) + + # test size and size_divisor are both None + with pytest.raises(AssertionError): + Pad(size=None, size_divisor=None) + + # test size and pad_to_square are both None + with pytest.raises(AssertionError): + Pad(size=(10, 10), pad_to_square=True) + + # test pad_val is not int or tuple + with pytest.raises(AssertionError): + Pad(size=(10, 10), pad_val=[]) + + # test padding_mode is not 'constant', 'edge', 'reflect' or 'symmetric' + with pytest.raises(AssertionError): + Pad(size=(10, 10), padding_mode='edg') + + data_info = dict( + img=np.random.random((1333, 800, 3)), + gt_seg_map=np.random.random((1333, 800, 3)), + gt_bboxes=np.array([[0, 0, 112, 112]]), + gt_keypoints=np.array([[[20, 50, 1]]])) + + # test pad img / gt_seg_map with size + trans = Pad(size=(1200, 2000)) + results = trans(copy.deepcopy(data_info)) + assert results['img'].shape[:2] == (2000, 1200) + assert results['gt_seg_map'].shape[:2] == (2000, 1200) + + # test pad img/gt_seg_map with size_divisor + trans = Pad(size_divisor=11) + results = trans(copy.deepcopy(data_info)) + assert results['img'].shape[:2] == (1342, 803) + assert results['gt_seg_map'].shape[:2] == (1342, 803) + + # test pad img/gt_seg_map with pad_to_square + trans = Pad(pad_to_square=True) + results = trans(copy.deepcopy(data_info)) + assert results['img'].shape[:2] == (1333, 1333) + assert results['gt_seg_map'].shape[:2] == (1333, 1333) + + # test pad img/gt_seg_map with pad_to_square and size_divisor + trans = Pad(pad_to_square=True, size_divisor=11) + results = trans(copy.deepcopy(data_info)) + assert results['img'].shape[:2] == (1342, 1342) + assert results['gt_seg_map'].shape[:2] == (1342, 1342) + + # test pad img/gt_seg_map with pad_to_square and size_divisor + trans = Pad(pad_to_square=True, size_divisor=11) + results = trans(copy.deepcopy(data_info)) + assert results['img'].shape[:2] == (1342, 1342) + assert results['gt_seg_map'].shape[:2] == (1342, 1342) + + # test padding_mode + new_img = np.ones((1333, 800, 3)) + data_info['img'] = new_img + trans = Pad(pad_to_square=True, padding_mode='edge') + results = trans(copy.deepcopy(data_info)) + assert (results['img'] == np.ones((1333, 1333, 3))).all() + + # test pad_val is dict + # test rgb image, size=(2000, 2000) + trans = Pad( + size=(2000, 2000), + pad_val=dict(img=(12, 12, 12), seg=(10, 10, 10))) + results = trans(copy.deepcopy(data_info)) + assert (results['img'][1333:2000, 800:2000, :] == 12).all() + assert (results['gt_seg_map'][1333:2000, 800:2000, :] == 10).all() + + trans = Pad(size=(2000, 2000), pad_val=dict(img=(12, 12, 12))) + results = trans(copy.deepcopy(data_info)) + assert (results['img'][1333:2000, 800:2000, :] == 12).all() + assert (results['gt_seg_map'][1333:2000, 800:2000, :] == 255).all() + + # test rgb image, pad_to_square=True + trans = Pad( + pad_to_square=True, + pad_val=dict(img=(12, 12, 12), seg=(10, 10, 10))) + results = trans(copy.deepcopy(data_info)) + assert (results['img'][:, 800:1333, :] == 12).all() + assert (results['gt_seg_map'][:, 800:1333, :] == 10).all() + + trans = Pad(pad_to_square=True, pad_val=dict(img=(12, 12, 12))) + results = trans(copy.deepcopy(data_info)) + assert (results['img'][:, 800:1333, :] == 12).all() + assert (results['gt_seg_map'][:, 800:1333, :] == 255).all() + + # test pad_val is int + # test rgb image + trans = Pad(size=(2000, 2000), pad_val=12) + results = trans(copy.deepcopy(data_info)) + assert (results['img'][1333:2000, 800:2000, :] == 12).all() + assert (results['gt_seg_map'][1333:2000, 800:2000, :] == 255).all() + # test gray image + new_img = np.random.random((1333, 800)) + data_info['img'] = new_img + new_semantic_seg = np.random.random((1333, 800)) + data_info['gt_seg_map'] = new_semantic_seg + trans = Pad(size=(2000, 2000), pad_val=12) + results = trans(copy.deepcopy(data_info)) + assert (results['img'][1333:2000, 800:2000] == 12).all() + assert (results['gt_seg_map'][1333:2000, 800:2000] == 255).all() + + def test_repr(self): + trans = Pad(pad_to_square=True, size_divisor=11, padding_mode='edge') + assert repr(trans) == ( + 'Pad(size=None, size_divisor=11, pad_to_square=True, ' + "pad_val={'img': 0, 'seg': 255}), padding_mode=edge)") + + +class TestCenterCrop: + + @classmethod + def setup_class(cls): + img = mmcv.imread( + osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color') + cls.original_img = copy.deepcopy(img) + seg = np.random.randint(0, 19, (300, 400)).astype(np.uint8) + cls.gt_semantic_map = copy.deepcopy(seg) + + @staticmethod + def reset_results(results, original_img, gt_semantic_map): + results['img'] = copy.deepcopy(original_img) + results['gt_seg_map'] = copy.deepcopy(gt_semantic_map) + results['gt_bboxes'] = np.array([[0, 0, 210, 160], + [200, 150, 400, 300]]) + results['gt_keypoints'] = np.array([[[20, 50, 1]], [[200, 150, 1]], + [[300, 225, 1]]]) + return results + + @pytest.mark.skipif( + condition=torch is None, reason='No torch in current env') + def test_error(self): + # test assertion if size is smaller than 0 + with pytest.raises(AssertionError): + transform = dict(type='CenterCrop', crop_size=-1) + TRANSFORMS.build(transform) + + # test assertion if size is tuple but one value is smaller than 0 + with pytest.raises(AssertionError): + transform = dict(type='CenterCrop', crop_size=(224, -1)) + TRANSFORMS.build(transform) + + # test assertion if size is tuple and len(size) < 2 + with pytest.raises(AssertionError): + transform = dict(type='CenterCrop', crop_size=(224, )) + TRANSFORMS.build(transform) + + # test assertion if size is tuple len(size) > 2 + with pytest.raises(AssertionError): + transform = dict(type='CenterCrop', crop_size=(224, 224, 3)) + TRANSFORMS.build(transform) + + def test_repr(self): + # test repr + transform = dict(type='CenterCrop', crop_size=224) + center_crop_module = TRANSFORMS.build(transform) + assert isinstance(repr(center_crop_module), str) + + def test_transform(self): + results = {} + self.reset_results(results, self.original_img, self.gt_semantic_map) + + # test CenterCrop when size is int + transform = dict(type='CenterCrop', crop_size=224) + center_crop_module = TRANSFORMS.build(transform) + results = center_crop_module(results) + assert results['img_shape'] == (224, 224) + assert (results['img'] == self.original_img[38:262, 88:312, ...]).all() + assert (results['gt_seg_map'] == self.gt_semantic_map[38:262, + 88:312]).all() + assert np.equal(results['gt_bboxes'], + np.array([[0, 0, 122, 122], [112, 112, 224, + 224]])).all() + assert np.equal( + results['gt_keypoints'], + np.array([[[0, 12, 0]], [[112, 112, 1]], [[212, 187, 1]]])).all() + + # test CenterCrop when size is tuple + transform = dict(type='CenterCrop', crop_size=(224, 224)) + center_crop_module = TRANSFORMS.build(transform) + results = self.reset_results(results, self.original_img, + self.gt_semantic_map) + results = center_crop_module(results) + assert results['img_shape'] == (224, 224) + assert (results['img'] == self.original_img[38:262, 88:312, ...]).all() + assert (results['gt_seg_map'] == self.gt_semantic_map[38:262, + 88:312]).all() + assert np.equal(results['gt_bboxes'], + np.array([[0, 0, 122, 122], [112, 112, 224, + 224]])).all() + assert np.equal( + results['gt_keypoints'], + np.array([[[0, 12, 0]], [[112, 112, 1]], [[212, 187, 1]]])).all() + + # test CenterCrop when crop_height != crop_width + transform = dict(type='CenterCrop', crop_size=(224, 256)) + center_crop_module = TRANSFORMS.build(transform) + results = self.reset_results(results, self.original_img, + self.gt_semantic_map) + results = center_crop_module(results) + assert results['img_shape'] == (256, 224) + assert (results['img'] == self.original_img[22:278, 88:312, ...]).all() + assert (results['gt_seg_map'] == self.gt_semantic_map[22:278, + 88:312]).all() + assert np.equal(results['gt_bboxes'], + np.array([[0, 0, 122, 138], [112, 128, 224, + 256]])).all() + assert np.equal( + results['gt_keypoints'], + np.array([[[0, 28, 0]], [[112, 128, 1]], [[212, 203, 1]]])).all() + + # test CenterCrop when crop_size is equal to img.shape + img_height, img_width, _ = self.original_img.shape + transform = dict(type='CenterCrop', crop_size=(img_width, img_height)) + center_crop_module = TRANSFORMS.build(transform) + results = self.reset_results(results, self.original_img, + self.gt_semantic_map) + results = center_crop_module(results) + assert results['img_shape'] == (300, 400) + assert (results['img'] == self.original_img).all() + assert (results['gt_seg_map'] == self.gt_semantic_map).all() + assert np.equal(results['gt_bboxes'], + np.array([[0, 0, 210, 160], [200, 150, 400, + 300]])).all() + assert np.equal( + results['gt_keypoints'], + np.array([[[20, 50, 1]], [[200, 150, 1]], [[300, 225, 1]]])).all() + + # test CenterCrop when crop_size is larger than img.shape + transform = dict( + type='CenterCrop', crop_size=(img_width * 2, img_height * 2)) + center_crop_module = TRANSFORMS.build(transform) + results = self.reset_results(results, self.original_img, + self.gt_semantic_map) + results = center_crop_module(results) + assert results['img_shape'] == (300, 400) + assert (results['img'] == self.original_img).all() + assert (results['gt_seg_map'] == self.gt_semantic_map).all() + assert np.equal(results['gt_bboxes'], + np.array([[0, 0, 210, 160], [200, 150, 400, + 300]])).all() + assert np.equal( + results['gt_keypoints'], + np.array([[[20, 50, 1]], [[200, 150, 1]], [[300, 225, 1]]])).all() + + # test with padding + transform = dict( + type='CenterCrop', + crop_size=(img_width // 2, img_height * 2), + auto_pad=True, + pad_cfg=dict(type='Pad', padding_mode='constant', pad_val=12)) + center_crop_module = TRANSFORMS.build(transform) + results = self.reset_results(results, self.original_img, + self.gt_semantic_map) + results = center_crop_module(results) + assert results['img_shape'] == (600, 200) + assert results['img'].shape[:2] == results['gt_seg_map'].shape + assert (results['img'][300:600, 100:300, ...] == 12).all() + assert (results['gt_seg_map'][300:600, 100:300] == 255).all() + assert np.equal(results['gt_bboxes'], + np.array([[0, 0, 110, 160], [100, 150, 200, + 300]])).all() + assert np.equal( + results['gt_keypoints'], + np.array([[[0, 50, 0]], [[100, 150, 1]], [[200, 225, 0]]])).all() + + transform = dict( + type='CenterCrop', + crop_size=(img_width // 2, img_height * 2), + auto_pad=True, + pad_cfg=dict( + type='Pad', + padding_mode='constant', + pad_val=dict(img=13, seg=33))) + center_crop_module = TRANSFORMS.build(transform) + results = self.reset_results(results, self.original_img, + self.gt_semantic_map) + results = center_crop_module(results) + assert results['img_shape'] == (600, 200) + assert (results['img'][300:600, 100:300, ...] == 13).all() + assert (results['gt_seg_map'][300:600, 100:300] == 33).all() + assert np.equal(results['gt_bboxes'], + np.array([[0, 0, 110, 160], [100, 150, 200, + 300]])).all() + assert np.equal( + results['gt_keypoints'], + np.array([[[0, 50, 0]], [[100, 150, 1]], [[200, 225, 0]]])).all() + + # test CenterCrop when crop_width is smaller than img_width + transform = dict( + type='CenterCrop', crop_size=(img_width // 2, img_height)) + center_crop_module = TRANSFORMS.build(transform) + results = self.reset_results(results, self.original_img, + self.gt_semantic_map) + results = center_crop_module(results) + assert results['img_shape'] == (img_height, img_width // 2) + assert (results['img'] == self.original_img[:, 100:300, ...]).all() + assert (results['gt_seg_map'] == self.gt_semantic_map[:, + 100:300]).all() + assert np.equal(results['gt_bboxes'], + np.array([[0, 0, 110, 160], [100, 150, 200, + 300]])).all() + assert np.equal( + results['gt_keypoints'], + np.array([[[0, 50, 0]], [[100, 150, 1]], [[200, 225, 0]]])).all() + + # test CenterCrop when crop_height is smaller than img_height + transform = dict( + type='CenterCrop', crop_size=(img_width, img_height // 2)) + center_crop_module = TRANSFORMS.build(transform) + results = self.reset_results(results, self.original_img, + self.gt_semantic_map) + results = center_crop_module(results) + assert results['img_shape'] == (img_height // 2, img_width) + assert (results['img'] == self.original_img[75:225, ...]).all() + assert (results['gt_seg_map'] == self.gt_semantic_map[75:225, + ...]).all() + assert np.equal(results['gt_bboxes'], + np.array([[0, 0, 210, 85], [200, 75, 400, + 150]])).all() + assert np.equal( + results['gt_keypoints'], + np.array([[[20, 0, 0]], [[200, 75, 1]], [[300, 150, 0]]])).all() + + @pytest.mark.skipif( + condition=torch is None, reason='No torch in current env') + def test_torchvision_compare(self): + # compare results with torchvision + results = {} + transform = dict(type='CenterCrop', crop_size=224) + center_crop_module = TRANSFORMS.build(transform) + results = self.reset_results(results, self.original_img, + self.gt_semantic_map) + results = center_crop_module(results) + center_crop_module = torchvision.transforms.CenterCrop(size=224) + pil_img = Image.fromarray(self.original_img) + pil_seg = Image.fromarray(self.gt_semantic_map) + cropped_img = center_crop_module(pil_img) + cropped_img = np.array(cropped_img) + cropped_seg = center_crop_module(pil_seg) + cropped_seg = np.array(cropped_seg) + assert np.equal(results['img'], cropped_img).all() + assert np.equal(results['gt_seg_map'], cropped_seg).all() + + +class TestRandomGrayscale: + + @classmethod + def setup_class(cls): + cls.img = (np.random.rand(10, 10, 3) * 255).astype(np.uint8) + + def test_repr(self): + # test repr + transform = dict( + type='RandomGrayscale', + prob=1., + channel_weights=(0.299, 0.587, 0.114), + keep_channels=True) + random_gray_scale_module = TRANSFORMS.build(transform) + assert isinstance(repr(random_gray_scale_module), str) + + def test_error(self): + # test invalid argument + transform = dict(type='RandomGrayscale', prob=2) + with pytest.raises(AssertionError): + TRANSFORMS.build(transform) + + def test_transform(self): + results = dict() + # test rgb2gray, return the grayscale image with prob = 1. + transform = dict( + type='RandomGrayscale', + prob=1., + channel_weights=(0.299, 0.587, 0.114), + keep_channels=True) + + random_gray_scale_module = TRANSFORMS.build(transform) + results['img'] = copy.deepcopy(self.img) + img = random_gray_scale_module(results)['img'] + computed_gray = (self.img[:, :, 0] * 0.299 + + self.img[:, :, 1] * 0.587 + + self.img[:, :, 2] * 0.114).astype(np.uint8) + for i in range(img.shape[2]): + assert_array_almost_equal(img[:, :, i], computed_gray, decimal=4) + assert img.shape == (10, 10, 3) + + # test rgb2gray, return the original image with p=0. + transform = dict(type='RandomGrayscale', prob=0.) + random_gray_scale_module = TRANSFORMS.build(transform) + results['img'] = copy.deepcopy(self.img) + img = random_gray_scale_module(results)['img'] + assert_array_equal(img, self.img) + assert img.shape == (10, 10, 3) + + # test image with one channel + transform = dict(type='RandomGrayscale', prob=1.) + results['img'] = self.img[:, :, 0:1] + random_gray_scale_module = TRANSFORMS.build(transform) + img = random_gray_scale_module(results)['img'] + assert_array_equal(img, self.img[:, :, 0:1]) + assert img.shape == (10, 10, 1) + + +@TRANSFORMS.register_module() +class MockPackTaskInputs(BaseTransform): + + def __init__(self) -> None: + super().__init__() + + def transform(self, results): + packed_results = dict(inputs=results['img'], data_sample=Mock()) + return packed_results + + +class TestMultiScaleFlipAug: + + @classmethod + def setup_class(cls): + cls.img = mmcv.imread( + osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color') + cls.original_img = copy.deepcopy(cls.img) + + def test_error(self): + # test assertion if scales is not tuple or list of tuple + with pytest.raises(AssertionError): + transform = dict( + type='MultiScaleFlipAug', scales=[1333, 800], transforms=[]) + TRANSFORMS.build(transform) + + # test assertion if flip_direction is not str or list of str + with pytest.raises(AssertionError): + transform = dict( + type='MultiScaleFlipAug', + scales=[(1333, 800)], + flip_direction=1, + transforms=[]) + TRANSFORMS.build(transform) + + @pytest.mark.skipif( + condition=torch is None, reason='No torch in current env') + def test_multi_scale_flip_aug(self): + # test with empty transforms + transform = dict( + type='MultiScaleFlipAug', + transforms=[dict(type='MockPackTaskInputs')], + scales=[(1333, 800), (800, 600), (640, 480)], + allow_flip=True, + flip_direction=['horizontal', 'vertical', 'diagonal']) + multi_scale_flip_aug_module = TRANSFORMS.build(transform) + results = dict() + results['img'] = copy.deepcopy(self.original_img) + packed_results = multi_scale_flip_aug_module(results) + assert len(packed_results['inputs']) == 12 + + # test with allow_flip=False + transform = dict( + type='MultiScaleFlipAug', + transforms=[dict(type='MockPackTaskInputs')], + scales=[(1333, 800), (800, 600), (640, 480)], + allow_flip=False, + flip_direction=['horizontal', 'vertical', 'diagonal']) + multi_scale_flip_aug_module = TRANSFORMS.build(transform) + results = dict() + results['img'] = copy.deepcopy(self.original_img) + packed_results = multi_scale_flip_aug_module(results) + assert len(packed_results['inputs']) == 3 + + # test with transforms + img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + to_rgb=True) + transforms_cfg = [ + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=32), + dict(type='ImageToTensor', keys=['img']), + dict(type='MockPackTaskInputs') + ] + transform = dict( + type='MultiScaleFlipAug', + transforms=transforms_cfg, + scales=[(1333, 800), (800, 600), (640, 480)], + allow_flip=True, + flip_direction=['horizontal', 'vertical', 'diagonal']) + multi_scale_flip_aug_module = TRANSFORMS.build(transform) + results = dict() + results['img'] = copy.deepcopy(self.original_img) + packed_results = multi_scale_flip_aug_module(results) + assert len(packed_results['inputs']) == 12 + + # test with scale_factor + img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + to_rgb=True) + transforms_cfg = [ + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=32), + dict(type='ImageToTensor', keys=['img']), + dict(type='MockPackTaskInputs') + ] + transform = dict( + type='MultiScaleFlipAug', + transforms=transforms_cfg, + scale_factor=[0.5, 1., 2.], + allow_flip=True, + flip_direction=['horizontal', 'vertical', 'diagonal']) + multi_scale_flip_aug_module = TRANSFORMS.build(transform) + results = dict() + results['img'] = copy.deepcopy(self.original_img) + packed_results = multi_scale_flip_aug_module(results) + assert len(packed_results['inputs']) == 12 + + # test no resize + img_norm_cfg = dict( + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + to_rgb=True) + transforms_cfg = [ + dict(type='Normalize', **img_norm_cfg), + dict(type='Pad', size_divisor=32), + dict(type='ImageToTensor', keys=['img']), + dict(type='MockPackTaskInputs') + ] + transform = dict( + type='MultiScaleFlipAug', + transforms=transforms_cfg, + allow_flip=True, + flip_direction=['horizontal', 'vertical', 'diagonal']) + multi_scale_flip_aug_module = TRANSFORMS.build(transform) + results = dict() + results['img'] = copy.deepcopy(self.original_img) + packed_results = multi_scale_flip_aug_module(results) + assert len(packed_results['inputs']) == 4 + + +class TestRandomChoiceResize: + + @classmethod + def setup_class(cls): + cls.img = mmcv.imread( + osp.join(osp.dirname(__file__), '../data/color.jpg'), 'color') + cls.original_img = copy.deepcopy(cls.img) + + def reset_results(self, results): + results['img'] = copy.deepcopy(self.original_img) + results['gt_seg_map'] = copy.deepcopy(self.original_img) + + def test_repr(self): + # test repr + transform = dict( + type='RandomChoiceResize', scales=[(1333, 800), (1333, 600)]) + random_multiscale_resize = TRANSFORMS.build(transform) + assert isinstance(repr(random_multiscale_resize), str) + + def test_error(self): + # test assertion if size is smaller than 0 + with pytest.raises(AssertionError): + transform = dict(type='RandomChoiceResize', scales=[0.5, 1, 2]) + TRANSFORMS.build(transform) + + def test_random_multiscale_resize(self): + results = dict() + # test with one scale + transform = dict(type='RandomChoiceResize', scales=[(1333, 800)]) + random_multiscale_resize = TRANSFORMS.build(transform) + self.reset_results(results) + results = random_multiscale_resize(results) + assert results['img'].shape == (800, 1333, 3) + + # test with multi scales + _scale_choice = [(1333, 800), (1333, 600)] + transform = dict(type='RandomChoiceResize', scales=_scale_choice) + random_multiscale_resize = TRANSFORMS.build(transform) + self.reset_results(results) + results = random_multiscale_resize(results) + assert (results['img'].shape[1], + results['img'].shape[0]) in _scale_choice + + # test keep_ratio + transform = dict( + type='RandomChoiceResize', + scales=[(900, 600)], + resize_type='Resize', + keep_ratio=True) + random_multiscale_resize = TRANSFORMS.build(transform) + self.reset_results(results) + _input_ratio = results['img'].shape[0] / results['img'].shape[1] + results = random_multiscale_resize(results) + _output_ratio = results['img'].shape[0] / results['img'].shape[1] + assert_array_almost_equal(_input_ratio, _output_ratio) + + # test clip_object_border + gt_bboxes = [[200, 150, 600, 450]] + transform = dict( + type='RandomChoiceResize', + scales=[(200, 150)], + resize_type='Resize', + clip_object_border=True) + random_multiscale_resize = TRANSFORMS.build(transform) + self.reset_results(results) + results['gt_bboxes'] = np.array(gt_bboxes) + results = random_multiscale_resize(results) + assert results['img'].shape == (150, 200, 3) + assert np.equal(results['gt_bboxes'], np.array([[100, 75, 200, + 150]])).all() + + transform = dict( + type='RandomChoiceResize', + scales=[(200, 150)], + resize_type='Resize', + clip_object_border=False) + random_multiscale_resize = TRANSFORMS.build(transform) + self.reset_results(results) + results['gt_bboxes'] = np.array(gt_bboxes) + results = random_multiscale_resize(results) + assert results['img'].shape == (150, 200, 3) + assert np.equal(results['gt_bboxes'], np.array([[100, 75, 300, + 225]])).all() + + +class TestRandomFlip: + + def test_init(self): + + # prob is float + TRANSFORMS = RandomFlip(0.1) + assert TRANSFORMS.prob == 0.1 + + # prob is None + with pytest.raises(ValueError): + TRANSFORMS = RandomFlip(None) + assert TRANSFORMS.prob is None + + # prob is a list + TRANSFORMS = RandomFlip([0.1, 0.2], ['horizontal', 'vertical']) + assert len(TRANSFORMS.prob) == 2 + assert len(TRANSFORMS.direction) == 2 + + # direction is an invalid type + with pytest.raises(ValueError): + TRANSFORMS = RandomFlip(0.1, 1) + + # prob is an invalid type + with pytest.raises(ValueError): + TRANSFORMS = RandomFlip('0.1') + + def test_transform(self): + + results = { + 'img': np.random.random((224, 224, 3)), + 'gt_bboxes': np.array([[0, 1, 100, 101]]), + 'gt_keypoints': np.array([[[100, 100, 1.0]]]), + # seg map flip is irrelative with image, so there is no requirement + # that gt_set_map of test data matches image. + 'gt_seg_map': np.array([[0, 1], [2, 3]]) + } + + # horizontal flip + TRANSFORMS = RandomFlip([1.0], ['horizontal']) + results_update = TRANSFORMS.transform(copy.deepcopy(results)) + assert (results_update['gt_bboxes'] == np.array([[124, 1, 224, + 101]])).all() + assert (results_update['gt_seg_map'] == np.array([[1, 0], [3, + 2]])).all() + + # diagonal flip + TRANSFORMS = RandomFlip([1.0], ['diagonal']) + results_update = TRANSFORMS.transform(copy.deepcopy(results)) + assert (results_update['gt_bboxes'] == np.array([[124, 123, 224, + 223]])).all() + assert (results_update['gt_seg_map'] == np.array([[3, 2], [1, + 0]])).all() + + # vertical flip + TRANSFORMS = RandomFlip([1.0], ['vertical']) + results_update = TRANSFORMS.transform(copy.deepcopy(results)) + assert (results_update['gt_bboxes'] == np.array([[0, 123, 100, + 223]])).all() + assert (results_update['gt_seg_map'] == np.array([[2, 3], [0, + 1]])).all() + + # horizontal flip when direction is None + TRANSFORMS = RandomFlip(1.0) + results_update = TRANSFORMS.transform(copy.deepcopy(results)) + assert (results_update['gt_bboxes'] == np.array([[124, 1, 224, + 101]])).all() + assert (results_update['gt_seg_map'] == np.array([[1, 0], [3, + 2]])).all() + + # horizontal flip and swap label pair + TRANSFORMS = RandomFlip([1.0], ['horizontal'], + swap_seg_labels=[[0, 1]]) + results_update = TRANSFORMS.transform(copy.deepcopy(results)) + assert (results_update['gt_seg_map'] == np.array([[0, 1], [3, + 2]])).all() + assert results_update['swap_seg_labels'] == [[0, 1]] + + TRANSFORMS = RandomFlip(0.0) + results_update = TRANSFORMS.transform(copy.deepcopy(results)) + assert (results_update['gt_bboxes'] == np.array([[0, 1, 100, + 101]])).all() + assert (results_update['gt_seg_map'] == np.array([[0, 1], [2, + 3]])).all() + + # flip direction is invalid in bbox flip + with pytest.raises(ValueError): + TRANSFORMS = RandomFlip(1.0) + results_update = TRANSFORMS._flip_bbox(results['gt_bboxes'], + (224, 224), 'invalid') + + # flip direction is invalid in keypoints flip + with pytest.raises(ValueError): + TRANSFORMS = RandomFlip(1.0) + results_update = TRANSFORMS._flip_keypoints( + results['gt_keypoints'], (224, 224), 'invalid') + + # swap pair is invalid + with pytest.raises(AssertionError): + TRANSFORMS = RandomFlip(1.0, swap_seg_labels='invalid') + results_update = TRANSFORMS._flip_seg_map(results['gt_seg_map'], + 'horizontal') + + def test_repr(self): + TRANSFORMS = RandomFlip(0.1) + TRANSFORMS_str = str(TRANSFORMS) + assert isinstance(TRANSFORMS_str, str) + + +class TestRandomResize: + + def test_init(self): + TRANSFORMS = RandomResize( + (224, 224), + (1.0, 2.0), + ) + assert TRANSFORMS.scale == (224, 224) + + def test_repr(self): + TRANSFORMS = RandomResize( + (224, 224), + (1.0, 2.0), + ) + TRANSFORMS_str = str(TRANSFORMS) + assert isinstance(TRANSFORMS_str, str) + + def test_transform(self): + + # choose target scale from init when override is True + results = {} + TRANSFORMS = RandomResize((224, 224), (1.0, 2.0)) + results_update = TRANSFORMS.transform(copy.deepcopy(results)) + assert results_update['scale'][0] >= 224 and results_update['scale'][ + 0] <= 448 + assert results_update['scale'][1] >= 224 and results_update['scale'][ + 1] <= 448 + + # keep ratio is True + results = { + 'img': np.random.random((224, 224, 3)), + 'gt_seg_map': np.random.random((224, 224, 3)), + 'gt_bboxes': np.array([[0, 0, 112, 112]]), + 'gt_keypoints': np.array([[[112, 112]]]) + } + + TRANSFORMS = RandomResize((224, 224), (1.0, 2.0), + resize_type='Resize', + keep_ratio=True) + results_update = TRANSFORMS.transform(copy.deepcopy(results)) + assert 224 <= results_update['img_shape'][0] + assert 448 >= results_update['img_shape'][0] + assert 224 <= results_update['img_shape'][1] + assert 448 >= results_update['img_shape'][1] + assert results_update['keep_ratio'] + assert results['gt_bboxes'][0][2] >= 112 + assert results['gt_bboxes'][0][2] <= 112 + + # keep ratio is False + TRANSFORMS = RandomResize((224, 224), (1.0, 2.0), + resize_type='Resize', + keep_ratio=False) + results_update = TRANSFORMS.transform(copy.deepcopy(results)) + + # choose target scale from init when override is False and scale is a + # list of tuples + results = {} + TRANSFORMS = RandomResize([(224, 448), (112, 224)], + resize_type='Resize', + keep_ratio=True) + results_update = TRANSFORMS.transform(copy.deepcopy(results)) + assert results_update['scale'][1] >= 224 and results_update['scale'][ + 1] <= 448 + assert results_update['scale'][0] >= 112 and results_update['scale'][ + 0] <= 224 + + # the type of scale is invalid in init + with pytest.raises(NotImplementedError): + results = {} + TRANSFORMS = RandomResize([(224, 448), [112, 224]], + resize_type='Resize', + keep_ratio=True) + results_update = TRANSFORMS.transform(copy.deepcopy(results)) + + +class TestTestTimeAug: + + def test_init(self): + subroutines = [[ + dict(type='Resize', scale=(1333, 800), keep_ratio=True), + dict(type='Resize', scale=(1333, 400), keep_ratio=True) + ], [ + dict(type='RandomFlip', prob=1.), + dict(type='RandomFlip', prob=0.) + ], [dict(type='Normalize', mean=(0, 0, 0), std=(1, 1, 1))]] + + tta_transform = TestTimeAug(subroutines) + subroutines = tta_transform.subroutines + assert len(subroutines) == 4 + + assert isinstance(subroutines[0].transforms[0], Resize) + assert isinstance(subroutines[0].transforms[1], RandomFlip) + assert isinstance(subroutines[0].transforms[2], Normalize) + assert isinstance(subroutines[1].transforms[0], Resize) + assert isinstance(subroutines[1].transforms[1], RandomFlip) + assert isinstance(subroutines[1].transforms[2], Normalize) + + def test_transform(self): + results = { + 'img': np.random.random((224, 224, 3)), + 'gt_bboxes': np.array([[0, 1, 100, 101]]), + 'gt_keypoints': np.array([[[100, 100, 1.0]]]), + 'gt_seg_map': np.random.random((224, 224, 3)) + } + input_results = copy.deepcopy(results) + transforms = [[ + dict(type='Resize', scale=(1333, 800), keep_ratio=True), + dict(type='Resize', scale=(1333, 400), keep_ratio=True) + ], [ + dict(type='RandomFlip', prob=0.), + dict(type='RandomFlip', prob=1.) + ], [dict(type='Normalize', mean=(0, 0, 0), std=(1, 1, 1))]] + + tta_transform = TestTimeAug(transforms) + results = tta_transform.transform(results) + assert len(results['img']) == 4 + + resize1 = tta_transform.subroutines[0].transforms[0] + resize2 = tta_transform.subroutines[2].transforms[0] + flip1 = tta_transform.subroutines[0].transforms[1] + flip2 = tta_transform.subroutines[1].transforms[1] + normalize = tta_transform.subroutines[0].transforms[2] + target_results = [ + normalize.transform( + flip1.transform( + resize1.transform(copy.deepcopy(input_results)))), + normalize.transform( + flip2.transform( + resize1.transform(copy.deepcopy(input_results)))), + normalize.transform( + flip1.transform( + resize2.transform(copy.deepcopy(input_results)))), + normalize.transform( + flip2.transform( + resize2.transform(copy.deepcopy(input_results)))), + ] + + assert np.allclose(target_results[0]['img'], results['img'][0]) + assert np.allclose(target_results[1]['img'], results['img'][1]) + assert np.allclose(target_results[2]['img'], results['img'][2]) + assert np.allclose(target_results[3]['img'], results['img'][3]) + + def test_repr(self): + transforms = [[ + dict(type='Resize', scale=(1333, 800), keep_ratio=True), + dict(type='Resize', scale=(1333, 400), keep_ratio=True) + ], [ + dict(type='RandomFlip', prob=0.), + dict(type='RandomFlip', prob=1.) + ], [dict(type='Normalize', mean=(0, 0, 0), std=(1, 1, 1))]] + + tta_transform = TestTimeAug(transforms) + repr_str = repr(tta_transform) + repr_str_list = repr_str.split('\n') + assert repr_str_list[0] == 'TestTimeAugtransforms=' + assert repr_str_list[1] == 'Compose(' + assert repr_str_list[2].startswith(' Resize(scale=(1333, 800)') + assert repr_str_list[3].startswith(' RandomFlip(prob=0.0') + assert repr_str_list[4].startswith(' Normalize(mean=[0. 0. 0.]') diff --git a/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_wrapper.py b/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_wrapper.py new file mode 100644 index 000000000..98feeb83e --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_wrapper.py @@ -0,0 +1,585 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import warnings + +import numpy as np +import pytest + +from mmcv.transforms.base import BaseTransform +from mmcv.transforms.builder import TRANSFORMS +from mmcv.transforms.utils import (avoid_cache_randomness, cache_random_params, + cache_randomness) +from mmcv.transforms.wrappers import (Compose, KeyMapper, RandomApply, + RandomChoice, TransformBroadcaster) + + +@TRANSFORMS.register_module() +class AddToValue(BaseTransform): + """Dummy transform to add a given addend to results['value']""" + + def __init__(self, addend=0) -> None: + super().__init__() + self.addend = addend + + def add(self, results, addend): + augend = results['value'] + + if isinstance(augend, list): + warnings.warn('value is a list', UserWarning) + if isinstance(augend, dict): + warnings.warn('value is a dict', UserWarning) + + def _add_to_value(augend, addend): + if isinstance(augend, list): + return [_add_to_value(v, addend) for v in augend] + if isinstance(augend, dict): + return {k: _add_to_value(v, addend) for k, v in augend.items()} + return augend + addend + + results['value'] = _add_to_value(results['value'], addend) + return results + + def transform(self, results): + return self.add(results, self.addend) + + def __repr__(self) -> str: + repr_str = self.__class__.__name__ + repr_str += f'addend = {self.addend}' + return repr_str + + +@TRANSFORMS.register_module() +class RandomAddToValue(AddToValue): + """Dummy transform to add a random addend to results['value']""" + + def __init__(self, repeat=1) -> None: + super().__init__(addend=None) + self.repeat = repeat + + @cache_randomness + def get_random_addend(self): + return np.random.rand() + + def transform(self, results): + for _ in range(self.repeat): + results = self.add(results, addend=self.get_random_addend()) + return results + + def __repr__(self) -> str: + repr_str = self.__class__.__name__ + repr_str += f'repeat = {self.repeat}' + return repr_str + + +@TRANSFORMS.register_module() +class SumTwoValues(BaseTransform): + """Dummy transform to test transform wrappers.""" + + def transform(self, results): + if 'num_1' in results and 'num_2' in results: + results['sum'] = results['num_1'] + results['num_2'] + elif 'num_1' in results: + results['sum'] = results['num_1'] + elif 'num_2' in results: + results['sum'] = results['num_2'] + else: + results['sum'] = np.nan + return results + + def __repr__(self) -> str: + repr_str = self.__class__.__name__ + return repr_str + + +def test_compose(): + + # Case 1: build from cfg + pipeline = [dict(type='AddToValue')] + pipeline = Compose(pipeline) + _ = str(pipeline) + + # Case 2: build from transform list + pipeline = [AddToValue()] + pipeline = Compose(pipeline) + + # Case 3: invalid build arguments + pipeline = [[dict(type='AddToValue')]] + with pytest.raises(TypeError): + pipeline = Compose(pipeline) + + # Case 4: contain transform with None output + class DummyTransform(BaseTransform): + + def transform(self, results): + return None + + pipeline = Compose([DummyTransform()]) + results = pipeline({}) + assert results is None + + +def test_cache_random_parameters(): + + transform = RandomAddToValue() + + # Case 1: cache random parameters + assert hasattr(RandomAddToValue, '_methods_with_randomness') + assert 'get_random_addend' in RandomAddToValue._methods_with_randomness + + with cache_random_params(transform): + results_1 = transform(dict(value=0)) + results_2 = transform(dict(value=0)) + np.testing.assert_equal(results_1['value'], results_2['value']) + + # Case 2: do not cache random parameters + results_1 = transform(dict(value=0)) + results_2 = transform(dict(value=0)) + with pytest.raises(AssertionError): + np.testing.assert_equal(results_1['value'], results_2['value']) + + # Case 3: allow to invoke random method 0 times + transform = RandomAddToValue(repeat=0) + with cache_random_params(transform): + _ = transform(dict(value=0)) + + # Case 4: NOT allow to invoke random method >1 times + transform = RandomAddToValue(repeat=2) + with pytest.raises(RuntimeError): + with cache_random_params(transform): + _ = transform(dict(value=0)) + + # Case 5: apply on nested transforms + transform = Compose([RandomAddToValue()]) + with cache_random_params(transform): + results_1 = transform(dict(value=0)) + results_2 = transform(dict(value=0)) + np.testing.assert_equal(results_1['value'], results_2['value']) + + +def test_key_mapper(): + # Case 0: only remap + pipeline = KeyMapper( + transforms=[AddToValue(addend=1)], remapping={'value': 'v_out'}) + + results = dict(value=0) + results = pipeline(results) + + np.testing.assert_equal(results['value'], 0) # should be unchanged + np.testing.assert_equal(results['v_out'], 1) + + # Case 1: simple remap + pipeline = KeyMapper( + transforms=[AddToValue(addend=1)], + mapping={'value': 'v_in'}, + remapping={'value': 'v_out'}) + + results = dict(value=0, v_in=1) + results = pipeline(results) + + np.testing.assert_equal(results['value'], 0) # should be unchanged + np.testing.assert_equal(results['v_in'], 1) + np.testing.assert_equal(results['v_out'], 2) + + # Case 2: collecting list + pipeline = KeyMapper( + transforms=[AddToValue(addend=2)], + mapping={'value': ['v_in_1', 'v_in_2']}, + remapping={'value': ['v_out_1', 'v_out_2']}) + results = dict(value=0, v_in_1=1, v_in_2=2) + + with pytest.warns(UserWarning, match='value is a list'): + results = pipeline(results) + + np.testing.assert_equal(results['value'], 0) # should be unchanged + np.testing.assert_equal(results['v_in_1'], 1) + np.testing.assert_equal(results['v_in_2'], 2) + np.testing.assert_equal(results['v_out_1'], 3) + np.testing.assert_equal(results['v_out_2'], 4) + + # Case 3: collecting dict + pipeline = KeyMapper( + transforms=[AddToValue(addend=2)], + mapping={'value': { + 'v1': 'v_in_1', + 'v2': 'v_in_2' + }}, + remapping={'value': { + 'v1': 'v_out_1', + 'v2': 'v_out_2' + }}) + results = dict(value=0, v_in_1=1, v_in_2=2) + + with pytest.warns(UserWarning, match='value is a dict'): + results = pipeline(results) + + np.testing.assert_equal(results['value'], 0) # should be unchanged + np.testing.assert_equal(results['v_in_1'], 1) + np.testing.assert_equal(results['v_in_2'], 2) + np.testing.assert_equal(results['v_out_1'], 3) + np.testing.assert_equal(results['v_out_2'], 4) + + # Case 4: collecting list with auto_remap mode + pipeline = KeyMapper( + transforms=[AddToValue(addend=2)], + mapping=dict(value=['v_in_1', 'v_in_2']), + auto_remap=True) + results = dict(value=0, v_in_1=1, v_in_2=2) + + with pytest.warns(UserWarning, match='value is a list'): + results = pipeline(results) + + np.testing.assert_equal(results['value'], 0) + np.testing.assert_equal(results['v_in_1'], 3) + np.testing.assert_equal(results['v_in_2'], 4) + + # Case 5: collecting dict with auto_remap mode + pipeline = KeyMapper( + transforms=[AddToValue(addend=2)], + mapping=dict(value=dict(v1='v_in_1', v2='v_in_2')), + auto_remap=True) + results = dict(value=0, v_in_1=1, v_in_2=2) + + with pytest.warns(UserWarning, match='value is a dict'): + results = pipeline(results) + + np.testing.assert_equal(results['value'], 0) + np.testing.assert_equal(results['v_in_1'], 3) + np.testing.assert_equal(results['v_in_2'], 4) + + # Case 6: nested collection with auto_remap mode + pipeline = KeyMapper( + transforms=[AddToValue(addend=2)], + mapping=dict(value=['v1', dict(v2=['v21', 'v22'], v3='v3')]), + auto_remap=True) + results = dict(value=0, v1=1, v21=2, v22=3, v3=4) + + with pytest.warns(UserWarning, match='value is a list'): + results = pipeline(results) + + np.testing.assert_equal(results['value'], 0) + np.testing.assert_equal(results['v1'], 3) + np.testing.assert_equal(results['v21'], 4) + np.testing.assert_equal(results['v22'], 5) + np.testing.assert_equal(results['v3'], 6) + + # Case 7: output_map must be None if `auto_remap` is set True + with pytest.raises(ValueError): + pipeline = KeyMapper( + transforms=[AddToValue(addend=1)], + mapping=dict(value='v_in'), + remapping=dict(value='v_out'), + auto_remap=True) + + # Case 8: allow_nonexist_keys8 + pipeline = KeyMapper( + transforms=[SumTwoValues()], + mapping=dict(num_1='a', num_2='b'), + auto_remap=False, + allow_nonexist_keys=True) + + results = pipeline(dict(a=1, b=2)) + np.testing.assert_equal(results['sum'], 3) + + results = pipeline(dict(a=1)) + np.testing.assert_equal(results['sum'], 1) + + # Case 9: use wrapper as a transform + transform = KeyMapper(mapping=dict(b='a'), auto_remap=False) + results = transform(dict(a=1)) + # note that the original key 'a' will not be removed + assert results == dict(a=1, b=1) + + # Case 10: manually set keys ignored + pipeline = KeyMapper( + transforms=[SumTwoValues()], + mapping=dict(num_1='a', num_2=...), # num_2 (b) will be ignored + auto_remap=False, + # allow_nonexist_keys will not affect manually ignored keys + allow_nonexist_keys=False) + + results = pipeline(dict(a=1, b=2)) + np.testing.assert_equal(results['sum'], 1) + + # Test basic functions + pipeline = KeyMapper( + transforms=[AddToValue(addend=1)], + mapping=dict(value='v_in'), + remapping=dict(value='v_out')) + + # __iter__ + for _ in pipeline: + pass + + # __repr__ + assert repr(pipeline) == ( + 'KeyMapper(transforms = Compose(\n ' + 'AddToValueaddend = 1' + + '\n), mapping = {\'value\': \'v_in\'}, ' + + 'remapping = {\'value\': \'v_out\'}, auto_remap = False, ' + + 'allow_nonexist_keys = False)') + + +def test_transform_broadcaster(): + + # Case 1: apply to list in results + pipeline = TransformBroadcaster( + transforms=[AddToValue(addend=1)], + mapping=dict(value='values'), + auto_remap=True) + results = dict(values=[1, 2]) + + results = pipeline(results) + + np.testing.assert_equal(results['values'], [2, 3]) + + # Case 2: apply to multiple keys + pipeline = TransformBroadcaster( + transforms=[AddToValue(addend=1)], + mapping=dict(value=['v_1', 'v_2']), + auto_remap=True) + results = dict(v_1=1, v_2=2) + + results = pipeline(results) + + np.testing.assert_equal(results['v_1'], 2) + np.testing.assert_equal(results['v_2'], 3) + + # Case 3: apply to multiple groups of keys + pipeline = TransformBroadcaster( + transforms=[SumTwoValues()], + mapping=dict(num_1=['a_1', 'b_1'], num_2=['a_2', 'b_2']), + remapping=dict(sum=['a', 'b']), + auto_remap=False) + + results = dict(a_1=1, a_2=2, b_1=3, b_2=4) + results = pipeline(results) + + np.testing.assert_equal(results['a'], 3) + np.testing.assert_equal(results['b'], 7) + + # Case 3: apply to all keys + pipeline = TransformBroadcaster( + transforms=[SumTwoValues()], mapping=None, remapping=None) + results = dict(num_1=[1, 2, 3], num_2=[4, 5, 6]) + + results = pipeline(results) + + np.testing.assert_equal(results['sum'], [5, 7, 9]) + + # Case 4: inconsistent sequence length + with pytest.raises(ValueError): + pipeline = TransformBroadcaster( + transforms=[SumTwoValues()], + mapping=dict(num_1='list_1', num_2='list_2'), + auto_remap=False) + + results = dict(list_1=[1, 2], list_2=[1, 2, 3]) + _ = pipeline(results) + + # Case 5: share random parameter + pipeline = TransformBroadcaster( + transforms=[RandomAddToValue()], + mapping=dict(value='values'), + auto_remap=True, + share_random_params=True) + + results = dict(values=[0, 0]) + results = pipeline(results) + + np.testing.assert_equal(results['values'][0], results['values'][1]) + + # Case 6: partial broadcasting + pipeline = TransformBroadcaster( + transforms=[SumTwoValues()], + mapping=dict(num_1=['a_1', 'b_1'], num_2=['a_2', ...]), + remapping=dict(sum=['a', 'b']), + auto_remap=False) + + results = dict(a_1=1, a_2=2, b_1=3, b_2=4) + results = pipeline(results) + + np.testing.assert_equal(results['a'], 3) + np.testing.assert_equal(results['b'], 3) + + pipeline = TransformBroadcaster( + transforms=[SumTwoValues()], + mapping=dict(num_1=['a_1', 'b_1'], num_2=['a_2', 'b_2']), + remapping=dict(sum=['a', ...]), + auto_remap=False) + + results = dict(a_1=1, a_2=2, b_1=3, b_2=4) + results = pipeline(results) + + np.testing.assert_equal(results['a'], 3) + assert 'b' not in results + + # Test repr + assert repr(pipeline) == ( + 'TransformBroadcaster(transforms = Compose(\n' + ' SumTwoValues' + + '\n), mapping = {\'num_1\': [\'a_1\', \'b_1\'], ' + + '\'num_2\': [\'a_2\', \'b_2\']}, ' + + 'remapping = {\'sum\': [\'a\', Ellipsis]}, auto_remap = False, ' + + 'allow_nonexist_keys = False, share_random_params = False)') + + +def test_random_choice(): + + # Case 1: given probability + pipeline = RandomChoice( + transforms=[[AddToValue(addend=1.0)], [AddToValue(addend=2.0)]], + prob=[1.0, 0.0]) + + results = pipeline(dict(value=1)) + np.testing.assert_equal(results['value'], 2.0) + + # Case 2: default probability + pipeline = RandomChoice(transforms=[[AddToValue( + addend=1.0)], [AddToValue(addend=2.0)]]) + + _ = pipeline(dict(value=1)) + + # Case 3: nested RandomChoice in TransformBroadcaster + pipeline = TransformBroadcaster( + transforms=[ + RandomChoice( + transforms=[[AddToValue(addend=1.0)], + [AddToValue(addend=2.0)]], ), + ], + mapping={'value': 'values'}, + auto_remap=True, + share_random_params=True) + + results = dict(values=[0 for _ in range(10)]) + results = pipeline(results) + # check share_random_params=True works so that all values are same + values = results['values'] + assert all(map(lambda x: x == values[0], values)) + + # repr + assert repr(pipeline) == ( + 'TransformBroadcaster(transforms = Compose(\n' + + ' RandomChoice(transforms = [Compose(\n' + + ' AddToValueaddend = 1.0' + '\n), Compose(\n' + + ' AddToValueaddend = 2.0' + '\n)]prob = None)' + + '\n), mapping = {\'value\': \'values\'}, ' + + 'remapping = {\'value\': \'values\'}, auto_remap = True, ' + + 'allow_nonexist_keys = False, share_random_params = True)') + + +def test_random_apply(): + + # Case 1: simple use + pipeline = RandomApply(transforms=[AddToValue(addend=1.0)], prob=1.0) + results = pipeline(dict(value=1)) + np.testing.assert_equal(results['value'], 2.0) + + pipeline = RandomApply(transforms=[AddToValue(addend=1.0)], prob=0.0) + results = pipeline(dict(value=1)) + np.testing.assert_equal(results['value'], 1.0) + + # Case 2: nested RandomApply in TransformBroadcaster + pipeline = TransformBroadcaster( + transforms=[RandomApply(transforms=[AddToValue(addend=1)], prob=0.5)], + mapping={'value': 'values'}, + auto_remap=True, + share_random_params=True) + + results = dict(values=[0 for _ in range(10)]) + results = pipeline(results) + # check share_random_params=True works so that all values are same + values = results['values'] + assert all(map(lambda x: x == values[0], values)) + + # __iter__ + for _ in pipeline: + pass + + # repr + assert repr(pipeline) == ( + 'TransformBroadcaster(transforms = Compose(\n' + + ' RandomApply(transforms = Compose(\n' + + ' AddToValueaddend = 1' + '\n), prob = 0.5)' + + '\n), mapping = {\'value\': \'values\'}, ' + + 'remapping = {\'value\': \'values\'}, auto_remap = True, ' + + 'allow_nonexist_keys = False, share_random_params = True)') + + +def test_utils(): + # Test cache_randomness: normal case + class DummyTransform(BaseTransform): + + @cache_randomness + def func(self): + return np.random.rand() + + def transform(self, results): + _ = self.func() + return results + + transform = DummyTransform() + _ = transform({}) + with cache_random_params(transform): + _ = transform({}) + + # Test cache_randomness: invalid function type + with pytest.raises(TypeError): + + class DummyTransform(BaseTransform): + + @cache_randomness + @staticmethod + def func(): + return np.random.rand() + + def transform(self, results): + return results + + # Test cache_randomness: invalid function argument list + with pytest.raises(TypeError): + + class DummyTransform(BaseTransform): + + @cache_randomness + def func(cls): + return np.random.rand() + + def transform(self, results): + return results + + # Test avoid_cache_randomness: invalid mixture with cache_randomness + with pytest.raises(RuntimeError): + + @avoid_cache_randomness + class DummyTransform(BaseTransform): + + @cache_randomness + def func(self): + pass + + def transform(self, results): + return results + + # Test avoid_cache_randomness: raise error in cache_random_params + with pytest.raises(RuntimeError): + + @avoid_cache_randomness + class DummyTransform(BaseTransform): + + def transform(self, results): + return results + + transform = DummyTransform() + with cache_random_params(transform): + pass + + # Test avoid_cache_randomness: non-inheritable + @avoid_cache_randomness + class DummyBaseTransform(BaseTransform): + + def transform(self, results): + return results + + class DummyTransform(DummyBaseTransform): + pass + + transform = DummyTransform() + with cache_random_params(transform): + pass diff --git a/cv/distiller/CWD/mmcv/tests/test_utils/test_env.py b/cv/distiller/CWD/mmcv/tests/test_utils/test_env.py new file mode 100644 index 000000000..74bafff37 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_utils/test_env.py @@ -0,0 +1,34 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import sys + +import pytest + +import mmcv + + +def test_collect_env(): + try: + import torch # noqa: F401 + except ModuleNotFoundError: + pytest.skip('skipping tests that require PyTorch') + + from mmcv.utils import collect_env + env_info = collect_env() + expected_keys = [ + 'sys.platform', 'Python', 'CUDA available', 'PyTorch', + 'PyTorch compiling details', 'OpenCV', 'MMCV', 'MMCV Compiler', 'GCC', + 'MMCV CUDA Compiler' + ] + for key in expected_keys: + assert key in env_info + + if env_info['CUDA available']: + for key in ['CUDA_HOME', 'NVCC']: + assert key in env_info + + if sys.platform == 'win32': + assert 'MSVC' in env_info + + assert env_info['sys.platform'] == sys.platform + assert env_info['Python'] == sys.version.replace('\n', '') + assert env_info['MMCV'] == mmcv.__version__ diff --git a/cv/distiller/CWD/mmcv/tests/test_utils/test_parrots_jit.py b/cv/distiller/CWD/mmcv/tests/test_utils/test_parrots_jit.py new file mode 100644 index 000000000..921a4402d --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_utils/test_parrots_jit.py @@ -0,0 +1,278 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch +from mmengine.utils.dl_utils import TORCH_VERSION + +import mmcv + +pytest.skip('this test not ready now', allow_module_level=True) +skip_no_parrots = pytest.mark.skipif( + TORCH_VERSION != 'parrots', reason='test case under parrots environment') + + +class TestJit: + + def test_add_dict(self): + + @mmcv.jit + def add_dict(oper): + rets = oper['x'] + oper['y'] + return {'result': rets} + + def add_dict_pyfunc(oper): + rets = oper['x'] + oper['y'] + return {'result': rets} + + a = torch.rand((3, 4)) + b = torch.rand((3, 4)) + oper = {'x': a, 'y': b} + + rets_t = add_dict(oper) + rets = add_dict_pyfunc(oper) + assert 'result' in rets + assert (rets_t['result'] == rets['result']).all() + + def test_add_list(self): + + @mmcv.jit + def add_list(oper, x, y): + rets = {} + for idx, pair in enumerate(oper): + rets[f'k{idx}'] = pair['x'] + pair['y'] + rets[f'k{len(oper)}'] = x + y + return rets + + def add_list_pyfunc(oper, x, y): + rets = {} + for idx, pair in enumerate(oper): + rets[f'k{idx}'] = pair['x'] + pair['y'] + rets[f'k{len(oper)}'] = x + y + return rets + + pair_num = 3 + oper = [] + for _ in range(pair_num): + oper.append({'x': torch.rand((3, 4)), 'y': torch.rand((3, 4))}) + a = torch.rand((3, 4)) + b = torch.rand((3, 4)) + rets = add_list_pyfunc(oper, x=a, y=b) + rets_t = add_list(oper, x=a, y=b) + for idx in range(pair_num + 1): + assert f'k{idx}' in rets_t + assert (rets[f'k{idx}'] == rets_t[f'k{idx}']).all() + + @skip_no_parrots + def test_jit_cache(self): + + @mmcv.jit + def func(oper): + if oper['const'] > 1: + return oper['x'] * 2 + oper['y'] + else: + return oper['x'] * 2 - oper['y'] + + def pyfunc(oper): + if oper['const'] > 1: + return oper['x'] * 2 + oper['y'] + else: + return oper['x'] * 2 - oper['y'] + + assert len(func._cache._cache) == 0 + + oper = {'const': 2, 'x': torch.rand((3, 4)), 'y': torch.rand((3, 4))} + rets_plus = pyfunc(oper) + rets_plus_t = func(oper) + assert (rets_plus == rets_plus_t).all() + assert len(func._cache._cache) == 1 + + oper['const'] = 0.5 + rets_minus = pyfunc(oper) + rets_minus_t = func(oper) + assert (rets_minus == rets_minus_t).all() + assert len(func._cache._cache) == 2 + + rets_a = (rets_minus_t + rets_plus_t) / 4 + assert torch.allclose(oper['x'], rets_a) + + @skip_no_parrots + def test_jit_shape(self): + + @mmcv.jit + def func(a): + return a + 1 + + assert len(func._cache._cache) == 0 + + a = torch.ones((3, 4)) + r = func(a) + assert r.shape == (3, 4) + assert (r == 2).all() + assert len(func._cache._cache) == 1 + + a = torch.ones((2, 3, 4)) + r = func(a) + assert r.shape == (2, 3, 4) + assert (r == 2).all() + assert len(func._cache._cache) == 2 + + @skip_no_parrots + def test_jit_kwargs(self): + + @mmcv.jit + def func(a, b): + return torch.mean((a - b) * (a - b)) + + assert len(func._cache._cache) == 0 + x = torch.rand((16, 32)) + y = torch.rand((16, 32)) + func(x, y) + assert len(func._cache._cache) == 1 + func(x, b=y) + assert len(func._cache._cache) == 1 + func(b=y, a=x) + assert len(func._cache._cache) == 1 + + def test_jit_derivate(self): + + @mmcv.jit(derivate=True) + def func(x, y): + return (x + 2) * (y - 2) + + a = torch.rand((3, 4)) + b = torch.rand((3, 4)) + a.requires_grad = True + + c = func(a, b) + assert c.requires_grad + d = torch.empty_like(c) + d.fill_(1.0) + c.backward(d) + assert torch.allclose(a.grad, (b - 2)) + assert b.grad is None + + a.grad = None + c = func(a, b) + assert c.requires_grad + d = torch.empty_like(c) + d.fill_(2.7) + c.backward(d) + assert torch.allclose(a.grad, 2.7 * (b - 2)) + assert b.grad is None + + def test_jit_optimize(self): + + @mmcv.jit(optimize=True) + def func(a, b): + return torch.mean((a - b) * (a - b)) + + def pyfunc(a, b): + return torch.mean((a - b) * (a - b)) + + a = torch.rand((16, 32)) + b = torch.rand((16, 32)) + + c = func(a, b) + d = pyfunc(a, b) + assert torch.allclose(c, d) + + @mmcv.skip_no_elena + def test_jit_coderize(self): + if not torch.cuda.is_available(): + return + + @mmcv.jit(coderize=True) + def func(a, b): + return (a + b) * (a - b) + + def pyfunc(a, b): + return (a + b) * (a - b) + + a = torch.rand((16, 32), device='cuda') + b = torch.rand((16, 32), device='cuda') + + c = func(a, b) + d = pyfunc(a, b) + assert torch.allclose(c, d) + + def test_jit_value_dependent(self): + + @mmcv.jit + def func(a, b): + torch.nonzero(a) + return torch.mean((a - b) * (a - b)) + + def pyfunc(a, b): + torch.nonzero(a) + return torch.mean((a - b) * (a - b)) + + a = torch.rand((16, 32)) + b = torch.rand((16, 32)) + + c = func(a, b) + d = pyfunc(a, b) + assert torch.allclose(c, d) + + @skip_no_parrots + def test_jit_check_input(self): + + def func(x): + y = torch.rand_like(x) + return x + y + + a = torch.ones((3, 4)) + with pytest.raises(AssertionError): + func = mmcv.jit(func, check_input=(a, )) + + @skip_no_parrots + def test_jit_partial_shape(self): + + @mmcv.jit(full_shape=False) + def func(a, b): + return torch.mean((a - b) * (a - b)) + + def pyfunc(a, b): + return torch.mean((a - b) * (a - b)) + + a = torch.rand((3, 4)) + b = torch.rand((3, 4)) + assert torch.allclose(func(a, b), pyfunc(a, b)) + assert len(func._cache._cache) == 1 + + a = torch.rand((6, 5)) + b = torch.rand((6, 5)) + assert torch.allclose(func(a, b), pyfunc(a, b)) + assert len(func._cache._cache) == 1 + + a = torch.rand((3, 4, 5)) + b = torch.rand((3, 4, 5)) + assert torch.allclose(func(a, b), pyfunc(a, b)) + assert len(func._cache._cache) == 2 + + a = torch.rand((1, 9, 8)) + b = torch.rand((1, 9, 8)) + assert torch.allclose(func(a, b), pyfunc(a, b)) + assert len(func._cache._cache) == 2 + + def test_instance_method(self): + + class T: + + def __init__(self, shape): + self._c = torch.rand(shape) + + @mmcv.jit + def test_method(self, x, y): + return (x * self._c) + y + + shape = (16, 32) + t = T(shape) + a = torch.rand(shape) + b = torch.rand(shape) + res = (a * t._c) + b + jit_res = t.test_method(a, b) + assert torch.allclose(res, jit_res) + + t = T(shape) + res = (a * t._c) + b + jit_res = t.test_method(a, b) + assert torch.allclose(res, jit_res) diff --git a/cv/distiller/CWD/mmcv/tests/test_video/test_optflow.py b/cv/distiller/CWD/mmcv/tests/test_video/test_optflow.py new file mode 100644 index 000000000..c5aaba3f5 --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_video/test_optflow.py @@ -0,0 +1,291 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import os.path as osp +import tempfile + +import cv2 +import numpy as np +import pytest +from numpy.testing import assert_array_almost_equal, assert_array_equal + +import mmcv + + +def test_flowread(): + data_dir = osp.join(osp.dirname(__file__), '../data') + flow_shape = (60, 80, 2) + + # read .flo file + flow = mmcv.flowread(osp.join(data_dir, 'optflow.flo')) + assert flow.shape == flow_shape + + # pseudo read + flow_same = mmcv.flowread(flow) + assert_array_equal(flow, flow_same) + + # read quantized flow concatenated vertically + flow = mmcv.flowread( + osp.join(data_dir, 'optflow_concat0.jpg'), quantize=True, denorm=True) + assert flow.shape == flow_shape + + # read quantized flow concatenated horizontally + flow = mmcv.flowread( + osp.join(data_dir, 'optflow_concat1.jpg'), + quantize=True, + concat_axis=1, + denorm=True) + assert flow.shape == flow_shape + + # test exceptions + notflow_file = osp.join(data_dir, 'color.jpg') + with pytest.raises(TypeError): + mmcv.flowread(1) + with pytest.raises(IOError): + mmcv.flowread(notflow_file) + with pytest.raises(IOError): + mmcv.flowread(notflow_file, quantize=True) + with pytest.raises(ValueError): + mmcv.flowread(np.zeros((100, 100, 1))) + + +def test_flowwrite(): + flow = np.random.rand(100, 100, 2).astype(np.float32) + + # write to a .flo file + tmp_filehandler, filename = tempfile.mkstemp() + mmcv.flowwrite(flow, filename) + flow_from_file = mmcv.flowread(filename) + assert_array_equal(flow, flow_from_file) + os.close(tmp_filehandler) + os.remove(filename) + + # write to two .jpg files + tmp_filename = osp.join(tempfile.gettempdir(), 'mmcv_test_flow.jpg') + for concat_axis in range(2): + mmcv.flowwrite( + flow, tmp_filename, quantize=True, concat_axis=concat_axis) + shape = (200, 100) if concat_axis == 0 else (100, 200) + assert osp.isfile(tmp_filename) + assert mmcv.imread(tmp_filename, flag='unchanged').shape == shape + os.remove(tmp_filename) + + # test exceptions + with pytest.raises(AssertionError): + mmcv.flowwrite(flow, tmp_filename, quantize=True, concat_axis=2) + + +def test_quantize_flow(): + flow = (np.random.rand(10, 8, 2).astype(np.float32) - 0.5) * 15 + max_val = 5.0 + dx, dy = mmcv.quantize_flow(flow, max_val=max_val, norm=False) + ref = np.zeros_like(flow, dtype=np.uint8) + for i in range(ref.shape[0]): + for j in range(ref.shape[1]): + for k in range(ref.shape[2]): + val = flow[i, j, k] + max_val + val = min(max(val, 0), 2 * max_val) + ref[i, j, k] = min(np.floor(255 * val / (2 * max_val)), 254) + assert_array_equal(dx, ref[..., 0]) + assert_array_equal(dy, ref[..., 1]) + max_val = 0.5 + dx, dy = mmcv.quantize_flow(flow, max_val=max_val, norm=True) + ref = np.zeros_like(flow, dtype=np.uint8) + for i in range(ref.shape[0]): + for j in range(ref.shape[1]): + for k in range(ref.shape[2]): + scale = flow.shape[1] if k == 0 else flow.shape[0] + val = flow[i, j, k] / scale + max_val + val = min(max(val, 0), 2 * max_val) + ref[i, j, k] = min(np.floor(255 * val / (2 * max_val)), 254) + assert_array_equal(dx, ref[..., 0]) + assert_array_equal(dy, ref[..., 1]) + + +def test_dequantize_flow(): + dx = np.random.randint(256, size=(10, 8), dtype=np.uint8) + dy = np.random.randint(256, size=(10, 8), dtype=np.uint8) + max_val = 5.0 + flow = mmcv.dequantize_flow(dx, dy, max_val=max_val, denorm=False) + ref = np.zeros_like(flow, dtype=np.float32) + for i in range(ref.shape[0]): + for j in range(ref.shape[1]): + ref[i, j, 0] = float(dx[i, j] + 0.5) * 2 * max_val / 255 - max_val + ref[i, j, 1] = float(dy[i, j] + 0.5) * 2 * max_val / 255 - max_val + assert_array_almost_equal(flow, ref) + max_val = 0.5 + flow = mmcv.dequantize_flow(dx, dy, max_val=max_val, denorm=True) + h, w = dx.shape + ref = np.zeros_like(flow, dtype=np.float32) + for i in range(ref.shape[0]): + for j in range(ref.shape[1]): + ref[i, j, + 0] = (float(dx[i, j] + 0.5) * 2 * max_val / 255 - max_val) * w + ref[i, j, + 1] = (float(dy[i, j] + 0.5) * 2 * max_val / 255 - max_val) * h + assert_array_almost_equal(flow, ref) + + +def test_flow2rgb(): + flow = np.array([[[0, 0], [0.5, 0.5], [1, 1], [2, 1], [3, np.inf]]], + dtype=np.float32) + flow_img = mmcv.flow2rgb(flow) + # yapf: disable + assert_array_almost_equal( + flow_img, + np.array([[[1., 1., 1.], + [1., 0.826074731, 0.683772236], + [1., 0.652149462, 0.367544472], + [1., 0.265650552, 5.96046448e-08], + [0., 0., 0.]]], + dtype=np.float32)) + # yapf: enable + + +def test_flow_warp(): + + img = np.zeros((5, 5, 3)) + img[2, 2, 0] = 1 + flow = np.ones((5, 5, 2)) + + res_nn = mmcv.flow_warp(img, flow, interpolate_mode='nearest') + res_bi = mmcv.flow_warp(img, flow, interpolate_mode='bilinear') + + assert_array_almost_equal(res_nn, res_bi, decimal=5) + + img = np.zeros((5, 5, 1)) + img[2, 2, 0] = 1 + img[2, 3, 0] = 0.75 + flow = np.zeros((5, 5, 2)) + flow[2, 2, :] = [0.5, 0.7] + + res_ = np.copy(img) + res_[2, 2] = 0.5 * 0.3 + 0.75 * 0.5 * 0.3 + res_bi = mmcv.flow_warp(img, flow, interpolate_mode='bilinear') + assert_array_almost_equal(res_, res_bi, decimal=5) + + with pytest.raises(NotImplementedError): + _ = mmcv.flow_warp(img, flow, interpolate_mode='xxx') + + with pytest.raises(AssertionError): + _ = mmcv.flow_warp(img, flow[:, :, 0], interpolate_mode='xxx') + + +def test_make_color_wheel(): + default_color_wheel = mmcv.make_color_wheel() + color_wheel = mmcv.make_color_wheel([2, 2, 2, 2, 2, 2]) + # yapf: disable + assert_array_equal(default_color_wheel, np.array( + [[1. , 0. , 0. ], # noqa + [1. , 0.06666667, 0. ], # noqa + [1. , 0.13333334, 0. ], # noqa + [1. , 0.2 , 0. ], # noqa + [1. , 0.26666668, 0. ], # noqa + [1. , 0.33333334, 0. ], # noqa + [1. , 0.4 , 0. ], # noqa + [1. , 0.46666667, 0. ], # noqa + [1. , 0.53333336, 0. ], # noqa + [1. , 0.6 , 0. ], # noqa + [1. , 0.6666667 , 0. ], # noqa + [1. , 0.73333335, 0. ], # noqa + [1. , 0.8 , 0. ], # noqa + [1. , 0.8666667 , 0. ], # noqa + [1. , 0.93333334, 0. ], # noqa + [1. , 1. , 0. ], # noqa + [0.8333333 , 1. , 0. ], # noqa + [0.6666667 , 1. , 0. ], # noqa + [0.5 , 1. , 0. ], # noqa + [0.33333334, 1. , 0. ], # noqa + [0.16666667, 1. , 0. ], # noqa + [0. , 1. , 0. ], # noqa + [0. , 1. , 0.25 ], # noqa + [0. , 1. , 0.5 ], # noqa + [0. , 1. , 0.75 ], # noqa + [0. , 1. , 1. ], # noqa + [0. , 0.90909094, 1. ], # noqa + [0. , 0.8181818 , 1. ], # noqa + [0. , 0.72727275, 1. ], # noqa + [0. , 0.6363636 , 1. ], # noqa + [0. , 0.54545456, 1. ], # noqa + [0. , 0.45454547, 1. ], # noqa + [0. , 0.36363637, 1. ], # noqa + [0. , 0.27272728, 1. ], # noqa + [0. , 0.18181819, 1. ], # noqa + [0. , 0.09090909, 1. ], # noqa + [0. , 0. , 1. ], # noqa + [0.07692308, 0. , 1. ], # noqa + [0.15384616, 0. , 1. ], # noqa + [0.23076923, 0. , 1. ], # noqa + [0.30769232, 0. , 1. ], # noqa + [0.3846154 , 0. , 1. ], # noqa + [0.46153846, 0. , 1. ], # noqa + [0.53846157, 0. , 1. ], # noqa + [0.61538464, 0. , 1. ], # noqa + [0.6923077 , 0. , 1. ], # noqa + [0.7692308 , 0. , 1. ], # noqa + [0.84615386, 0. , 1. ], # noqa + [0.9230769 , 0. , 1. ], # noqa + [1. , 0. , 1. ], # noqa + [1. , 0. , 0.8333333 ], # noqa + [1. , 0. , 0.6666667 ], # noqa + [1. , 0. , 0.5 ], # noqa + [1. , 0. , 0.33333334], # noqa + [1. , 0. , 0.16666667]], dtype=np.float32)) # noqa + + assert_array_equal( + color_wheel, + np.array([[1., 0. , 0. ], # noqa + [1. , 0.5, 0. ], # noqa + [1. , 1. , 0. ], # noqa + [0.5, 1. , 0. ], # noqa + [0. , 1. , 0. ], # noqa + [0. , 1. , 0.5], # noqa + [0. , 1. , 1. ], # noqa + [0. , 0.5, 1. ], # noqa + [0. , 0. , 1. ], # noqa + [0.5, 0. , 1. ], # noqa + [1. , 0. , 1. ], # noqa + [1. , 0. , 0.5]], dtype=np.float32)) # noqa + # yapf: enable + + +def test_flow_from_bytes(): + data_dir = osp.join(osp.dirname(__file__), '../data') + flow_shape = (60, 80, 2) + flow_file = osp.join(data_dir, 'optflow.flo') + + # read .flo file + flow_fromfile = mmcv.flowread(flow_file) + + with open(flow_file, 'rb') as f: + flow_bytes = f.read() + flow_frombytes = mmcv.flow_from_bytes(flow_bytes) + + assert flow_frombytes.shape == flow_shape + assert np.all(flow_frombytes == flow_fromfile) + + +def test_sparse_flow_from_bytes(): + data_dir = osp.join(osp.dirname(__file__), '../data') + flow_file = osp.join(data_dir, 'sparse_flow.png') + + with open(flow_file, 'rb') as f: + flow_bytes = f.read() + # read flow from bytes + flow_frombytes, valid_frombytes = mmcv.sparse_flow_from_bytes(flow_bytes) + + # test flow shape is [H, W, 2] and valid shape is [H, W] + assert flow_frombytes.shape[:2] == valid_frombytes.shape + assert flow_frombytes.shape[2] == 2 + + def read_sparse_flow_from_file(): + flow = cv2.imread(flow_file, cv2.IMREAD_ANYDEPTH | cv2.IMREAD_COLOR) + flow = flow[:, :, ::-1].astype(np.float32) + flow, valid = flow[:, :, :2], flow[:, :, 2] + flow = (flow - 2**15) / 64.0 + return flow, valid + + # read flow from file + flow_flowfile, valid_fromfile = read_sparse_flow_from_file() + + assert np.all(flow_frombytes == flow_flowfile) + assert np.all(valid_frombytes == valid_fromfile) diff --git a/cv/distiller/CWD/mmcv/tests/test_video/test_processing.py b/cv/distiller/CWD/mmcv/tests/test_video/test_processing.py new file mode 100644 index 000000000..88c37a2bd --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_video/test_processing.py @@ -0,0 +1,58 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import os.path as osp +import platform +import tempfile + +import pytest + +import mmcv + + +class TestVideoEditor: + + @classmethod + def setup_class(cls): + cls.video_path = osp.join(osp.dirname(__file__), '../data/test.mp4') + cls.num_frames = 168 + + @pytest.mark.skipif(platform.system() == 'Windows', reason='skip windows') + def test_cut_concat_video(self): + part1_file = osp.join(tempfile.gettempdir(), '.mmcv_test1.mp4') + part2_file = osp.join(tempfile.gettempdir(), '.mmcv_test2.mp4') + mmcv.cut_video(self.video_path, part1_file, end=3, vcodec='h264') + mmcv.cut_video(self.video_path, part2_file, start=3, vcodec='h264') + v1 = mmcv.VideoReader(part1_file) + v2 = mmcv.VideoReader(part2_file) + assert len(v1) == 75 + assert len(v2) == self.num_frames - 75 + + out_file = osp.join(tempfile.gettempdir(), '.mmcv_test.mp4') + mmcv.concat_video([part1_file, part2_file], out_file) + v = mmcv.VideoReader(out_file) + assert len(v) == self.num_frames + os.remove(part1_file) + os.remove(part2_file) + os.remove(out_file) + + @pytest.mark.skipif(platform.system() == 'Windows', reason='skip windows') + def test_resize_video(self): + out_file = osp.join(tempfile.gettempdir(), '.mmcv_test.mp4') + mmcv.resize_video( + self.video_path, out_file, (200, 100), log_level='panic') + v = mmcv.VideoReader(out_file) + assert v.resolution == (200, 100) + os.remove(out_file) + mmcv.resize_video(self.video_path, out_file, ratio=2) + v = mmcv.VideoReader(out_file) + assert v.resolution == (294 * 2, 240 * 2) + os.remove(out_file) + mmcv.resize_video(self.video_path, out_file, (1000, 480), keep_ar=True) + v = mmcv.VideoReader(out_file) + assert v.resolution == (294 * 2, 240 * 2) + os.remove(out_file) + mmcv.resize_video( + self.video_path, out_file, ratio=(2, 1.5), keep_ar=True) + v = mmcv.VideoReader(out_file) + assert v.resolution == (294 * 2, 360) + os.remove(out_file) diff --git a/cv/distiller/CWD/mmcv/tests/test_video/test_reader.py b/cv/distiller/CWD/mmcv/tests/test_video/test_reader.py new file mode 100644 index 000000000..c3bbdb7dc --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_video/test_reader.py @@ -0,0 +1,210 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import os.path as osp +import shutil +import tempfile +from collections import OrderedDict + +import pytest + +import mmcv + + +class TestCache: + + def test_init(self): + with pytest.raises(ValueError): + mmcv.Cache(0) + cache = mmcv.Cache(100) + assert cache.capacity == 100 + assert cache.size == 0 + + def test_put(self): + cache = mmcv.Cache(3) + for i in range(1, 4): + cache.put(f'k{i}', i) + assert cache.size == i + assert cache._cache == OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)]) + cache.put('k4', 4) + assert cache.size == 3 + assert cache._cache == OrderedDict([('k2', 2), ('k3', 3), ('k4', 4)]) + cache.put('k2', 2) + assert cache._cache == OrderedDict([('k2', 2), ('k3', 3), ('k4', 4)]) + + def test_get(self): + cache = mmcv.Cache(3) + assert cache.get('key_none') is None + assert cache.get('key_none', 0) == 0 + cache.put('k1', 1) + assert cache.get('k1') == 1 + + +class TestVideoReader: + + @classmethod + def setup_class(cls): + cls.video_path = osp.join(osp.dirname(__file__), '../data/test.mp4') + cls.num_frames = 168 + cls.video_url = 'https://download.openmmlab.com/mmcv/test_data/sample-mp4-file.mp4' # noqa: E501 + + def test_load(self): + # read from video file + v = mmcv.VideoReader(self.video_path) + assert v.width == 294 + assert v.height == 240 + assert v.fps == 25 + assert v.frame_cnt == self.num_frames + assert len(v) == self.num_frames + assert v.opened + import cv2 + assert isinstance(v.vcap, type(cv2.VideoCapture())) + + # read from video url + v = mmcv.VideoReader(self.video_url) + assert v.width == 320 + assert v.height == 240 + assert v.fps == 15 + assert v.frame_cnt == 1889 + assert len(v) == 1889 + assert v.opened + assert isinstance(v.vcap, type(cv2.VideoCapture())) + + def test_read(self): + v = mmcv.VideoReader(self.video_path) + img = v.read() + assert int(round(img.mean())) == 94 + img = v.get_frame(63) + assert int(round(img.mean())) == 94 + img = v[64] + assert int(round(img.mean())) == 205 + img = v[-104] + assert int(round(img.mean())) == 205 + img = v[63] + assert int(round(img.mean())) == 94 + img = v[-105] + assert int(round(img.mean())) == 94 + img = v.read() + assert int(round(img.mean())) == 205 + with pytest.raises(IndexError): + v.get_frame(self.num_frames + 1) + with pytest.raises(IndexError): + v[-self.num_frames - 1] + + def test_slice(self): + v = mmcv.VideoReader(self.video_path) + imgs = v[-105:-103] + assert int(round(imgs[0].mean())) == 94 + assert int(round(imgs[1].mean())) == 205 + assert len(imgs) == 2 + imgs = v[63:65] + assert int(round(imgs[0].mean())) == 94 + assert int(round(imgs[1].mean())) == 205 + assert len(imgs) == 2 + imgs = v[64:62:-1] + assert int(round(imgs[0].mean())) == 205 + assert int(round(imgs[1].mean())) == 94 + assert len(imgs) == 2 + imgs = v[:5] + assert len(imgs) == 5 + for img in imgs: + assert int(round(img.mean())) == 94 + imgs = v[165:] + assert len(imgs) == 3 + for img in imgs: + assert int(round(img.mean())) == 0 + imgs = v[-3:] + assert len(imgs) == 3 + for img in imgs: + assert int(round(img.mean())) == 0 + + def test_current_frame(self): + v = mmcv.VideoReader(self.video_path) + assert v.current_frame() is None + v.read() + img = v.current_frame() + assert int(round(img.mean())) == 94 + + def test_position(self): + v = mmcv.VideoReader(self.video_path) + assert v.position == 0 + for _ in range(10): + v.read() + assert v.position == 10 + v.get_frame(99) + assert v.position == 100 + + def test_iterator(self): + cnt = 0 + for img in mmcv.VideoReader(self.video_path): + cnt += 1 + assert img.shape == (240, 294, 3) + assert cnt == self.num_frames + + def test_with(self): + with mmcv.VideoReader(self.video_path) as v: + assert v.opened + assert not v.opened + + def test_cvt2frames(self): + v = mmcv.VideoReader(self.video_path) + frame_dir = tempfile.mkdtemp() + v.cvt2frames(frame_dir) + assert osp.isdir(frame_dir) + for i in range(self.num_frames): + filename = f'{frame_dir}/{i:06d}.jpg' + assert osp.isfile(filename) + os.remove(filename) + + v = mmcv.VideoReader(self.video_path) + v.cvt2frames(frame_dir, show_progress=False) + assert osp.isdir(frame_dir) + for i in range(self.num_frames): + filename = f'{frame_dir}/{i:06d}.jpg' + assert osp.isfile(filename) + os.remove(filename) + + v = mmcv.VideoReader(self.video_path) + v.cvt2frames( + frame_dir, + file_start=100, + filename_tmpl='{:03d}.JPEG', + start=100, + max_num=20) + assert osp.isdir(frame_dir) + for i in range(100, 120): + filename = f'{frame_dir}/{i:03d}.JPEG' + assert osp.isfile(filename) + os.remove(filename) + shutil.rmtree(frame_dir) + + def test_frames2video(self): + v = mmcv.VideoReader(self.video_path) + frame_dir = tempfile.mkdtemp() + v.cvt2frames(frame_dir) + assert osp.isdir(frame_dir) + for i in range(self.num_frames): + filename = f'{frame_dir}/{i:06d}.jpg' + assert osp.isfile(filename) + + out_filename = osp.join(tempfile.gettempdir(), 'mmcv_test.avi') + mmcv.frames2video(frame_dir, out_filename) + v = mmcv.VideoReader(out_filename) + assert v.fps == 30 + assert len(v) == self.num_frames + + mmcv.frames2video( + frame_dir, + out_filename, + fps=25, + start=10, + end=50, + show_progress=False) + + with mmcv.VideoReader(out_filename) as v: + assert v.fps == 25 + assert len(v) == 40 + + for i in range(self.num_frames): + filename = f'{frame_dir}/{i:06d}.jpg' + os.remove(filename) + shutil.rmtree(frame_dir) diff --git a/cv/distiller/CWD/mmcv/tests/test_visualization.py b/cv/distiller/CWD/mmcv/tests/test_visualization.py new file mode 100644 index 000000000..82dd093bf --- /dev/null +++ b/cv/distiller/CWD/mmcv/tests/test_visualization.py @@ -0,0 +1,19 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import pytest + +import mmcv + + +def test_color(): + assert mmcv.color_val(mmcv.Color.blue) == (255, 0, 0) + assert mmcv.color_val('green') == (0, 255, 0) + assert mmcv.color_val((1, 2, 3)) == (1, 2, 3) + assert mmcv.color_val(100) == (100, 100, 100) + assert mmcv.color_val(np.zeros(3, dtype=int)) == (0, 0, 0) + with pytest.raises(TypeError): + mmcv.color_val([255, 255, 255]) + with pytest.raises(TypeError): + mmcv.color_val(1.0) + with pytest.raises(AssertionError): + mmcv.color_val((0, 0, 500)) diff --git a/cv/distiller/CWD/mmrazor b/cv/distiller/CWD/mmrazor new file mode 160000 index 000000000..d3cd028f4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor @@ -0,0 +1 @@ +Subproject commit d3cd028f4b998d8701cfa9c9fced3bad94660217 -- Gitee From a1105a8d670d8d3fa912000213916b1986b8e9ab Mon Sep 17 00:00:00 2001 From: "yongle.wu" Date: Wed, 17 May 2023 08:56:26 +0000 Subject: [PATCH 2/6] rm -rf .git --- cv/distiller/CWD/mmrazor | 1 - 1 file changed, 1 deletion(-) delete mode 160000 cv/distiller/CWD/mmrazor diff --git a/cv/distiller/CWD/mmrazor b/cv/distiller/CWD/mmrazor deleted file mode 160000 index d3cd028f4..000000000 --- a/cv/distiller/CWD/mmrazor +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d3cd028f4b998d8701cfa9c9fced3bad94660217 -- Gitee From f7646ab3d9f1cd5aa3bde3dafc0205235f6ec064 Mon Sep 17 00:00:00 2001 From: "yongle.wu" Date: Wed, 17 May 2023 08:57:49 +0000 Subject: [PATCH 3/6] add mmrazor --- cv/distiller/CWD/mmrazor/.circleci/config.yml | 34 + .../CWD/mmrazor/.circleci/docker/Dockerfile | 11 + cv/distiller/CWD/mmrazor/.circleci/test.yml | 193 +++ .../.dev_scripts/benchmark_summary_analyse.py | 67 + .../mmrazor/.dev_scripts/benchmark_test.py | 307 +++++ .../mmrazor/.dev_scripts/benchmark_train.py | 338 ++++++ .../mmrazor/.dev_scripts/meta_files_test.py | 58 + .../CWD/mmrazor/.pre-commit-config.yaml | 72 ++ cv/distiller/CWD/mmrazor/.readthedocs.yml | 9 + cv/distiller/CWD/mmrazor/LICENSE | 203 ++++ cv/distiller/CWD/mmrazor/MANIFEST.in | 6 + cv/distiller/CWD/mmrazor/README.md | 235 ++++ cv/distiller/CWD/mmrazor/README_zh-CN.md | 226 ++++ .../datasets/mmcls/cifar100_bs16_auto_aug.py | 50 + .../mmcls/pipelines/auto_aug_cifar.py | 125 ++ .../attentive_mobilenetv3_supernet.py | 49 + .../_base_/nas_backbones/darts_supernet.py | 31 + .../dsnas_shufflenet_supernet.py | 28 + .../nas_backbones/ofa_mobilenetv3_supernet.py | 57 + .../nas_backbones/spos_mobilenet_supernet.py | 65 + .../nas_backbones/spos_shufflenet_supernet.py | 23 + .../_base_/settings/cifar10_darts_subnet.py | 68 ++ .../_base_/settings/cifar10_darts_supernet.py | 88 ++ .../_base_/settings/imagenet_bs1024_dsnas.py | 102 ++ .../_base_/settings/imagenet_bs1024_spos.py | 83 ++ .../_base_/settings/imagenet_bs2048_AdamW.py | 180 +++ .../settings/imagenet_bs2048_autoslim.py | 15 + .../settings/imagenet_bs2048_autoslim_pil.py | 13 + .../_base_/settings/imagenet_bs2048_bignas.py | 400 ++++++ .../_base_/settings/imagenet_bs2048_dmcp.py | 98 ++ .../_base_/settings/imagenet_bs2048_ofa.py | 98 ++ .../_base_/vanilla_models/wrn16_2_cifar10.py | 20 + .../configs/distill/mmcls/abloss/README.md | 69 ++ ...oss_logits_resnet50_resnet18_8xb32_in1k.py | 40 + ...n_backbone_resnet50_resnet18_8xb32_in1k.py | 97 ++ .../configs/distill/mmcls/abloss/metafile.yml | 36 + .../configs/distill/mmcls/byot/README.md | 57 + .../byot/byot_resnet18_8xb16_cifar100.py | 155 +++ .../configs/distill/mmcls/byot/metafile.yml | 31 + .../configs/distill/mmcls/crd/README.md | 30 + .../crd/crd_neck_r50_r18_8xb16_cifar10.py | 108 ++ .../mmcls/crd/datasets/crd_cifar10_bs16.py | 49 + .../configs/distill/mmcls/dafl/README.md | 38 + ...logits_resnet34_resnet18_8xb256_cifar10.py | 105 ++ .../configs/distill/mmcls/dafl/metafile.yml | 43 + .../configs/distill/mmcls/deit/README.md | 45 + .../deit-base_regnety160_pt-16xb64_in1k.py | 64 + .../configs/distill/mmcls/deit/metafile.yml | 34 + .../configs/distill/mmcls/dfad/README.md | 30 + ..._logits_resnet34_resnet18_8xb32_cifar10.py | 100 ++ .../configs/distill/mmcls/dfad/metafile.yml | 43 + .../configs/distill/mmcls/dkd/README.md | 47 + .../dkd/dkd_resnet34_resnet18_8xb32_in1k.py | 47 + .../configs/distill/mmcls/dkd/metafile.yml | 43 + .../distill/mmcls/factor_transfer/README.md | 53 + ...esnet50_resnet18_8xb16_cifar10_pretrain.py | 59 + ...e_resnet50_resnet18_8xb16_cifar10_train.py | 29 + .../mmcls/factor_transfer/metafile.yml | 38 + .../configs/distill/mmcls/fitnets/README.md | 48 + ...one_logits_resnet50_resnet18_8xb32_in1k.py | 72 ++ .../distill/mmcls/fitnets/metafile.yml | 40 + .../configs/distill/mmcls/kd/README.md | 34 + .../kd_logits_resnet34_resnet18_8xb32_in1k.py | 39 + ...logits_resnet50_mobilenet-v2_8xb32_in1k.py | 37 + ...s_resnet50_shufflenet-v2-1x_16xb64_in1k.py | 37 + .../configs/distill/mmcls/kd/metafile.yml | 82 ++ .../configs/distill/mmcls/ofd/README.md | 63 + .../configs/distill/mmcls/ofd/metafile.yml | 38 + ...ackbone_resnet50_resnet18_8xb16_cifar10.py | 100 ++ .../configs/distill/mmcls/rkd/README.md | 43 + .../configs/distill/mmcls/rkd/metafile.yml | 38 + .../rkd_neck_resnet34_resnet18_8xb32_in1k.py | 44 + .../configs/distill/mmcls/wsld/README.md | 43 + .../configs/distill/mmcls/wsld/metafile.yml | 38 + ...sld_logits_resnet34_resnet18_8xb32_in1k.py | 41 + .../configs/distill/mmcls/zskt/README.md | 37 + .../configs/distill/mmcls/zskt/metafile.yml | 43 + ..._logits_resnet34_resnet18_8xb16_cifar10.py | 139 +++ .../configs/distill/mmdet/cwd/README.md | 37 + ...s_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py | 9 + .../cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py | 54 + .../cwd_fpn_retina_r101_retina_r50_1x_coco.py | 13 + ...a_r101_retina_r50_1x_coco_visualization.py | 21 + .../configs/distill/mmdet/cwd/metafile.yml | 23 + .../configs/distill/mmdet/fbkd/README.md | 37 + ...aster-rcnn_r101_faster-rcnn_r50_1x_coco.py | 126 ++ .../configs/distill/mmdet/fbkd/metafile.yml | 41 + .../configs/distill/mmdet/mgd/README.md | 30 + .../mgd_fpn_retina_x101_retina_r50_2x_coco.py | 118 ++ .../configs/distill/mmdet/pkd/README.md | 34 + .../configs/distill/mmdet/pkd/metafile.yml | 110 ++ ...aster-rcnn_r101_faster-rcnn_r50_2x_coco.py | 45 + .../pkd_fpn_fcos_x101_retina_r50_1x_coco.py | 27 + ...d_fpn_mask-rcnn_swin_retina_r50_2x_coco.py | 53 + ...eppoints_x101-dcn_reppoints_r50_2x_coco.py | 13 + .../pkd_fpn_retina_x101_retina_r50_2x_coco.py | 19 + .../configs/distill/mmdet3d/pkd/README.md | 30 + .../configs/distill/mmdet3d/pkd/metafile.yml | 22 + ...os3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py | 49 + .../configs/distill/mmseg/cwd/README.md | 37 + ...net_r18-d8_4xb2-80k_cityscapes-512x1024.py | 31 + .../configs/distill/mmseg/cwd/metafile.yml | 41 + .../mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml | 134 ++ .../configs/nas/mmcls/autoformer/README.md | 75 ++ .../autoformer_search_8xb128_in1k.py | 17 + .../autoformer_subnet_8xb256_in1k.py | 17 + .../autoformer_supernet_32xb256_in1k.py | 68 ++ .../configs/nas/mmcls/autoslim/README.md | 87 ++ .../autoslim_mbv2_1.5x_search_8xb256_in1k.py | 19 + ..._mbv2_1.5x_slimmable_subnet_8xb256_in1k.py | 46 + ...mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py | 3 + ...mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py | 3 + ...mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py | 3 + ...autoslim_mbv2_1.5x_supernet_8xb256_in1k.py | 68 ++ .../configs/nas/mmcls/autoslim/metafile.yml | 60 + .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml | 64 + .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A1.yaml | 64 + .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A2.yaml | 64 + .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A3.yaml | 64 + .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A4.yaml | 64 + .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A5.yaml | 64 + .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A6.yaml | 64 + .../configs/nas/mmcls/bignas/README.md | 69 ++ .../attentive_mobilenet_search_8xb128_in1k.py | 16 + .../attentive_mobilenet_subnet_8xb256_in1k.py | 24 + ...ttentive_mobilenet_supernet_32xb64_in1k.py | 59 + .../DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml | 80 ++ .../darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml | 116 ++ .../mmrazor/configs/nas/mmcls/darts/README.md | 65 + .../darts/darts_subnet_1xb96_cifar10_2.0.py | 44 + .../darts_subnet_1xb96_cifar10_2.0_mmrazor.py | 39 + .../darts_supernet_unroll_1xb96_cifar10.py | 33 + .../configs/nas/mmcls/darts/metafile.yml | 28 + .../DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml | 40 + .../mmrazor/configs/nas/mmcls/dsnas/README.md | 61 + .../mmcls/dsnas/dsnas_subnet_8xb128_in1k.py | 12 + .../mmcls/dsnas/dsnas_supernet_8xb128_in1k.py | 43 + .../onceforall/OFA_SUBNET_NOTE8_LAT22.yaml | 140 +++ .../onceforall/OFA_SUBNET_NOTE8_LAT31.yaml | 148 +++ .../configs/nas/mmcls/onceforall/README.md | 50 + .../ofa_mobilenet_search_8xb128_in1k.py | 16 + .../ofa_mobilenet_subnet_8xb256_in1k.py | 22 + .../ofa_mobilenet_supernet_32xb64_in1k.py | 51 + .../mmrazor/configs/nas/mmcls/spos/README.md | 76 ++ .../configs/nas/mmcls/spos/SPOS_SUBNET.yaml | 40 + .../faster-rcnn_nas_backbone_fpn_1x_coco.py | 21 + .../configs/nas/mmcls/spos/metafile.yml | 28 + .../spos/spos_mobilenet_search_8xb128_in1k.py | 17 + .../spos/spos_mobilenet_subnet_8xb128_in1k.py | 17 + .../spos_mobilenet_supernet_8xb128_in1k.py | 31 + .../spos_shufflenet_search_8xb128_in1k.py | 17 + ...shufflenet_search_predictor_8xb128_in1k.py | 21 + .../spos_shufflenet_subnet_8xb128_in1k.py | 17 + .../spos_shufflenet_supernet_8xb128_in1k.py | 31 + .../nas/mmdet/detnas/DETNAS_SUBNET.yaml | 40 + .../configs/nas/mmdet/detnas/README.md | 87 ++ .../detnas_frcnn_shufflenet_search_coco_1x.py | 17 + .../detnas_frcnn_shufflenet_subnet_coco_1x.py | 15 + ...etnas_frcnn_shufflenet_supernet_coco_1x.py | 30 + ...tnas_retina_shufflenet_supernet_coco_1x.py | 27 + .../detnas_shufflenet_subnet_8xb128_in1k.py | 12 + .../detnas_shufflenet_supernet_8xb128_in1k.py | 1 + .../configs/nas/mmdet/detnas/metafile.yml | 30 + .../pruning/base/group_fisher/README.md | 246 ++++ .../group_fisher_deploy_template.py | 24 + .../group_fisher_finetune_template.py | 32 + .../group_fisher_prune_template.py | 75 ++ .../configs/pruning/mmcls/dcff/README.md | 82 ++ .../dcff/dcff_compact_resnet_8xb32_in1k.py | 13 + .../mmcls/dcff/dcff_resnet_8xb32_in1k.py | 84 ++ .../pruning/mmcls/dcff/fix_subnet.json | 141 +++ .../pruning/mmcls/dmcp/DMCP_MBV2_100M.json | 271 +++++ .../pruning/mmcls/dmcp/DMCP_R50_2G.json | 391 ++++++ .../configs/pruning/mmcls/dmcp/README.md | 62 + .../mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py | 49 + .../mmcls/dmcp/dmcp_mbv2_supernet_32xb64.py | 61 + .../mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py | 48 + .../dmcp/dmcp_resnet50_supernet_32xb64.py | 67 + .../configs/pruning/mmcls/dmcp/metafile.yml | 19 + .../pruning/mmcls/group_fisher/README.md | 11 + ...sher_act_deploy_mobilenet-v2_8xb32_in1k.py | 50 + ...er_act_finetune_mobilenet-v2_8xb32_in1k.py | 31 + ...isher_act_prune_mobilenet-v2_8xb32_in1k.py | 75 ++ ...er_flops_deploy_mobilenet-v2_8xb32_in1k.py | 49 + ..._flops_finetune_mobilenet-v2_8xb32_in1k.py | 32 + ...her_flops_prune_mobilenet-v2_8xb32_in1k.py | 5 + .../mmcls/group_fisher/mobilenet/metafile.yml | 19 + .../mmcls/group_fisher/mobilenet/script.sh | 47 + ...p_fisher_act_deploy_resnet50_8xb32_in1k.py | 61 + ...fisher_act_finetune_resnet50_8xb32_in1k.py | 31 + ...r_act_finetune_resnet50_8xb32_in1k_dist.py | 61 + ...up_fisher_act_prune_resnet50_8xb32_in1k.py | 75 ++ ...fisher_flops_deploy_resnet50_8xb32_in1k.py | 61 + ...sher_flops_finetune_resnet50_8xb32_in1k.py | 31 + ..._fisher_flops_prune_resnet50_8xb32_in1k.py | 5 + .../mmcls/group_fisher/resnet50/metafile.yml | 19 + .../mmcls/group_fisher/resnet50/script.sh | 49 + .../configs/pruning/mmcls/l1-norm/README.md | 61 + .../l1-norm/l1-norm_resnet34_8xb32_in1k_a.py | 60 + .../l1-norm_resnet34_8xb32_in1k_a_deploy.py | 57 + .../l1-norm/l1-norm_resnet34_8xb32_in1k_b.py | 38 + .../l1-norm_resnet34_8xb32_in1k_b_deploy.py | 57 + .../l1-norm/l1-norm_resnet34_8xb32_in1k_c.py | 34 + .../l1-norm_resnet34_8xb32_in1k_c_deploy.py | 54 + .../pruning/mmcls/l1-norm/metafile.yml | 28 + .../configs/pruning/mmcls/l1-norm/script.sh | 25 + .../configs/pruning/mmdet/dcff/README.md | 82 ++ ..._compact_faster_rcnn_resnet50_8xb4_coco.py | 12 + .../dcff_faster_rcnn_resnet50_8xb4_coco.py | 87 ++ .../dcff/dcff_faster_rcnn_resnet50_fpn.py | 114 ++ .../pruning/mmdet/dcff/fix_subnet.json | 141 +++ .../pruning/mmdet/group_fisher/README.md | 11 + ...er_act_deploy_retinanet_r50_fpn_1x_coco.py | 73 ++ ..._act_finetune_retinanet_r50_fpn_1x_coco.py | 31 + ...her_act_prune_retinanet_r50_fpn_1x_coco.py | 76 ++ ..._flops_deploy_retinanet_r50_fpn_1x_coco.py | 73 ++ ...lops_finetune_retinanet_r50_fpn_1x_coco.py | 31 + ...r_flops_prune_retinanet_r50_fpn_1x_coco.py | 5 + .../mmdet/group_fisher/retinanet/metafile.yml | 19 + .../mmdet/group_fisher/retinanet/script.sh | 49 + .../configs/pruning/mmpose/dcff/README.md | 82 ++ ...f_compact_topdown_heatmap_resnet50_coco.py | 12 + .../dcff_topdown_heatmap_resnet50_coco.py | 188 +++ .../pruning/mmpose/dcff/fix_subnet.json | 141 +++ ..._rtmpose-s_8xb256-420e_aic-coco-256x192.py | 53 + ...ploy_rtmpose-s_8xb256-420e_coco-256x192.py | 53 + ..._rtmpose-s_8xb256-420e_aic-coco-256x192.py | 32 + ...tune_rtmpose-s_8xb256-420e_coco-256x192.py | 33 + ..._rtmpose-s_8xb256-420e_aic-coco-256x192.py | 75 ++ ...rune_rtmpose-s_8xb256-420e_coco-256x192.py | 75 ++ .../pruning/mmpose/group_fisher/script.sh | 39 + .../configs/pruning/mmseg/dcff/README.md | 82 ++ ...pact_pointrend_resnet50_8xb2_cityscapes.py | 12 + ...dcff_pointrend_resnet50_8xb2_cityscapes.py | 99 ++ .../pruning/mmseg/dcff/fix_subnet.json | 141 +++ .../pruning/mmseg/dcff/pointrend_resnet50.py | 63 + ...classification_openvino_dynamic-224x224.py | 30 + ..._tensorrt-int8-explicit_dynamic-224x224.py | 39 + .../detection_openvino_dynamic-800x1344.py | 47 + ...int8-explicit_dynamic-320x320-1344x1344.py | 58 + .../configs/quantization/ptq/base/README.md | 59 + .../quantization/ptq/base/metafile.yml | 164 +++ ...tq_openvino_mbv2_8xb32_in1k_calib32xb32.py | 54 + ...penvino_resnet18_8xb32_in1k_calib32xb32.py | 51 + ...penvino_resnet50_8xb32_in1k_calib32xb32.py | 50 + ...openvino_retina_r50_1x_coco_calib32xb32.py | 52 + ...vino_yolox_s_8xb8-300e_coco_calib32xb32.py | 57 + ...tq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py | 54 + ...ensorrt_resnet18_8xb32_in1k_calib32xb32.py | 51 + ...ensorrt_resnet50_8xb32_in1k_calib32xb32.py | 51 + ...tensorrt_retina_r50_1x_coco_calib32xb32.py | 53 + ...orrt_yolox_s_8xb8-300e_coco_calib32xb32.py | 58 + .../configs/quantization/qat/base/README.md | 45 + .../quantization/qat/base/metafile.yml | 20 + .../qat_openvino_resnet18_10e_8xb32_in1k.py | 62 + .../configs/quantization/qat/lsq/README.md | 46 + .../lsq_openvino_resnet18_8xb32_100e_in1k.py | 68 ++ .../lsq_openvino_resnet18_8xb32_10e_in1k.py | 63 + .../configs/quantization/qat/lsq/metafile.yml | 36 + .../vanilla/mmcls/wide-resnet/README.md | 34 + .../wide-resnet/wrn16-w2_b16x8_cifar10.py | 7 + .../wide-resnet/wrn22-w4_b16x8_cifar10.py | 3 + .../wide-resnet/wrn28-w4_b16x8_cifar10.py | 3 + .../wide-resnet/wrn40-w2_b16x8_cifar10.py | 3 + cv/distiller/CWD/mmrazor/mmrazor/__init__.py | 27 + .../CWD/mmrazor/mmrazor/datasets/__init__.py | 5 + .../mmrazor/datasets/crd_dataset_wrapper.py | 254 ++++ .../mmrazor/datasets/transforms/__init__.py | 6 + .../datasets/transforms/auto_augment.py | 415 +++++++ .../datasets/transforms/auto_augmentv2.py | 540 +++++++++ .../mmrazor/datasets/transforms/formatting.py | 73 ++ .../CWD/mmrazor/mmrazor/engine/__init__.py | 19 + .../mmrazor/mmrazor/engine/hooks/__init__.py | 11 + .../mmrazor/engine/hooks/dmcp_subnet_hook.py | 74 ++ .../mmrazor/engine/hooks/dump_subnet_hook.py | 169 +++ .../engine/hooks/estimate_resources_hook.py | 122 ++ .../engine/hooks/group_fisher_hooks.py | 9 + .../engine/hooks/stop_distillation_hook.py | 31 + .../engine/hooks/visualization_hook.py | 205 ++++ .../mmrazor/engine/optimizers/__init__.py | 4 + .../optimizers/optimizer_constructor.py | 71 ++ .../mmrazor/mmrazor/engine/runner/__init__.py | 19 + .../runner/autoslim_greedy_search_loop.py | 223 ++++ .../mmrazor/engine/runner/darts_loop.py | 181 +++ .../mmrazor/engine/runner/distill_val_loop.py | 127 ++ .../engine/runner/evolution_search_loop.py | 443 +++++++ .../engine/runner/iteprune_val_loop.py | 58 + .../engine/runner/quantization_loops.py | 399 ++++++ .../engine/runner/slimmable_val_loop.py | 58 + .../engine/runner/subnet_sampler_loop.py | 338 ++++++ .../mmrazor/engine/runner/subnet_val_loop.py | 96 ++ .../mmrazor/engine/runner/utils/__init__.py | 6 + .../engine/runner/utils/calibrate_bn_mixin.py | 141 +++ .../mmrazor/engine/runner/utils/check.py | 48 + .../mmrazor/engine/runner/utils/genetic.py | 31 + .../mmrazor/implementations/__init__.py | 13 + .../implementations/pruning/__init__.py | 4 + .../pruning/group_fisher/__init__.py | 24 + .../pruning/group_fisher/algorithm.py | 86 ++ .../pruning/group_fisher/counters.py | 16 + .../pruning/group_fisher/hook.py | 198 +++ .../pruning/group_fisher/mutator.py | 87 ++ .../pruning/group_fisher/ops.py | 150 +++ .../group_fisher/prune_deploy_sub_model.py | 78 ++ .../pruning/group_fisher/prune_sub_model.py | 105 ++ .../pruning/group_fisher/unit.py | 230 ++++ .../CWD/mmrazor/mmrazor/models/__init__.py | 12 + .../mmrazor/models/algorithms/__init__.py | 20 + .../mmrazor/mmrazor/models/algorithms/base.py | 209 ++++ .../models/algorithms/distill/__init__.py | 10 + .../distill/configurable/__init__.py | 13 + .../configurable/datafree_distillation.py | 229 ++++ .../configurable/fpn_teacher_distill.py | 59 + .../overhaul_feature_distillation.py | 53 + .../distill/configurable/self_distill.py | 92 ++ .../configurable/single_teacher_distill.py | 156 +++ .../mmrazor/models/algorithms/nas/__init__.py | 12 + .../models/algorithms/nas/autoformer.py | 63 + .../mmrazor/models/algorithms/nas/autoslim.py | 263 ++++ .../mmrazor/models/algorithms/nas/bignas.py | 280 +++++ .../mmrazor/models/algorithms/nas/darts.py | 523 ++++++++ .../mmrazor/models/algorithms/nas/dsnas.py | 332 +++++ .../mmrazor/models/algorithms/nas/spos.py | 97 ++ .../models/algorithms/pruning/__init__.py | 8 + .../mmrazor/models/algorithms/pruning/dcff.py | 153 +++ .../mmrazor/models/algorithms/pruning/dmcp.py | 425 +++++++ .../pruning/group_fisher_algoritho.py | 7 + .../algorithms/pruning/ite_prune_algorithm.py | 273 +++++ .../algorithms/pruning/slimmable_network.py | 219 ++++ .../algorithms/quantization/__init__.py | 4 + .../quantization/mm_architecture.py | 427 +++++++ .../mmrazor/models/architectures/__init__.py | 10 + .../architectures/backbones/__init__.py | 12 + .../architectures/backbones/darts_backbone.py | 376 ++++++ .../backbones/searchable_autoformer.py | 375 ++++++ .../backbones/searchable_mobilenet_v2.py | 229 ++++ .../backbones/searchable_mobilenet_v3.py | 366 ++++++ .../backbones/searchable_shufflenet_v2.py | 225 ++++ .../architectures/backbones/wideresnet.py | 403 +++++++ .../architectures/classifiers/__init__.py | 4 + .../models/architectures/classifiers/image.py | 104 ++ .../architectures/connectors/__init__.py | 17 + .../connectors/base_connector.py | 43 + .../connectors/byot_connector.py | 82 ++ .../connectors/convmodule_connector.py | 92 ++ .../architectures/connectors/crd_connector.py | 47 + .../connectors/factor_transfer_connectors.py | 133 ++ .../connectors/fbkd_connector.py | 298 +++++ .../architectures/connectors/mgd_connector.py | 71 ++ .../connectors/norm_connector.py | 19 + .../architectures/connectors/ofd_connector.py | 38 + .../connectors/torch_connector.py | 135 +++ .../architectures/dynamic_ops/__init__.py | 4 + .../dynamic_ops/bricks/__init__.py | 35 + .../dynamic_ops/bricks/dynamic_container.py | 109 ++ .../dynamic_ops/bricks/dynamic_conv.py | 286 +++++ .../dynamic_ops/bricks/dynamic_embed.py | 154 +++ .../dynamic_ops/bricks/dynamic_function.py | 61 + .../dynamic_ops/bricks/dynamic_linear.py | 53 + .../bricks/dynamic_multi_head_attention.py | 279 +++++ .../dynamic_ops/bricks/dynamic_norm.py | 482 ++++++++ .../bricks/dynamic_relative_position.py | 154 +++ .../dynamic_ops/bricks/group_fisher_ops.py | 11 + .../dynamic_ops/head/__init__.py | 4 + .../dynamic_ops/head/dynamic_linear_head.py | 85 ++ .../dynamic_ops/mixins/__init__.py | 14 + .../dynamic_ops/mixins/dynamic_conv_mixins.py | 572 +++++++++ .../mixins/dynamic_layernorm_mixins.py | 147 +++ .../dynamic_ops/mixins/dynamic_mixins.py | 455 +++++++ .../architectures/generators/__init__.py | 5 + .../generators/base_generator.py | 63 + .../generators/dafl_generator.py | 86 ++ .../generators/zskt_generator.py | 91 ++ .../models/architectures/heads/__init__.py | 5 + .../architectures/heads/darts_subnet_head.py | 83 ++ .../models/architectures/heads/deit_head.py | 69 ++ .../models/architectures/necks/__init__.py | 4 + .../necks/squeezemean_with_dropout.py | 57 + .../models/architectures/ops/__init__.py | 17 + .../mmrazor/models/architectures/ops/base.py | 19 + .../models/architectures/ops/common.py | 48 + .../models/architectures/ops/darts_series.py | 181 +++ .../architectures/ops/efficientnet_series.py | 165 +++ .../models/architectures/ops/function.py | 41 + .../architectures/ops/gather_tensors.py | 58 + .../architectures/ops/mobilenet_series.py | 217 ++++ .../architectures/ops/shufflenet_series.py | 261 ++++ .../architectures/ops/transformer_series.py | 193 +++ .../models/architectures/utils/__init__.py | 5 + .../architectures/utils/mutable_register.py | 86 ++ .../models/architectures/utils/set_dropout.py | 35 + .../mmrazor/models/distillers/__init__.py | 9 + .../models/distillers/base_distiller.py | 22 + .../models/distillers/byot_distiller.py | 44 + .../distillers/configurable_distiller.py | 294 +++++ .../models/distillers/ofd_distiller.py | 77 ++ .../mmrazor/models/fake_quants/__init__.py | 10 + .../mmrazor/models/fake_quants/base.py | 8 + .../mmrazor/mmrazor/models/fake_quants/lsq.py | 313 +++++ .../models/fake_quants/torch_fake_quants.py | 38 + .../mmrazor/mmrazor/models/losses/__init__.py | 28 + .../mmrazor/mmrazor/models/losses/ab_loss.py | 66 + .../mmrazor/mmrazor/models/losses/at_loss.py | 41 + .../mmrazor/mmrazor/models/losses/crd_loss.py | 271 +++++ .../models/losses/cross_entropy_loss.py | 23 + .../CWD/mmrazor/mmrazor/models/losses/cwd.py | 51 + .../mmrazor/models/losses/dafl_loss.py | 124 ++ .../mmrazor/models/losses/decoupled_kd.py | 157 +++ .../mmrazor/models/losses/dist_loss.py | 52 + .../models/losses/factor_transfer_loss.py | 38 + .../mmrazor/models/losses/fbkd_loss.py | 120 ++ .../mmrazor/models/losses/kd_soft_ce_loss.py | 94 ++ .../mmrazor/models/losses/kl_divergence.py | 66 + .../mmrazor/mmrazor/models/losses/l1_loss.py | 71 ++ .../mmrazor/mmrazor/models/losses/l2_loss.py | 75 ++ .../mmrazor/mmrazor/models/losses/mgd_loss.py | 54 + .../mmrazor/mmrazor/models/losses/ofd_loss.py | 56 + .../mmrazor/mmrazor/models/losses/pkd_loss.py | 83 ++ .../mmrazor/models/losses/relational_kd.py | 149 +++ .../weighted_soft_label_distillation.py | 59 + .../mmrazor/models/mutables/__init__.py | 27 + .../mmrazor/models/mutables/base_mutable.py | 94 ++ .../models/mutables/derived_mutable.py | 456 +++++++ .../mutable_channel/MutableChannel.md | 36 + .../mutables/mutable_channel/__init__.py | 18 + .../mutable_channel/base_mutable_channel.py | 85 ++ .../mutable_channel_container.py | 123 ++ .../oneshot_mutable_channel.py | 42 + .../sequential_mutable_channel.py | 140 +++ .../mutable_channel/simple_mutable_channel.py | 57 + .../mutable_channel/units/__init__.py | 15 + .../mutable_channel/units/channel_unit.py | 258 ++++ .../units/dcff_channel_unit.py | 50 + .../units/dmcp_channel_unit.py | 50 + .../units/group_fisher_unit.py | 7 + .../units/l1_mutable_channel_unit.py | 82 ++ .../units/mutable_channel_unit.ipynb | 314 +++++ .../units/mutable_channel_unit.py | 308 +++++ .../units/one_shot_mutable_channel_unit.py | 139 +++ .../units/sequential_mutable_channel_unit.py | 157 +++ .../units/slimmable_channel_unit.py | 59 + .../mutables/mutable_channel/units/utils.py | 80 ++ .../mutables/mutable_module/__init__.py | 11 + .../mutable_module/diff_mutable_module.py | 582 +++++++++ .../mutables/mutable_module/mutable_module.py | 97 ++ .../mutable_module/one_shot_mutable_module.py | 299 +++++ .../models/mutables/mutable_value/__init__.py | 4 + .../mutables/mutable_value/mutable_value.py | 246 ++++ .../mmrazor/models/mutators/__init__.py | 10 + .../mmrazor/models/mutators/base_mutator.py | 53 + .../mutators/channel_mutator/__init__.py | 11 + .../channel_mutator/channel_mutator.ipynb | 375 ++++++ .../channel_mutator/channel_mutator.py | 374 ++++++ .../channel_mutator/dcff_channel_mutator.py | 47 + .../channel_mutator/dmcp_channel_mutator.py | 178 +++ .../channel_mutator/group_fisher_mutator.py | 7 + .../one_shot_channel_mutator.py | 70 ++ .../slimmable_channel_mutator.py | 82 ++ .../mmrazor/models/mutators/group_mixin.py | 261 ++++ .../mmrazor/models/mutators/nas_mutator.py | 260 ++++ .../mmrazor/models/observers/__init__.py | 9 + .../mmrazor/mmrazor/models/observers/base.py | 8 + .../mmrazor/mmrazor/models/observers/lsq.py | 129 ++ .../models/observers/torch_observers.py | 66 + .../mmrazor/models/quantizers/__init__.py | 11 + .../models/quantizers/academic_quantizer.py | 170 +++ .../mmrazor/mmrazor/models/quantizers/base.py | 87 ++ .../models/quantizers/exporters/__init__.py | 5 + .../exporters/base_quantize_exporter.py | 167 +++ .../exporters/openvino_quantize_exporter.py | 159 +++ .../quantizers/exporters/optim_utils.py | 265 ++++ .../exporters/tensorrt_quantize_exporter.py | 49 + .../models/quantizers/native_quantizer.py | 446 +++++++ .../models/quantizers/openvino_quantizer.py | 86 ++ .../models/quantizers/tensorrt_quantizer.py | 84 ++ .../mmrazor/models/task_modules/__init__.py | 9 + .../models/task_modules/delivery/__init__.py | 9 + .../task_modules/delivery/delivery_manager.py | 113 ++ .../task_modules/delivery/distill_delivery.py | 66 + .../delivery/function_outputs_delivery.py | 158 +++ .../delivery/method_outputs_delivery.py | 155 +++ .../task_modules/demo_inputs/__init__.py | 15 + .../demo_inputs/default_demo_inputs.py | 108 ++ .../task_modules/demo_inputs/demo_inputs.py | 148 +++ .../demo_inputs/mmpose_demo_input.py | 119 ++ .../demo_inputs/mmseg_demo_input.py | 81 ++ .../task_modules/estimators/__init__.py | 5 + .../task_modules/estimators/base_estimator.py | 51 + .../estimators/counters/__init__.py | 6 + .../counters/flops_params_counter.py | 604 ++++++++++ .../estimators/counters/latency_counter.py | 135 +++ .../counters/op_counters/__init__.py | 25 + .../op_counters/activation_layer_counter.py | 40 + .../counters/op_counters/base_counter.py | 28 + .../op_counters/conv_layer_counter.py | 115 ++ .../op_counters/deconv_layer_counter.py | 39 + .../op_counters/group_fisher_counters.py | 7 + .../op_counters/linear_layer_counter.py | 25 + .../op_counters/norm_layer_counter.py | 91 ++ .../op_counters/pooling_layer_counter.py | 89 ++ .../op_counters/upsample_layer_counter.py | 20 + .../estimators/resource_estimator.py | 215 ++++ .../models/task_modules/predictor/__init__.py | 4 + .../predictor/handler/__init__.py | 7 + .../predictor/handler/base_handler.py | 32 + .../predictor/handler/carts_handler.py | 97 ++ .../predictor/handler/gp_handler.py | 129 ++ .../predictor/handler/mlp_handler.py | 197 +++ .../predictor/handler/rbf_handler.py | 68 ++ .../predictor/metric_predictor.py | 223 ++++ .../models/task_modules/recorder/__init__.py | 15 + .../task_modules/recorder/base_recorder.py | 116 ++ .../recorder/function_inputs_recorder.py | 71 ++ .../recorder/function_outputs_recorder.py | 162 +++ .../recorder/method_inputs_recorder.py | 83 ++ .../recorder/method_outputs_recorder.py | 167 +++ .../recorder/module_inputs_recorder.py | 27 + .../recorder/module_outputs_recorder.py | 96 ++ .../task_modules/recorder/param_recorder.py | 57 + .../task_modules/recorder/recorder_manager.py | 116 ++ .../models/task_modules/tracer/__init__.py | 17 + .../task_modules/tracer/backward_tracer.py | 201 +++ .../task_modules/tracer/channel_analyzer.py | 178 +++ .../models/task_modules/tracer/fx/__init__.py | 18 + .../task_modules/tracer/fx/custom_tracer.py | 477 ++++++++ .../task_modules/tracer/fx/graph_utils.py | 387 ++++++ .../models/task_modules/tracer/fx_tracer.py | 359 ++++++ .../tracer/loss_calculator/__init__.py | 16 + ...cascade_encoder_decoder_loss_calculator.py | 26 + .../image_classifier_loss_calculator.py | 29 + .../single_stage_detector_loss_calculator.py | 33 + .../loss_calculator/sum_loss_calculator.py | 42 + ...top_down_pose_estimator_loss_calculator.py | 25 + .../two_stage_detector_loss_calculator.py | 27 + .../models/task_modules/tracer/parsers.py | 187 +++ .../models/task_modules/tracer/path.py | 359 ++++++ .../mmrazor/mmrazor/models/utils/__init__.py | 13 + .../models/utils/expandable_utils/__init__.py | 15 + .../models/utils/expandable_utils/ops.py | 238 ++++ .../models/utils/expandable_utils/tools.py | 91 ++ .../models/utils/expandable_utils/unit.py | 31 + .../mmrazor/models/utils/make_divisible.py | 46 + .../CWD/mmrazor/mmrazor/models/utils/misc.py | 20 + .../mmrazor/models/utils/optim_wrapper.py | 29 + .../mmrazor/models/utils/parse_values.py | 18 + .../mmrazor/models/utils/quantization_util.py | 60 + .../CWD/mmrazor/mmrazor/models/utils/utils.py | 39 + .../CWD/mmrazor/mmrazor/registry/__init__.py | 15 + .../CWD/mmrazor/mmrazor/registry/registry.py | 141 +++ .../mmrazor/mmrazor/structures/__init__.py | 3 + .../mmrazor/structures/graph/__init__.py | 5 + .../mmrazor/structures/graph/base_graph.py | 233 ++++ .../mmrazor/structures/graph/channel_flow.py | 220 ++++ .../mmrazor/structures/graph/channel_graph.py | 245 ++++ .../mmrazor/structures/graph/channel_nodes.py | 533 ++++++++ .../mmrazor/structures/graph/module_graph.py | 507 ++++++++ .../structures/graph/pseudo_fx_graph.py | 105 ++ .../structures/quantization/__init__.py | 3 + .../quantization/backend_config/__init__.py | 21 + .../quantization/backend_config/academic.py | 56 + .../common_operator_config_utils.py | 639 ++++++++++ .../quantization/backend_config/mapping.py | 23 + .../quantization/backend_config/native.py | 147 +++ .../quantization/backend_config/openvino.py | 89 ++ .../quantization/backend_config/tensorrt.py | 68 ++ .../structures/quantization/qconfig.py | 200 +++ .../mmrazor/structures/subnet/__init__.py | 7 + .../mmrazor/structures/subnet/candidate.py | 184 +++ .../mmrazor/structures/subnet/fix_subnet.py | 218 ++++ .../CWD/mmrazor/mmrazor/testing/__init__.py | 3 + .../testing/_fast_stop_training_hook.py | 27 + .../CWD/mmrazor/mmrazor/testing/_fx_models.py | 44 + .../CWD/mmrazor/mmrazor/utils/__init__.py | 18 + .../CWD/mmrazor/mmrazor/utils/index_dict.py | 61 + .../CWD/mmrazor/mmrazor/utils/log_tools.py | 29 + .../CWD/mmrazor/mmrazor/utils/misc.py | 38 + .../CWD/mmrazor/mmrazor/utils/placeholder.py | 57 + .../CWD/mmrazor/mmrazor/utils/runtime_info.py | 58 + .../CWD/mmrazor/mmrazor/utils/setup_env.py | 85 ++ .../CWD/mmrazor/mmrazor/utils/typing.py | 37 + cv/distiller/CWD/mmrazor/mmrazor/version.py | 28 + .../mmrazor/mmrazor/visualization/__init__.py | 4 + .../mmrazor/visualization/local_visualizer.py | 115 ++ cv/distiller/CWD/mmrazor/model-index.yml | 31 + cv/distiller/CWD/mmrazor/requirements.txt | 3 + .../CWD/mmrazor/requirements/docs.txt | 7 + .../CWD/mmrazor/requirements/mminstall.txt | 2 + .../CWD/mmrazor/requirements/optional.txt | 4 + .../CWD/mmrazor/requirements/readthedocs.txt | 4 + .../CWD/mmrazor/requirements/runtime.txt | 2 + .../CWD/mmrazor/requirements/tests.txt | 11 + .../resources/design_and_implement.png | Bin 0 -> 126764 bytes .../CWD/mmrazor/resources/mmrazor-logo.png | Bin 0 -> 247699 bytes .../CWD/mmrazor/resources/qq_group_qrcode.jpg | Bin 0 -> 71955 bytes .../resources/xiaozhushou_weixin_qrcode.jpeg | Bin 0 -> 42538 bytes .../CWD/mmrazor/resources/zhihu_qrcode.jpg | Bin 0 -> 397245 bytes cv/distiller/CWD/mmrazor/setup.cfg | 24 + cv/distiller/CWD/mmrazor/setup.py | 192 +++ cv/distiller/CWD/mmrazor/tests/__init__.py | 1 + .../CWD/mmrazor/tests/data/MBV2_220M.yaml | 474 ++++++++ .../CWD/mmrazor/tests/data/MBV2_320M.yaml | 474 ++++++++ .../CWD/mmrazor/tests/data/MBV2_530M.yaml | 474 ++++++++ .../data/MBV2_slimmable_channel_config.json | 362 ++++++ .../tests/data/MBV2_slimmable_config.json | 377 ++++++ .../CWD/mmrazor/tests/data/__init__.py | 1 + .../CWD/mmrazor/tests/data/color.jpeg | Bin 0 -> 39779 bytes .../mmrazor/tests/data/concat_subnet1.yaml | 24 + .../mmrazor/tests/data/concat_subnet2.yaml | 24 + .../CWD/mmrazor/tests/data/dataset/a/1.JPG | 0 .../CWD/mmrazor/tests/data/dataset/ann.json | 28 + .../CWD/mmrazor/tests/data/dataset/ann.txt | 3 + .../CWD/mmrazor/tests/data/dataset/b/2.jpeg | 0 .../mmrazor/tests/data/dataset/b/subb/3.jpg | 0 .../mmrazor/tests/data/dataset/classes.txt | 2 + .../tests/data/dataset/multi_label_ann.json | 28 + .../CWD/mmrazor/tests/data/model_library.py | 693 +++++++++++ cv/distiller/CWD/mmrazor/tests/data/models.py | 1073 +++++++++++++++++ .../CWD/mmrazor/tests/data/subnet1.yaml | 24 + .../CWD/mmrazor/tests/data/subnet2.yaml | 24 + .../test_models/test_algorithm/MBV2_220M.yaml | 474 ++++++++ .../test_models/test_mutator/subnet1.json | 15 + .../test_subnet/mockmodel_subnet.yaml | 6 + .../test_task_modules/mmcls_cfg.py | 2 + .../registry_architecture_config.py | 14 + .../test_registry/registry_subnet_config.py | 17 + .../tests/data/test_registry/subnet.json | 141 +++ .../tests/data/tracer_passed_models.py | 520 ++++++++ .../CWD/mmrazor/tests/test_core/__init__.py | 1 + .../test_delivers/test_deliver_manager.py | 60 + .../test_function_outputs_deliver.py | 163 +++ .../test_method_outputs_deliver.py | 70 ++ .../test_core/test_delivers/toy_module.py | 25 + .../tests/test_core/test_graph/__init__.py | 1 + .../test_core/test_graph/test_channel_flow.py | 80 ++ .../test_graph/test_channel_graph.py | 74 ++ .../tests/test_core/test_graph/test_graph.py | 31 + .../test_graph/test_prune_tracer_model.py | 193 +++ .../test_recorders/test_base_recorder.py | 50 + .../test_func_inputs_recorder.py | 138 +++ .../test_func_outputs_recorder.py | 51 + .../test_method_inputs_recorder.py | 35 + .../test_method_outputs_recorder.py | 55 + .../test_recorders/test_module_recorders.py | 75 ++ .../test_recorders/test_param_recorder.py | 42 + .../test_recorders/test_recorder_manager.py | 58 + .../tests/test_core/test_recorders/toy_mod.py | 56 + .../tests/test_core/test_tracer/__init__.py | 1 + .../test_tracer/test_backward_tracer.py | 309 +++++ .../test_core/test_tracer/test_fx_tracer.py | 68 ++ .../test_tracer/test_loss_calculator.py | 39 + .../test_tracer/test_prune_tracer.py | 25 + cv/distiller/CWD/mmrazor/tests/test_data.py | 93 ++ .../tests/test_datasets/test_datasets.py | 88 ++ .../test_transforms/test_formatting.py | 56 + cv/distiller/CWD/mmrazor/tests/test_doc.py | 32 + .../test_hooks/test_stop_distillation_hook.py | 26 + .../test_hooks/test_visualization_hook.py | 129 ++ .../CWD/mmrazor/tests/test_impl/__init__.py | 1 + .../tests/test_impl/test_pruning/__init__.py | 1 + .../test_group_fisher/__init__.py | 1 + .../test_group_fisher/test_algorithm.py | 68 ++ .../test_prune_deploy_sub_model.py | 56 + .../test_group_fisher/test_prune_sub_model.py | 70 ++ .../test_group_fisher/test_unit.py | 44 + .../CWD/mmrazor/tests/test_models/__init__.py | 1 + .../test_models/test_algorithms/__init__.py | 1 + .../test_algorithms/test_autoformer.py | 73 ++ .../test_algorithms/test_autoslim.py | 195 +++ .../test_algorithms/test_base_algorithm.py | 124 ++ .../test_algorithms/test_bignas.py | 111 ++ .../test_models/test_algorithms/test_darts.py | 266 ++++ .../test_algorithms/test_datafree_distill.py | 221 ++++ .../test_algorithms/test_dcff_network.py | 294 +++++ .../test_models/test_algorithms/test_dmcp.py | 193 +++ .../test_models/test_algorithms/test_dsnas.py | 217 ++++ .../test_algorithms/test_general_quant.py | 34 + .../test_algorithms/test_mm_architecture.py | 225 ++++ .../test_algorithms/test_ofd_algo.py | 46 + .../test_algorithms/test_prune_algorithm.py | 264 ++++ .../test_algorithms/test_self_distill.py | 57 + .../test_single_teacher_distill.py | 77 ++ .../test_algorithms/test_slimmable_network.py | 182 +++ .../test_models/test_algorithms/test_spos.py | 85 ++ .../test_models/test_algorithms/toy_models.py | 94 ++ .../test_backbones/test_autoformerbackbone.py | 60 + .../test_backbones/test_dartsbackbone.py | 117 ++ .../test_searchable_mobilenet_v2.py | 116 ++ .../test_searchable_mobilenet_v3.py | 124 ++ .../test_searchable_shufflenet_v2.py | 160 +++ .../test_backbones/utils.py | 21 + .../test_connectors/test_connectors.py | 169 +++ .../test_dynamic_op/__init__.py | 1 + .../test_dynamic_op/test_bricks/__init__.py | 1 + .../test_bricks/test_dynamic_attention.py | 50 + .../test_bricks/test_dynamic_container.py | 46 + .../test_bricks/test_dynamic_conv.py | 314 +++++ .../test_bricks/test_dynamic_embed.py | 64 + .../test_bricks/test_dynamic_layernorm.py | 45 + .../test_bricks/test_dynamic_linear.py | 113 ++ .../test_bricks/test_dynamic_norm.py | 154 +++ .../test_dynamic_relative_position.py | 55 + .../test_bricks/test_dynamic_resizer.py | 81 ++ .../test_dynamic_op/utils.py | 20 + .../test_generators/test_generators.py | 73 ++ .../test_classifier/test_imageclassifier.py | 45 + .../test_distillers/test_byot_distill.py | 69 ++ .../test_configurable_distill.py | 115 ++ .../test_fake_quants/test_lsq_fake_quants.py | 208 ++++ .../test_torch_fake_quants.py | 18 + .../test_losses/test_distillation_losses.py | 213 ++++ .../test_losses/test_general_losses.py | 52 + .../test_models/test_mutables/__init__.py | 1 + .../test_mutables/test_derived_mutable.py | 318 +++++ .../test_mutables/test_diffchoiceroute.py | 87 ++ .../test_models/test_mutables/test_diffop.py | 200 +++ .../test_mutables/test_gumbelchoiceroute.py | 90 ++ .../test_mutable_channel/__init__.py | 1 + .../test_mutable_channels.py | 33 + .../test_sequential_mutable_channel.py | 57 + .../test_units/__init__.py | 1 + .../test_units/test_dcff_channel_unit.py | 77 ++ .../test_l1_mutable_channel_unit.py | 28 + .../test_units/test_mutable_channel_units.py | 140 +++ .../test_one_shot_mutable_channel_unit.py | 33 + .../test_sequential_mutable_channel_unit.py | 41 + .../test_mutables/test_mutable_value.py | 119 ++ .../test_mutables/test_onehotop.py | 200 +++ .../test_mutables/test_oneshotop.py | 241 ++++ .../test_sequential_mutable_channel.py | 14 + .../test_models/test_mutators/__init__.py | 1 + .../test_mutators/test_channel_mutator.py | 180 +++ .../test_mutators/test_dcff_mutator.py | 101 ++ .../test_mutators/test_dmcp_mutator.py | 40 + .../test_mutators/test_nas_mutator.py | 196 +++ .../test_observers/test_lsq_observer.py | 77 ++ .../test_observers/test_torch_observers.py | 18 + .../test_academic_quantizer.py | 167 +++ .../test_quantizers/test_exporter.py | 348 ++++++ .../test_quantizers/test_native_quantizer.py | 224 ++++ .../test_openvino_quantizer.py | 55 + .../test_tensorrt_quantizer.py | 51 + .../test_models/test_subnet/test_candidate.py | 152 +++ .../test_subnet/test_fix_subnet.py | 150 +++ .../test_models/test_task_modules/__init__.py | 1 + .../test_task_modules/test_custom_tracer.py | 184 +++ .../test_demo_inputs/__init__.py | 1 + .../test_demo_inputs/test_demo_inputs.py | 24 + .../test_estimators/test_flops_params.py | 236 ++++ .../test_task_modules/test_graph_utils.py | 536 ++++++++ .../test_predictors/test_metric_predictor.py | 196 +++ .../tests/test_models/test_utils/__init__.py | 1 + .../test_expandable_utils/__init__.py | 1 + .../test_expandable_utils/test_expand.py | 64 + .../tests/test_registry/test_registry.py | 144 +++ .../test_autoslim_greedy_search_loop.py | 187 +++ .../tests/test_runners/test_darts_loop.py | 258 ++++ .../test_runners/test_distill_val_loop.py | 180 +++ .../test_evolution_search_loop.py | 392 ++++++ .../test_runners/test_quantization_loop.py | 413 +++++++ .../test_runners/test_subnet_sampler_loop.py | 207 ++++ .../test_utils/test_calibrate_bn_mixin.py | 83 ++ .../test_runners/test_utils/test_check.py | 44 + .../test_runners/test_utils/test_genetic.py | 15 + .../test_structures/test_backendconfig.py | 62 + .../tests/test_structures/test_qconfig.py | 172 +++ .../CWD/mmrazor/tests/test_tools/__init__.py | 1 + .../mmrazor/tests/test_tools/test_tools.py | 101 ++ .../tests/test_utils/test_index_dict.py | 16 + .../tests/test_utils/test_placeholder.py | 18 + .../tests/test_visualizer/test_visualizer.py | 128 ++ .../CWD/mmrazor/tests/utils/__init__.py | 4 + .../CWD/mmrazor/tests/utils/set_dist_env.py | 31 + .../mmrazor/tests/utils/set_torch_thread.py | 17 + .../tools/dataset_converters/cityscapes.py | 56 + cv/distiller/CWD/mmrazor/tools/dist_test.sh | 22 + cv/distiller/CWD/mmrazor/tools/dist_train.sh | 19 + .../CWD/mmrazor/tools/misc/print_config.py | 51 + .../convert_attentivenas_nas_ckpt.py | 170 +++ .../convert_bignas_gml_ckpt.py | 56 + .../tools/model_converters/convert_kd_ckpt.py | 47 + .../convert_kd_ckpt_to_student.py | 48 + .../model_converters/convert_ofa_ckpt.py | 110 ++ .../model_converters/convert_quant_ckpt.py | 53 + .../convert_supernet2subnet.py | 60 + .../tools/model_converters/publish_model.py | 91 ++ .../tools/pruning/get_channel_units.py | 84 ++ .../CWD/mmrazor/tools/pruning/get_flops.py | 55 + .../tools/pruning/get_l1_prune_config.py | 127 ++ .../get_static_model_from_algorithm.py | 82 ++ cv/distiller/CWD/mmrazor/tools/ptq.py | 73 ++ cv/distiller/CWD/mmrazor/tools/slurm_test.sh | 10 + cv/distiller/CWD/mmrazor/tools/slurm_train.sh | 24 + cv/distiller/CWD/mmrazor/tools/test.py | 80 ++ cv/distiller/CWD/mmrazor/tools/train.py | 121 ++ .../CWD/mmrazor/tools/visualizations/demo.jpg | Bin 0 -> 259865 bytes .../feature_diff_visualization.py | 169 +++ .../visualizations/feature_visualization.py | 155 +++ .../backbone_feature_diff_visualization.py | 18 + .../backbone_feature_visualization.py | 8 + .../fpn_feature_diff_visualization.py | 18 + .../vis_configs/fpn_feature_visualization.py | 8 + .../tools/visualizations/vis_scheduler.py | 262 ++++ 802 files changed, 76303 insertions(+) create mode 100755 cv/distiller/CWD/mmrazor/.circleci/config.yml create mode 100755 cv/distiller/CWD/mmrazor/.circleci/docker/Dockerfile create mode 100755 cv/distiller/CWD/mmrazor/.circleci/test.yml create mode 100755 cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_summary_analyse.py create mode 100755 cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_test.py create mode 100755 cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_train.py create mode 100755 cv/distiller/CWD/mmrazor/.dev_scripts/meta_files_test.py create mode 100755 cv/distiller/CWD/mmrazor/.pre-commit-config.yaml create mode 100755 cv/distiller/CWD/mmrazor/.readthedocs.yml create mode 100755 cv/distiller/CWD/mmrazor/LICENSE create mode 100755 cv/distiller/CWD/mmrazor/MANIFEST.in create mode 100755 cv/distiller/CWD/mmrazor/README.md create mode 100755 cv/distiller/CWD/mmrazor/README_zh-CN.md create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/cifar100_bs16_auto_aug.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/pipelines/auto_aug_cifar.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/attentive_mobilenetv3_supernet.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/darts_supernet.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/dsnas_shufflenet_supernet.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/ofa_mobilenetv3_supernet.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_mobilenet_supernet.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_shufflenet_supernet.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_subnet.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_supernet.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_dsnas.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_spos.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_AdamW.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim_pil.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_bignas.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_dmcp.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_ofa.py create mode 100755 cv/distiller/CWD/mmrazor/configs/_base_/vanilla_models/wrn16_2_cifar10.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/byot_resnet18_8xb16_cifar100.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/crd_neck_r50_r18_8xb16_cifar10.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/datasets/crd_cifar10_bs16.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/dafl_logits_resnet34_resnet18_8xb256_cifar10.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/deit-base_regnety160_pt-16xb64_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/dfad_logits_resnet34_resnet18_8xb32_cifar10.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/dkd_resnet34_resnet18_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet34_resnet18_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/wsld_logits_resnet34_resnet18_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco_visualization.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/fbkd_fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/mgd_fpn_retina_x101_retina_r50_2x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_fcos_x101_retina_r50_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_retina_x101_retina_r50_2x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py create mode 100755 cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_search_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_subnet_8xb256_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_supernet_32xb256_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_search_8xb256_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_supernet_8xb256_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A1.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A2.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A3.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A4.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A5.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A6.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_search_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_supernet_32xb64_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0_mmrazor.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_supernet_unroll_1xb96_cifar10.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_subnet_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_supernet_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT22.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT31.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_search_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_subnet_8xb256_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_supernet_32xb64_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/SPOS_SUBNET.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/faster-rcnn_nas_backbone_fpn_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_search_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_subnet_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_supernet_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_predictor_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_subnet_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_supernet_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/DETNAS_SUBNET.yaml create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_search_coco_1x.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_subnet_coco_1x.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_supernet_coco_1x.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_retina_shufflenet_supernet_coco_1x.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_subnet_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_supernet_8xb128_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_deploy_template.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_finetune_template.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_prune_template.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_compact_resnet_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_resnet_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/fix_subnet.json create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_MBV2_100M.json create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_R50_2G.json create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_supernet_32xb64.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_supernet_32xb64.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_deploy_mobilenet-v2_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_deploy_mobilenet-v2_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/script.sh create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_deploy_resnet50_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_prune_resnet50_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_deploy_resnet50_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_prune_resnet50_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/script.sh create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a_deploy.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b_deploy.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c_deploy.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/script.sh create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_compact_faster_rcnn_resnet50_8xb4_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_fpn.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/fix_subnet.json create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_deploy_retinanet_r50_fpn_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_deploy_retinanet_r50_fpn_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/script.sh create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_compact_topdown_heatmap_resnet50_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/fix_subnet.json create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_aic-coco-256x192.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_coco-256x192.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/script.sh create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_compact_pointrend_resnet50_8xb2_cityscapes.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/fix_subnet.json create mode 100755 cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/pointrend_resnet50.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_openvino_dynamic-800x1344.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_tensorrt-int8-explicit_dynamic-320x320-1344x1344.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_retina_r50_1x_coco_calib32xb32.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/qat/base/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/qat/base/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/qat/base/qat_openvino_resnet18_10e_8xb32_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_100e_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_10e_in1k.py create mode 100755 cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/metafile.yml create mode 100755 cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/README.md create mode 100755 cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py create mode 100755 cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn22-w4_b16x8_cifar10.py create mode 100755 cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py create mode 100755 cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn40-w2_b16x8_cifar10.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/datasets/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/datasets/crd_dataset_wrapper.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augment.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augmentv2.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/formatting.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dmcp_subnet_hook.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dump_subnet_hook.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/estimate_resources_hook.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/group_fisher_hooks.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/stop_distillation_hook.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/visualization_hook.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/optimizer_constructor.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/autoslim_greedy_search_loop.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/darts_loop.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/distill_val_loop.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/evolution_search_loop.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/iteprune_val_loop.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/quantization_loops.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/slimmable_val_loop.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_sampler_loop.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_val_loop.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/calibrate_bn_mixin.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/check.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/genetic.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/implementations/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/algorithm.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/counters.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/hook.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/mutator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/ops.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_deploy_sub_model.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_sub_model.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/unit.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/base.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/datafree_distillation.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/fpn_teacher_distill.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/overhaul_feature_distillation.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/self_distill.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/single_teacher_distill.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoformer.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoslim.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/bignas.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/darts.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/dsnas.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/spos.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dcff.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dmcp.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/group_fisher_algoritho.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/ite_prune_algorithm.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/slimmable_network.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/mm_architecture.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/darts_backbone.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_autoformer.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v2.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v3.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_shufflenet_v2.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/wideresnet.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/image.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/base_connector.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/byot_connector.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/convmodule_connector.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/crd_connector.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/factor_transfer_connectors.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/fbkd_connector.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/mgd_connector.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/norm_connector.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/ofd_connector.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/torch_connector.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_container.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_conv.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_embed.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_function.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_linear.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_multi_head_attention.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_norm.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_relative_position.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/group_fisher_ops.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/dynamic_linear_head.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_conv_mixins.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_layernorm_mixins.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_mixins.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/base_generator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/dafl_generator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/zskt_generator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/darts_subnet_head.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/deit_head.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/squeezemean_with_dropout.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/base.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/common.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/darts_series.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/efficientnet_series.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/function.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/gather_tensors.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/mobilenet_series.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/shufflenet_series.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/transformer_series.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/mutable_register.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/set_dropout.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/distillers/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/distillers/base_distiller.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/distillers/byot_distiller.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/distillers/configurable_distiller.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/distillers/ofd_distiller.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/base.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/lsq.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/torch_fake_quants.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/ab_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/at_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/crd_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/cross_entropy_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/cwd.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/dafl_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/decoupled_kd.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/dist_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/factor_transfer_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/fbkd_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/kd_soft_ce_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/kl_divergence.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/l1_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/l2_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/mgd_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/ofd_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/pkd_loss.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/relational_kd.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/losses/weighted_soft_label_distillation.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/base_mutable.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/derived_mutable.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/MutableChannel.md create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/base_mutable_channel.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/mutable_channel_container.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/oneshot_mutable_channel.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/sequential_mutable_channel.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/simple_mutable_channel.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dcff_channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dmcp_channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/group_fisher_unit.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/l1_mutable_channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.ipynb create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/one_shot_mutable_channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/sequential_mutable_channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/slimmable_channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/utils.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/diff_mutable_module.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/mutable_module.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/one_shot_mutable_module.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/mutable_value.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/base_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.ipynb create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dcff_channel_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dmcp_channel_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/group_fisher_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/one_shot_channel_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/slimmable_channel_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/group_mixin.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/mutators/nas_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/observers/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/observers/base.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/observers/lsq.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/observers/torch_observers.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/academic_quantizer.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/base.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/base_quantize_exporter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/openvino_quantize_exporter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/optim_utils.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/tensorrt_quantize_exporter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/native_quantizer.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/openvino_quantizer.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/tensorrt_quantizer.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/delivery_manager.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/distill_delivery.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/function_outputs_delivery.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/method_outputs_delivery.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/default_demo_inputs.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/demo_inputs.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmpose_demo_input.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmseg_demo_input.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/base_estimator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/flops_params_counter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/latency_counter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/activation_layer_counter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/base_counter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/conv_layer_counter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/deconv_layer_counter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/group_fisher_counters.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/linear_layer_counter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/norm_layer_counter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/pooling_layer_counter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/upsample_layer_counter.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/resource_estimator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/base_handler.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/carts_handler.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/gp_handler.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/mlp_handler.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/rbf_handler.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/metric_predictor.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/base_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_inputs_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_outputs_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_inputs_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_outputs_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_inputs_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_outputs_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/param_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/recorder_manager.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/backward_tracer.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/channel_analyzer.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/custom_tracer.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/graph_utils.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx_tracer.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/cascade_encoder_decoder_loss_calculator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/image_classifier_loss_calculator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/single_stage_detector_loss_calculator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/sum_loss_calculator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/top_down_pose_estimator_loss_calculator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/two_stage_detector_loss_calculator.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/parsers.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/path.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/utils/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/ops.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/tools.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/unit.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/utils/make_divisible.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/utils/misc.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/utils/optim_wrapper.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/utils/parse_values.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/utils/quantization_util.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/models/utils/utils.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/registry/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/registry/registry.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/graph/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/graph/base_graph.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_flow.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_graph.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_nodes.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/graph/module_graph.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/graph/pseudo_fx_graph.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/academic.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/common_operator_config_utils.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/mapping.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/native.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/openvino.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/tensorrt.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/qconfig.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/candidate.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/fix_subnet.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/testing/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/testing/_fast_stop_training_hook.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/testing/_fx_models.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/utils/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/utils/index_dict.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/utils/log_tools.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/utils/misc.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/utils/placeholder.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/utils/runtime_info.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/utils/setup_env.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/utils/typing.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/version.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/visualization/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/mmrazor/visualization/local_visualizer.py create mode 100755 cv/distiller/CWD/mmrazor/model-index.yml create mode 100755 cv/distiller/CWD/mmrazor/requirements.txt create mode 100755 cv/distiller/CWD/mmrazor/requirements/docs.txt create mode 100755 cv/distiller/CWD/mmrazor/requirements/mminstall.txt create mode 100755 cv/distiller/CWD/mmrazor/requirements/optional.txt create mode 100755 cv/distiller/CWD/mmrazor/requirements/readthedocs.txt create mode 100755 cv/distiller/CWD/mmrazor/requirements/runtime.txt create mode 100755 cv/distiller/CWD/mmrazor/requirements/tests.txt create mode 100755 cv/distiller/CWD/mmrazor/resources/design_and_implement.png create mode 100755 cv/distiller/CWD/mmrazor/resources/mmrazor-logo.png create mode 100755 cv/distiller/CWD/mmrazor/resources/qq_group_qrcode.jpg create mode 100755 cv/distiller/CWD/mmrazor/resources/xiaozhushou_weixin_qrcode.jpeg create mode 100755 cv/distiller/CWD/mmrazor/resources/zhihu_qrcode.jpg create mode 100755 cv/distiller/CWD/mmrazor/setup.cfg create mode 100755 cv/distiller/CWD/mmrazor/setup.py create mode 100755 cv/distiller/CWD/mmrazor/tests/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/data/MBV2_220M.yaml create mode 100755 cv/distiller/CWD/mmrazor/tests/data/MBV2_320M.yaml create mode 100755 cv/distiller/CWD/mmrazor/tests/data/MBV2_530M.yaml create mode 100755 cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_channel_config.json create mode 100755 cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_config.json create mode 100755 cv/distiller/CWD/mmrazor/tests/data/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/data/color.jpeg create mode 100755 cv/distiller/CWD/mmrazor/tests/data/concat_subnet1.yaml create mode 100755 cv/distiller/CWD/mmrazor/tests/data/concat_subnet2.yaml create mode 100755 cv/distiller/CWD/mmrazor/tests/data/dataset/a/1.JPG create mode 100755 cv/distiller/CWD/mmrazor/tests/data/dataset/ann.json create mode 100755 cv/distiller/CWD/mmrazor/tests/data/dataset/ann.txt create mode 100755 cv/distiller/CWD/mmrazor/tests/data/dataset/b/2.jpeg create mode 100755 cv/distiller/CWD/mmrazor/tests/data/dataset/b/subb/3.jpg create mode 100755 cv/distiller/CWD/mmrazor/tests/data/dataset/classes.txt create mode 100755 cv/distiller/CWD/mmrazor/tests/data/dataset/multi_label_ann.json create mode 100755 cv/distiller/CWD/mmrazor/tests/data/model_library.py create mode 100755 cv/distiller/CWD/mmrazor/tests/data/models.py create mode 100755 cv/distiller/CWD/mmrazor/tests/data/subnet1.yaml create mode 100755 cv/distiller/CWD/mmrazor/tests/data/subnet2.yaml create mode 100755 cv/distiller/CWD/mmrazor/tests/data/test_models/test_algorithm/MBV2_220M.yaml create mode 100755 cv/distiller/CWD/mmrazor/tests/data/test_models/test_mutator/subnet1.json create mode 100755 cv/distiller/CWD/mmrazor/tests/data/test_models/test_subnet/mockmodel_subnet.yaml create mode 100755 cv/distiller/CWD/mmrazor/tests/data/test_models/test_task_modules/mmcls_cfg.py create mode 100755 cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_architecture_config.py create mode 100755 cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_subnet_config.py create mode 100755 cv/distiller/CWD/mmrazor/tests/data/test_registry/subnet.json create mode 100755 cv/distiller/CWD/mmrazor/tests/data/tracer_passed_models.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_deliver_manager.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_function_outputs_deliver.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_method_outputs_deliver.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/toy_module.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_graph/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_flow.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_graph.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_graph.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_prune_tracer_model.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_base_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_inputs_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_outputs_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_inputs_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_outputs_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_module_recorders.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_param_recorder.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_recorder_manager.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/toy_mod.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_backward_tracer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_fx_tracer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_loss_calculator.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_prune_tracer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_data.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_datasets/test_datasets.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_datasets/test_transforms/test_formatting.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_doc.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_stop_distillation_hook.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_visualization_hook.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_impl/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_algorithm.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_deploy_sub_model.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_sub_model.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_unit.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoformer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoslim.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_base_algorithm.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_bignas.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_darts.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_datafree_distill.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dcff_network.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dmcp.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dsnas.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_general_quant.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_mm_architecture.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_ofd_algo.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_prune_algorithm.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_self_distill.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_single_teacher_distill.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_slimmable_network.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_spos.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/toy_models.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_autoformerbackbone.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_dartsbackbone.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v2.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v3.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_shufflenet_v2.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/utils.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_connectors/test_connectors.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_attention.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_container.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_conv.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_embed.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_layernorm.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_linear.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_norm.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_relative_position.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_resizer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/utils.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_generators/test_generators.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_classifier/test_imageclassifier.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_byot_distill.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_configurable_distill.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_lsq_fake_quants.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_torch_fake_quants.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_distillation_losses.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_general_losses.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_derived_mutable.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffchoiceroute.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffop.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_gumbelchoiceroute.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_mutable_channels.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_sequential_mutable_channel.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_dcff_channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_l1_mutable_channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_mutable_channel_units.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_one_shot_mutable_channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_sequential_mutable_channel_unit.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_value.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_onehotop.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_oneshotop.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_sequential_mutable_channel.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_channel_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dcff_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dmcp_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_nas_mutator.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_lsq_observer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_torch_observers.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_academic_quantizer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_exporter.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_native_quantizer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_openvino_quantizer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_tensorrt_quantizer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_candidate.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_fix_subnet.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_custom_tracer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/test_demo_inputs.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_estimators/test_flops_params.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_graph_utils.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_predictors/test_metric_predictor.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_utils/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/test_expand.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_registry/test_registry.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_runners/test_autoslim_greedy_search_loop.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_runners/test_darts_loop.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_runners/test_distill_val_loop.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_runners/test_evolution_search_loop.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_runners/test_quantization_loop.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_runners/test_subnet_sampler_loop.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_calibrate_bn_mixin.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_check.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_genetic.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_structures/test_backendconfig.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_structures/test_qconfig.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_tools/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_tools/test_tools.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_utils/test_index_dict.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_utils/test_placeholder.py create mode 100755 cv/distiller/CWD/mmrazor/tests/test_visualizer/test_visualizer.py create mode 100755 cv/distiller/CWD/mmrazor/tests/utils/__init__.py create mode 100755 cv/distiller/CWD/mmrazor/tests/utils/set_dist_env.py create mode 100755 cv/distiller/CWD/mmrazor/tests/utils/set_torch_thread.py create mode 100755 cv/distiller/CWD/mmrazor/tools/dataset_converters/cityscapes.py create mode 100755 cv/distiller/CWD/mmrazor/tools/dist_test.sh create mode 100755 cv/distiller/CWD/mmrazor/tools/dist_train.sh create mode 100755 cv/distiller/CWD/mmrazor/tools/misc/print_config.py create mode 100755 cv/distiller/CWD/mmrazor/tools/model_converters/convert_attentivenas_nas_ckpt.py create mode 100755 cv/distiller/CWD/mmrazor/tools/model_converters/convert_bignas_gml_ckpt.py create mode 100755 cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt.py create mode 100755 cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt_to_student.py create mode 100755 cv/distiller/CWD/mmrazor/tools/model_converters/convert_ofa_ckpt.py create mode 100755 cv/distiller/CWD/mmrazor/tools/model_converters/convert_quant_ckpt.py create mode 100755 cv/distiller/CWD/mmrazor/tools/model_converters/convert_supernet2subnet.py create mode 100755 cv/distiller/CWD/mmrazor/tools/model_converters/publish_model.py create mode 100755 cv/distiller/CWD/mmrazor/tools/pruning/get_channel_units.py create mode 100755 cv/distiller/CWD/mmrazor/tools/pruning/get_flops.py create mode 100755 cv/distiller/CWD/mmrazor/tools/pruning/get_l1_prune_config.py create mode 100755 cv/distiller/CWD/mmrazor/tools/pruning/get_static_model_from_algorithm.py create mode 100755 cv/distiller/CWD/mmrazor/tools/ptq.py create mode 100755 cv/distiller/CWD/mmrazor/tools/slurm_test.sh create mode 100755 cv/distiller/CWD/mmrazor/tools/slurm_train.sh create mode 100755 cv/distiller/CWD/mmrazor/tools/test.py create mode 100755 cv/distiller/CWD/mmrazor/tools/train.py create mode 100755 cv/distiller/CWD/mmrazor/tools/visualizations/demo.jpg create mode 100755 cv/distiller/CWD/mmrazor/tools/visualizations/feature_diff_visualization.py create mode 100755 cv/distiller/CWD/mmrazor/tools/visualizations/feature_visualization.py create mode 100755 cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_diff_visualization.py create mode 100755 cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_visualization.py create mode 100755 cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_diff_visualization.py create mode 100755 cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_visualization.py create mode 100755 cv/distiller/CWD/mmrazor/tools/visualizations/vis_scheduler.py diff --git a/cv/distiller/CWD/mmrazor/.circleci/config.yml b/cv/distiller/CWD/mmrazor/.circleci/config.yml new file mode 100755 index 000000000..27e235306 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/.circleci/config.yml @@ -0,0 +1,34 @@ +version: 2.1 + +# this allows you to use CircleCI's dynamic configuration feature +setup: true + +# the path-filtering orb is required to continue a pipeline based on +# the path of an updated fileset +orbs: + path-filtering: circleci/path-filtering@0.1.2 + +workflows: + # the always-run workflow is always triggered, regardless of the pipeline parameters. + always-run: + jobs: + # the path-filtering/filter job determines which pipeline + # parameters to update. + - path-filtering/filter: + name: check-updated-files + # 3-column, whitespace-delimited mapping. One mapping per + # line: + # + mapping: | + mmrazor/.* lint_only false + requirements/.* lint_only false + tests/.* lint_only false + tools/.* lint_only false + configs/.* lint_only false + .circleci/.* lint_only false + base-revision: main + # this is the path of the configuration we should trigger once + # path filtering and pipeline parameter value updates are + # complete. In this case, we are using the parent dynamic + # configuration itself. + config-path: .circleci/test.yml diff --git a/cv/distiller/CWD/mmrazor/.circleci/docker/Dockerfile b/cv/distiller/CWD/mmrazor/.circleci/docker/Dockerfile new file mode 100755 index 000000000..d9cf8cc77 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/.circleci/docker/Dockerfile @@ -0,0 +1,11 @@ +ARG PYTORCH="1.8.1" +ARG CUDA="10.2" +ARG CUDNN="7" + +FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-devel + +# To fix GPG key error when running apt-get update +RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub +RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/7fa2af80.pub + +RUN apt-get update && apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx diff --git a/cv/distiller/CWD/mmrazor/.circleci/test.yml b/cv/distiller/CWD/mmrazor/.circleci/test.yml new file mode 100755 index 000000000..9acc7fdfc --- /dev/null +++ b/cv/distiller/CWD/mmrazor/.circleci/test.yml @@ -0,0 +1,193 @@ +version: 2.1 + +# the default pipeline parameters, which will be updated according to +# the results of the path-filtering orb +parameters: + lint_only: + type: boolean + default: true + +jobs: + lint: + docker: + - image: cimg/python:3.7.4 + steps: + - checkout + - run: + name: Install pre-commit hook + command: | + pip install pre-commit + pre-commit install + - run: + name: Linting + command: pre-commit run --all-files + - run: + name: Check docstring coverage + command: | + pip install interrogate + interrogate -v --ignore-init-method --ignore-module --ignore-nested-functions --ignore-magic --ignore-regex "__repr__" --fail-under 80 mmrazor + build_cpu: + parameters: + # The python version must match available image tags in + # https://circleci.com/developer/images/image/cimg/python + python: + type: string + torch: + type: string + torchvision: + type: string + docker: + - image: cimg/python:<< parameters.python >> + resource_class: large + steps: + - checkout + - run: + name: Install Libraries + command: | + sudo apt-get update + sudo apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx libjpeg-dev zlib1g-dev libtinfo-dev libncurses5 + - run: + name: Configure Python & pip + command: | + pip install --upgrade pip + pip install wheel + - run: + name: Install PyTorch + command: | + python -V + pip install torch==<< parameters.torch >>+cpu torchvision==<< parameters.torchvision >>+cpu -f https://download.pytorch.org/whl/torch_stable.html + - when: + condition: + equal: ["3.9.0", << parameters.python >>] + steps: + - run: pip install "protobuf <= 3.20.1" && sudo apt-get update && sudo apt-get -y install libprotobuf-dev protobuf-compiler cmake + - run: + name: Install mmrazor dependencies + command: | + pip install git+https://github.com/open-mmlab/mmengine.git@main + pip install -U openmim + mim install 'mmcv >= 2.0.0rc1' + pip install git+https://github.com/open-mmlab/mmpretrain.git@mmcls-1.x + pip install git+https://github.com/open-mmlab/mmdetection.git@main + pip install git+https://github.com/open-mmlab/mmsegmentation.git@main + python -m pip install git+ssh://git@github.com/open-mmlab/mmpose.git@main + pip install -r requirements.txt + - run: + name: Build and install + command: | + pip install -e . + - run: + name: Run unittests + command: | + coverage run --branch --source mmrazor -m pytest tests/ + coverage xml + coverage report -m + build_cuda: + parameters: + torch: + type: string + cuda: + type: enum + enum: ["10.1", "10.2", "11.1"] + cudnn: + type: integer + default: 7 + machine: + image: ubuntu-2004-cuda-11.4:202110-01 + # docker_layer_caching: true + resource_class: gpu.nvidia.small + steps: + - checkout + - run: + # Cloning repos in VM since Docker doesn't have access to the private key + name: Clone Repos + command: | + git clone -b main --depth 1 https://github.com/open-mmlab/mmengine.git /home/circleci/mmengine + git clone -b main --depth 1 https://github.com/open-mmlab/mmdetection.git /home/circleci/mmdetection + git clone -b 1.x --depth 1 https://github.com/open-mmlab/mmclassification.git /home/circleci/mmclassification + git clone -b main --depth 1 https://github.com/open-mmlab/mmsegmentation.git /home/circleci/mmsegmentation + - run: + name: Build Docker image + command: | + docker build .circleci/docker -t mmrazor:gpu --build-arg PYTORCH=<< parameters.torch >> --build-arg CUDA=<< parameters.cuda >> --build-arg CUDNN=<< parameters.cudnn >> + docker run --gpus all -t -d -v /home/circleci/project:/mmrazor -v /home/circleci/mmengine:/mmengine -v /home/circleci/mmdetection:/mmdetection -v /home/circleci/mmclassification:/mmclassification -v /home/circleci/mmsegmentation:/mmsegmentation -w /mmrazor --name mmrazor mmrazor:gpu + - run: + name: Install mmrazor dependencies + command: | + docker exec mmrazor pip install -e /mmengine + docker exec mmrazor pip install -U openmim + docker exec mmrazor mim install 'mmcv >= 2.0.0rc1' + docker exec mmrazor pip install -e /mmdetection + docker exec mmrazor pip install -e /mmclassification + docker exec mmrazor pip install -e /mmsegmentation + docker exec mmrazor pip install -r requirements.txt + - run: + name: Build and install + command: | + docker exec mmrazor pip install -e . + - run: + name: Run unittests + command: | + docker exec mmrazor pytest tests/ + +workflows: + pr_stage_lint: + when: << pipeline.parameters.lint_only >> + jobs: + - lint: + name: lint + filters: + branches: + ignore: + - main + - 1.x + pr_stage_test: + when: + not: << pipeline.parameters.lint_only >> + jobs: + - lint: + name: lint + filters: + branches: + ignore: + - main + - build_cpu: + name: minimum_version_cpu + torch: 1.8.1 + torchvision: 0.9.1 + python: 3.7.4 + requires: + - lint + - build_cpu: + name: maximum_version_cpu + torch: 1.13.1 + torchvision: 0.14.1 + python: 3.9.0 + requires: + - lint + - hold: + type: approval + requires: + - maximum_version_cpu + - build_cuda: + name: mainstream_version_gpu + torch: 1.8.1 + # Use double quotation mark to explicitly specify its type + # as string instead of number + cuda: "10.2" + requires: + - hold + merge_stage_test: + when: + not: << pipeline.parameters.lint_only >> + jobs: + - build_cuda: + name: minimum_version_gpu + torch: 1.8.1 + # Use double quotation mark to explicitly specify its type + # as string instead of number + cuda: "10.2" + filters: + branches: + only: + - main diff --git a/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_summary_analyse.py b/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_summary_analyse.py new file mode 100755 index 000000000..372e1326c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_summary_analyse.py @@ -0,0 +1,67 @@ +import argparse +import os + +import mmengine + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Analyse summary.yml generated by benchmark test') + parser.add_argument('file_path', help='Summary.yml path') + args = parser.parse_args() + return args + + +metric_mapping = { + 'Top 1 Accuracy': 'accuracy/top1', + 'Top 5 Accuracy': 'accuracy/top5', + 'box AP': 'coco/bbox_mAP', + 'mIoU': 'mIoU' +} + + +def compare_metric(result, metric): + expect_val = result['expect'][metric] + actual_val = result['actual'].get(metric_mapping[metric], None) + if actual_val is None: + return None, None + if metric == 'box AP': + actual_val *= 100 + decimal_bit = len(str(expect_val).split('.')[-1]) + actual_val = round(actual_val, decimal_bit) + error = round(actual_val - expect_val, decimal_bit) + error_percent = round(abs(error) * 100 / expect_val, 3) + return error, error_percent + + +def main(): + args = parse_args() + file_path = args.file_path + results = mmengine.load(file_path, 'yml') + miss_models = dict() + sort_by_error = dict() + for k, v in results.items(): + valid_keys = v['expect'].keys() + compare_res = dict() + for m in valid_keys: + error, error_percent = compare_metric(v, m) + if error is None: + continue + compare_res[m] = {'error': error, 'error_percent': error_percent} + if error != 0: + miss_models[k] = compare_res + sort_by_error[k] = error + sort_by_error = sorted( + sort_by_error.items(), key=lambda x: abs(x[1]), reverse=True) + miss_models_sort = dict() + miss_models_sort['total error models'] = len(sort_by_error) + for k_v in sort_by_error: + index = k_v[0] + miss_models_sort[index] = miss_models[index] + save_path = os.path.join(os.path.dirname(file_path), 'summary_error.yml') + mmengine.fileio.dump(miss_models_sort, save_path, sort_keys=False) + print(f'Summary analysis result saved in {save_path}') + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_test.py b/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_test.py new file mode 100755 index 000000000..1af3e4fa4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_test.py @@ -0,0 +1,307 @@ +import argparse +import os +import os.path as osp +import re +from collections import OrderedDict +from pathlib import Path + +import mmengine +import wget +from modelindex.load_model_index import load +from rich.console import Console +from rich.syntax import Syntax +from rich.table import Table + +console = Console() +MMRAZOR_ROOT = Path(__file__).absolute().parents[1] + +METRIC_MAPPINGS = { + 'accuracy/top1': 'Top 1 Accuracy', + 'accuracy/top5': 'Top 5 Accuracy' +} + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Test all models' accuracy in model-index.yml") + parser.add_argument('checkpoint_root', help='Checkpoint file root path.') + parser.add_argument( + '--partition', type=str, help='Cluster partition to use.') + parser.add_argument( + '--job-name', + type=str, + default='razor-test-benchmark', + help='Slurm job name prefix') + parser.add_argument('--port', type=int, default=29666, help='dist port') + parser.add_argument( + '--models', nargs='+', type=str, help='Specify model names to run.') + parser.add_argument('--gpus', type=int, default=8, help='num gpus') + parser.add_argument( + '--work-dir', + default='work_dirs/benchmark_test', + help='the dir to save metric') + parser.add_argument( + '--replace-ceph', action='store_true', help='load data from ceph') + parser.add_argument( + '--run', action='store_true', help='run script directly') + parser.add_argument( + '--summary', action='store_true', help='collect results') + parser.add_argument( + '--local', + action='store_true', + help='run at local instead of cluster.') + parser.add_argument( + '--mail', type=str, help='Mail address to watch test status.') + parser.add_argument( + '--mail-type', + nargs='+', + default=['BEGIN'], + choices=['NONE', 'BEGIN', 'END', 'FAIL', 'REQUEUE', 'ALL'], + help='Mail address to watch test status.') + parser.add_argument( + '--quotatype', + default=None, + choices=['reserved', 'auto', 'spot'], + help='Quota type, only available for phoenix-slurm>=0.2') + + args = parser.parse_args() + return args + + +def replace_to_ceph(cfg): + + file_client_args = dict( + backend='petrel', + path_mapping=dict({ + './data/coco': + 's3://openmmlab/datasets/detection/coco', + 'data/coco': + 's3://openmmlab/datasets/detection/coco', + './data/cityscapes': + 's3://openmmlab/datasets/segmentation/cityscapes', + 'data/cityscapes': + 's3://openmmlab/datasets/segmentation/cityscapes', + './data/imagenet': + 's3://openmmlab/datasets/classification/imagenet', + 'data/imagenet': + 's3://openmmlab/datasets/classification/imagenet', + })) + + def _process_dataset(dataset): + + def replace_pipline(pipelines): + for pipeline in pipelines: + if pipeline['type'] in [ + 'LoadImageFromFile', + 'LoadAnnotations', + 'LoadPanopticAnnotations', + ]: + pipeline['file_client_args'] = file_client_args + + if dataset['type'] in ['CityscapesDataset']: + dataset['file_client_args'] = file_client_args + if 'pipeline' in dataset: + replace_pipline(dataset['pipeline']) + if 'dataset' in dataset: + _process_dataset(dataset['dataset']) + + def _process_evaluator(evaluator): + if evaluator['type'] == 'CocoPanopticMetric': + evaluator['file_client_args'] = file_client_args + + # half ceph + _process_dataset(cfg.train_dataloader.dataset, ) + _process_dataset(cfg.val_dataloader.dataset) + _process_dataset(cfg.test_dataloader.dataset) + _process_evaluator(cfg.val_evaluator) + _process_evaluator(cfg.test_evaluator) + + +def create_test_job_batch(commands, model_info, args, port): + + fname = model_info.name + + cfg_path = Path(model_info.config) + + cfg = mmengine.Config.fromfile(cfg_path) + + if args.replace_ceph: + replace_to_ceph(cfg) + + http_prefix = 'https://download.openmmlab.com/mmrazor/' + if 's3://' in args.checkpoint_root: + from mmengine.fileio import FileClient + from petrel_client.common.exception import AccessDeniedError + file_client = FileClient.infer_client(uri=args.checkpoint_root) + checkpoint = file_client.join_path( + args.checkpoint_root, model_info.weights[len(http_prefix):]) + + try: + exists = file_client.exists(checkpoint) + except AccessDeniedError: + exists = False + else: + checkpoint_root = Path(args.checkpoint_root) + checkpoint = checkpoint_root / model_info.weights[len(http_prefix):] + checkpoint.parent.mkdir(parents=True, exist_ok=True) + exists = checkpoint.exists() + if exists: + print(f'{checkpoint} already exists.') + else: + print(f'start downloading {fname}') + wget.download(model_info.weights, str(checkpoint)) + print(f'\nSaved in {checkpoint}.') + + job_name = f'{args.job_name}_{fname}' + work_dir = Path(args.work_dir) / fname + work_dir.mkdir(parents=True, exist_ok=True) + test_cfg_path = work_dir / 'config.py' + cfg.dump(test_cfg_path) + + if args.quotatype is not None: + quota_cfg = f'#SBATCH --quotatype {args.quotatype}\n' + else: + quota_cfg = '' + + launcher = 'none' if args.local else 'slurm' + runner = 'python' if args.local else 'srun python' + master_port = f'MASTER_PORT={port}' + + script_name = osp.join('tools', 'test.py') + job_script = (f'#!/bin/bash\n' + f'#SBATCH --output {work_dir}/job.%j.out\n' + f'#SBATCH --partition={args.partition}\n' + f'#SBATCH --job-name {job_name}\n' + f'#SBATCH --gres=gpu:{args.gpus}\n' + f'{quota_cfg}' + f'#SBATCH --ntasks-per-node={args.gpus}\n' + f'#SBATCH --ntasks={args.gpus}\n' + f'#SBATCH --cpus-per-task=5\n\n' + f'{master_port} {runner} -u {script_name} ' + f'{test_cfg_path} {checkpoint} ' + f'--work-dir {work_dir} ' + f'--launcher={launcher}\n') + + with open(work_dir / 'job.sh', 'w') as f: + f.write(job_script) + + commands.append(f'echo "{test_cfg_path}"') + if args.local: + commands.append(f'bash {work_dir}/job.sh') + else: + commands.append(f'sbatch {work_dir}/job.sh') + + return work_dir / 'job.sh' + + +def summary(args): + # parse model-index.yml + model_index_file = MMRAZOR_ROOT / 'model-index.yml' + model_index = load(str(model_index_file)) + model_index.build_models_with_collections() + models = OrderedDict({model.name: model for model in model_index.models}) + + if args.models: + patterns = [re.compile(pattern) for pattern in args.models] + filter_models = {} + for k, v in models.items(): + if any([re.match(pattern, k) for pattern in patterns]): + filter_models[k] = v + if len(filter_models) == 0: + print('No model found, please specify models in:') + print('\n'.join(models.keys())) + return + models = filter_models + + model_results = dict() + for model_info in models.values(): + model_name = model_info.name + work_dir = Path(args.work_dir) / model_name + sub_dirs = [p.name for p in work_dir.iterdir() if p.is_dir()] + + if len(sub_dirs) == 0: + print(f'{model_name} has no results.') + continue + + latest_time = sub_dirs[-1] + latest_json = work_dir / latest_time / f'{latest_time}.json' + + if not latest_json.exists(): + print(f'{model_name} has no results.') + continue + latest_result = mmengine.load(latest_json, 'json') + + expect_result = model_info.results[0].metrics + summary_result = { + 'expect': expect_result, + 'actual': {k: v + for k, v in latest_result.items()} + } + model_results[model_name] = summary_result + + mmengine.fileio.dump(model_results, + Path(args.work_dir) / 'summary.yml', 'yaml') + print(f'Summary results saved in {Path(args.work_dir)}/summary.yml') + + +def test(args): + # parse model-index.yml + model_index_file = MMRAZOR_ROOT / 'model-index.yml' + model_index = load(str(model_index_file)) + model_index.build_models_with_collections() + models = OrderedDict({model.name: model for model in model_index.models}) + + commands = [] + if args.models: + patterns = [re.compile(pattern) for pattern in args.models] + filter_models = {} + for k, v in models.items(): + if any([re.match(pattern, k) for pattern in patterns]): + filter_models[k] = v + if len(filter_models) == 0: + print('No model found, please specify models in:') + print('\n'.join(models.keys())) + return + models = filter_models + + preview_script = '' + port = args.port + for model_info in models.values(): + script_path = create_test_job_batch(commands, model_info, args, port) + preview_script = script_path or preview_script + port += 1 + command_str = '\n'.join(commands) + + preview = Table() + preview.add_column(str(preview_script)) + preview.add_column('Shell command preview') + preview.add_row( + Syntax.from_path( + preview_script, + background_color='default', + line_numbers=True, + word_wrap=True), + Syntax( + command_str, + 'bash', + background_color='default', + line_numbers=True, + word_wrap=True)) + console.print(preview) + + if args.run: + os.system(command_str) + else: + console.print('Please set "--run" to start the job') + + +def main(): + args = parse_args() + if args.summary: + summary(args) + else: + test(args) + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_train.py b/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_train.py new file mode 100755 index 000000000..597e9af0c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_train.py @@ -0,0 +1,338 @@ +import argparse +import logging +import os +import os.path as osp +import re +from collections import OrderedDict +from pathlib import Path + +import mmcv +import mmengine +from mmengine.logging import print_log +from modelindex.load_model_index import load +from rich.console import Console +from rich.syntax import Syntax +from rich.table import Table + +from mmrazor.testing import FastStopTrainingHook # noqa: F401 + +os.environ['MKL_THREADING_LAYER'] = 'GNU' + +console = Console() +MMRAZOR_ROOT = Path(__file__).absolute().parents[1] + +METRIC_MAPPINGS = { + 'accuracy/top1': 'Top 1 Accuracy', + 'accuracy/top5': 'Top 5 Accuracy' +} + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Test all models' accuracy in model-index.yml") + parser.add_argument( + 'partition', type=str, help='Cluster partition to use.') + parser.add_argument( + '--job-name', + type=str, + default='razor-train-benchmark', + help='Slurm job name prefix') + parser.add_argument('--port', type=int, default=29666, help='dist port') + parser.add_argument( + '--models', nargs='+', type=str, help='Specify model names to run.') + parser.add_argument('--gpus', type=int, default=8, help='num gpus') + parser.add_argument( + '--work-dir', + default='work_dirs/benchmark_train', + help='the dir to save metric') + parser.add_argument('--amp', action='store_true', help='use amp') + parser.add_argument( + '--auto-scale-lr', action='store_true', help='use auto scale lr') + parser.add_argument( + '--auto-resume', action='store_true', help='use auto resume') + parser.add_argument( + '--replace-ceph', action='store_true', help='load data from ceph') + parser.add_argument( + '--early-stop', action='store_true', help='early stop training') + parser.add_argument( + '--run', action='store_true', help='run script directly') + parser.add_argument( + '--summary', action='store_true', help='collect results') + parser.add_argument( + '--local', + action='store_true', + help='run at local instead of cluster.') + parser.add_argument( + '--mail', type=str, help='Mail address to watch test status.') + parser.add_argument( + '--mail-type', + nargs='+', + default=['BEGIN'], + choices=['NONE', 'BEGIN', 'END', 'FAIL', 'REQUEUE', 'ALL'], + help='Mail address to watch test status.') + parser.add_argument( + '--quotatype', + default=None, + choices=['reserved', 'auto', 'spot'], + help='Quota type, only available for phoenix-slurm>=0.2') + + args = parser.parse_args() + return args + + +def replace_to_ceph(cfg): + + file_client_args = dict( + backend='petrel', + path_mapping=dict({ + './data/coco': + 's3://openmmlab/datasets/detection/coco', + 'data/coco': + 's3://openmmlab/datasets/detection/coco', + './data/cityscapes': + 's3://openmmlab/datasets/segmentation/cityscapes', + 'data/cityscapes': + 's3://openmmlab/datasets/segmentation/cityscapes', + './data/imagenet': + 's3://openmmlab/datasets/classification/imagenet', + 'data/imagenet': + 's3://openmmlab/datasets/classification/imagenet', + })) + + def _process_pipeline(dataset, name): + + def replace_img(pipeline): + if pipeline['type'] == 'LoadImageFromFile': + pipeline['file_client_args'] = file_client_args + + def replace_ann(pipeline): + if pipeline['type'] == 'LoadAnnotations' or pipeline[ + 'type'] == 'LoadPanopticAnnotations': + pipeline['file_client_args'] = file_client_args + + if 'pipeline' in dataset: + replace_img(dataset.pipeline[0]) + replace_ann(dataset.pipeline[1]) + if 'dataset' in dataset: + # dataset wrapper + replace_img(dataset.dataset.pipeline[0]) + replace_ann(dataset.dataset.pipeline[1]) + else: + # dataset wrapper + replace_img(dataset.dataset.pipeline[0]) + replace_ann(dataset.dataset.pipeline[1]) + + def _process_evaluator(evaluator, name): + if evaluator['type'] == 'CocoPanopticMetric': + evaluator['file_client_args'] = file_client_args + + # half ceph + _process_pipeline(cfg.train_dataloader.dataset, cfg.filename) + _process_pipeline(cfg.val_dataloader.dataset, cfg.filename) + _process_pipeline(cfg.test_dataloader.dataset, cfg.filename) + _process_evaluator(cfg.val_evaluator, cfg.filename) + _process_evaluator(cfg.test_evaluator, cfg.filename) + + +def create_train_job_batch(commands, model_info, args, port): + + fname = model_info.name + + cfg_path = Path(model_info.config) + + cfg = mmengine.Config.fromfile(cfg_path) + + if args.replace_ceph: + replace_to_ceph(cfg) + + # enable automatically scaling LR + if args.auto_scale_lr: + if 'auto_scale_lr' in cfg and \ + 'enable' in cfg.auto_scale_lr and \ + 'base_batch_size' in cfg.auto_scale_lr: + cfg.auto_scale_lr.enable = True + else: + raise RuntimeError('Can not find "auto_scale_lr" or ' + '"auto_scale_lr.enable" or ' + '"auto_scale_lr.base_batch_size" in your' + ' configuration file.') + + # enable automatic-mixed-precision training + if args.amp is True: + optim_wrapper = cfg.optim_wrapper.type + if optim_wrapper == 'AmpOptimWrapper': + print_log( + 'AMP training is already enabled in your config.', + logger='current', + level=logging.WARNING) + else: + assert optim_wrapper == 'OptimWrapper', ( + '`--amp` is only supported when the optimizer wrapper type is ' + f'`OptimWrapper` but got {optim_wrapper}.') + cfg.optim_wrapper.type = 'AmpOptimWrapper' + cfg.optim_wrapper.loss_scale = 'dynamic' + + if args.auto_resume: + cfg.resume = True + + if args.early_stop: + if 'custom_hooks' in cfg: + cfg.custom_hooks.append(dict(type='mmrazor.FastStopTrainingHook')) + else: + custom_hooks = [dict(type='mmrazor.FastStopTrainingHook')] + cfg.custom_hooks = custom_hooks + + job_name = f'{args.job_name}_{fname}' + work_dir = Path(args.work_dir) / fname + work_dir.mkdir(parents=True, exist_ok=True) + + train_cfg_path = work_dir / 'config.py' + cfg.dump(train_cfg_path) + + if args.quotatype is not None: + quota_cfg = f'#SBATCH --quotatype {args.quotatype}\n' + else: + quota_cfg = '' + + launcher = 'none' if args.local else 'slurm' + runner = 'python' if args.local else 'srun python' + master_port = f'MASTER_PORT={port}' + + script_name = osp.join('tools', 'train.py') + job_script = (f'#!/bin/bash\n' + f'#SBATCH --output {work_dir}/job.%j.out\n' + f'#SBATCH --partition={args.partition}\n' + f'#SBATCH --job-name {job_name}\n' + f'#SBATCH --gres=gpu:{args.gpus}\n' + f'{quota_cfg}' + f'#SBATCH --ntasks-per-node={args.gpus}\n' + f'#SBATCH --ntasks={args.gpus}\n' + f'#SBATCH --cpus-per-task=5\n\n' + f'{master_port} {runner} -u {script_name} {train_cfg_path} ' + f'--work-dir {work_dir} ' + f'--launcher={launcher}\n') + + with open(work_dir / 'job.sh', 'w') as f: + f.write(job_script) + + commands.append(f'echo "{train_cfg_path}"') + if args.local: + commands.append(f'bash {work_dir}/job.sh') + else: + commands.append(f'sbatch {work_dir}/job.sh') + + return work_dir / 'job.sh' + + +def summary(args): + # parse model-index.yml + model_index_file = MMRAZOR_ROOT / 'model-index.yml' + model_index = load(str(model_index_file)) + model_index.build_models_with_collections() + models = OrderedDict({model.name: model for model in model_index.models}) + + if args.models: + patterns = [re.compile(pattern) for pattern in args.models] + filter_models = {} + for k, v in models.items(): + if any([re.match(pattern, k) for pattern in patterns]): + filter_models[k] = v + if len(filter_models) == 0: + print('No model found, please specify models in:') + print('\n'.join(models.keys())) + return + models = filter_models + + model_results = dict() + for model_info in models.values(): + model_name = model_info.name + work_dir = Path(args.work_dir) / model_name + sub_dirs = [p.name for p in work_dir.iterdir() if p.is_dir()] + + if len(sub_dirs) == 0: + print(f'{model_name} has no results.') + continue + + latest_time = sub_dirs[-1] + latest_json = work_dir / latest_time / f'{latest_time}.json' + + if not latest_json.exists(): + print(f'{model_name} has no results.') + continue + latest_result = mmcv.load(latest_json, 'json') + + expect_result = model_info.results[0].metrics + summary_result = { + 'expect': expect_result, + 'actual': + {METRIC_MAPPINGS[k]: v + for k, v in latest_result.items()} + } + model_results[model_name] = summary_result + + mmengine.fileio.dump(model_results, + Path(args.work_dir) / 'summary.yml', 'yaml') + print(f'Summary results saved in {Path(args.work_dir)}/summary.yml') + + +def train(args): + # parse model-index.yml + model_index_file = MMRAZOR_ROOT / 'model-index.yml' + model_index = load(str(model_index_file)) + model_index.build_models_with_collections() + models = OrderedDict({model.name: model for model in model_index.models}) + + commands = [] + if args.models: + patterns = [re.compile(pattern) for pattern in args.models] + filter_models = {} + for k, v in models.items(): + if any([re.match(pattern, k) for pattern in patterns]): + filter_models[k] = v + if len(filter_models) == 0: + print('No model found, please specify models in:') + print('\n'.join(models.keys())) + return + models = filter_models + + preview_script = '' + port = args.port + for model_info in models.values(): + script_path = create_train_job_batch(commands, model_info, args, port) + preview_script = script_path or preview_script + port += 1 + command_str = '\n'.join(commands) + + preview = Table() + preview.add_column(str(preview_script)) + preview.add_column('Shell command preview') + preview.add_row( + Syntax.from_path( + preview_script, + background_color='default', + line_numbers=True, + word_wrap=True), + Syntax( + command_str, + 'bash', + background_color='default', + line_numbers=True, + word_wrap=True)) + console.print(preview) + + if args.run: + os.system(command_str) + else: + console.print('Please set "--run" to start the job') + + +def main(): + args = parse_args() + if args.summary: + summary(args) + else: + train(args) + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/.dev_scripts/meta_files_test.py b/cv/distiller/CWD/mmrazor/.dev_scripts/meta_files_test.py new file mode 100755 index 000000000..92c0f2f0d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/.dev_scripts/meta_files_test.py @@ -0,0 +1,58 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import unittest +from pathlib import Path + +import requests +import yaml + +MMRAZOR_ROOT = Path(__file__).absolute().parents[1] + + +class TestMetafiles(unittest.TestCase): + + def get_metafiles(self, code_path): + """ + Function: get the metafile of all configs from model-index.yml + """ + metafile = os.path.join(code_path, 'model-index.yml') + with open(metafile, 'r') as f: + meta = yaml.safe_load(f) + return meta['Import'] + + def test_metafiles(self): + metafiles = self.get_metafiles(MMRAZOR_ROOT) + for mf in metafiles: + metafile = os.path.abspath(os.path.join(MMRAZOR_ROOT, mf)) + with open(metafile, 'r') as f: + meta = yaml.safe_load(f) + for model in meta['Models']: + # 1. weights url check + r = requests.head(model['Weights'], timeout=4) + assert r.status_code != 404, \ + f"can't connect url {model['Weights']} in " \ + f'metafile {metafile}' + + # 2. config check + dir_path = os.path.abspath(os.path.join(metafile, '../')) + # list all files which are in the same directory of + # current metafile + config_files = os.listdir(dir_path) + + if isinstance(model['Config'], list): + # TODO: 3. log error + continue + + assert (model['Config'].split('/')[-1] in config_files), \ + f"config error in {metafile} model {model['Name']}" + + # 4. name check + # erase '.py' + correct_name = model['Config'].split('/')[-1][:-3] + assert model['Name'] == correct_name, \ + f'name error in {metafile}, correct name should ' \ + f'be {correct_name}' + + +if __name__ == '__main__': + unittest.main() diff --git a/cv/distiller/CWD/mmrazor/.pre-commit-config.yaml b/cv/distiller/CWD/mmrazor/.pre-commit-config.yaml new file mode 100755 index 000000000..cd73ef928 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/.pre-commit-config.yaml @@ -0,0 +1,72 @@ + +exclude: ^tests/data/ +repos: + - repo: https://github.com/PyCQA/flake8 + rev: 4.0.1 + hooks: + - id: flake8 + - repo: https://github.com/PyCQA/isort + rev: 5.11.5 + hooks: + - id: isort + - repo: https://github.com/pre-commit/mirrors-yapf + rev: v0.30.0 + hooks: + - id: yapf + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.1.0 + hooks: + - id: trailing-whitespace + - id: check-yaml + - id: end-of-file-fixer + - id: requirements-txt-fixer + - id: double-quote-string-fixer + - id: check-merge-conflict + - id: fix-encoding-pragma + args: ["--remove"] + - id: mixed-line-ending + args: ["--fix=lf"] + - repo: https://github.com/codespell-project/codespell + rev: v2.1.0 + hooks: + - id: codespell + - repo: https://github.com/executablebooks/mdformat + rev: 0.7.14 + hooks: + - id: mdformat + args: ["--number"] + additional_dependencies: + - mdformat-gfm + - mdformat_frontmatter + - linkify-it-py + - repo: https://github.com/myint/docformatter + rev: v1.3.1 + hooks: + - id: docformatter + args: ["--in-place", "--wrap-descriptions", "79"] + - repo: https://github.com/executablebooks/mdformat + rev: 0.7.9 + hooks: + - id: mdformat + args: ["--number"] + additional_dependencies: + - mdformat-gfm + - mdformat_frontmatter + - linkify-it-py + - repo: https://github.com/open-mmlab/pre-commit-hooks + rev: v0.2.0 + hooks: + - id: check-algo-readme + - id: check-copyright + args: [ "mmrazor", "tests", "tools"] + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.812 + hooks: + - id: mypy + exclude: |- + (?x)( + ^test + | ^docs + | ^configs + | ^.*/configs* + ) diff --git a/cv/distiller/CWD/mmrazor/.readthedocs.yml b/cv/distiller/CWD/mmrazor/.readthedocs.yml new file mode 100755 index 000000000..6cfbf5d31 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/.readthedocs.yml @@ -0,0 +1,9 @@ +version: 2 + +formats: all + +python: + version: 3.7 + install: + - requirements: requirements/docs.txt + - requirements: requirements/readthedocs.txt diff --git a/cv/distiller/CWD/mmrazor/LICENSE b/cv/distiller/CWD/mmrazor/LICENSE new file mode 100755 index 000000000..f731325b2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/LICENSE @@ -0,0 +1,203 @@ +Copyright (c) OpenMMLab. All rights reserved + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 MMClassification Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/cv/distiller/CWD/mmrazor/MANIFEST.in b/cv/distiller/CWD/mmrazor/MANIFEST.in new file mode 100755 index 000000000..0aba33385 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/MANIFEST.in @@ -0,0 +1,6 @@ +include requirements/*.txt +include mmrazor/VERSION +include mmrazor/.mim/model-index.yml +include mmrazor/.mim/demo/*/* +recursive-include mmrazor/.mim/configs *.py *.yml +recursive-include mmrazor/.mim/tools *.sh *.py diff --git a/cv/distiller/CWD/mmrazor/README.md b/cv/distiller/CWD/mmrazor/README.md new file mode 100755 index 000000000..4dbb364d5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/README.md @@ -0,0 +1,235 @@ +

    + +
     
    +
    + OpenMMLab website + + + HOT + + +      + OpenMMLab platform + + + TRY IT OUT + + +
    +
     
    + + + +[![PyPI](https://img.shields.io/pypi/v/mmrazor)](https://pypi.org/project/mmrazor) +[![docs](https://img.shields.io/badge/docs-latest-blue)](https://mmrazor.readthedocs.io/en/main/) +[![badge](https://github.com/open-mmlab/mmrazor/workflows/build/badge.svg)](https://github.com/open-mmlab/mmrazor/actions) +[![codecov](https://codecov.io/gh/open-mmlab/mmrazor/branch/master/graph/badge.svg)](https://codecov.io/gh/open-mmlab/mmrazor) +[![license](https://img.shields.io/github/license/open-mmlab/mmrazor.svg)](https://github.com/open-mmlab/mmrazor/blob/master/LICENSE) +[![open issues](https://isitmaintained.com/badge/open/open-mmlab/mmrazor.svg)](https://github.com/open-mmlab/mmrazor/issues) +[![issue resolution](https://isitmaintained.com/badge/resolution/open-mmlab/mmrazor.svg)](https://github.com/open-mmlab/mmrazor/issues) + + + + + +[📘Documentation](https://mmrazor.readthedocs.io/en/main/) | +[🛠ï¸Installation](https://mmrazor.readthedocs.io/en/main/get_started/installation.html) | +[👀Model Zoo](https://mmrazor.readthedocs.io/en/main/get_started/model_zoo.html) | +[🤔Reporting Issues](https://github.com/open-mmlab/mmrazor/issues/new/choose) + +
    + + + +
    + +English | [简体中文](README_zh-CN.md) + +
    + + + + + + + + + + + +
    + +
    + +## Introduction + +MMRazor is a model compression toolkit for model slimming and AutoML, which includes 4 mainstream technologies: + +- Neural Architecture Search (NAS) +- Pruning +- Knowledge Distillation (KD) +- Quantization + +It is a part of the [OpenMMLab](https://openmmlab.com/) project. + +Major features: + +- **Compatibility** + + MMRazor can be easily applied to various projects in OpenMMLab, due to the similar architecture design of OpenMMLab as well as the decoupling of slimming algorithms and vision tasks. + +- **Flexibility** + + Different algorithms, e.g., NAS, pruning and KD, can be incorporated in a plug-n-play manner to build a more powerful system. + +- **Convenience** + + With better modular design, developers can implement new model compression algorithms with only a few codes, or even by simply modifying config files. + +About MMRazor's design and implementation, please refer to [tutorials](https://mmrazor.readthedocs.io/en/main/get_started/overview.html) for more details. + +## Latest Updates + +**The default branch is now `main` and the code on the branch has been upgraded to v1.0.0. The old `master` branch code now exists on the 0.x branch** + +MMRazor v1.0.0 was released in 2023-4-24, Major updates from 1.0.0rc2 include: + +1. MMRazor quantization is released. +2. Add a new pruning algorithm named GroupFisher. +3. Support distilling rtmdet with MMRazor. + +To know more about the updates in MMRazor 1.0, please refer to [Changelog](https://mmrazor.readthedocs.io/en/main/notes/changelog.html) for more details! + +## Benchmark and model zoo + +Results and models are available in the [model zoo](https://mmrazor.readthedocs.io/en/main/get_started/model_zoo.html). + +Supported algorithms: + +
    +Neural Architecture Search + +- [x] [DARTS(ICLR'2019)](configs/nas/mmcls/darts) + +- [x] [DetNAS(NeurIPS'2019)](configs/nas/mmdet/detnas) + +- [x] [SPOS(ECCV'2020)](configs/nas/mmcls/spos) + +
    + +
    +Pruning + +- [x] [AutoSlim(NeurIPS'2019)](/configs/pruning/mmcls/autoslim) + +- [x] [L1-norm](/configs/pruning/mmcls/l1-norm) + +- [x] [Group Fisher](/configs/pruning/base/group_fisher) + +- [x] [DMCP](/configs/pruning/mmcls/dmcp) + +
    + +
    +Knowledge Distillation + +- [x] [CWD(ICCV'2021)](/configs/distill/mmdet/cwd) + +- [x] [WSLD(ICLR'2021)](/configs/distill/mmcls/wsld) + +- [x] [ABLoss](/configs/distill/mmcls/abloss) + +- [x] [BYOT](/configs/distill/mmcls/byot) + +- [x] [DAFL](/configs/distill/mmcls/dafl) + +- [x] [DFAD](/configs/distill/mmcls/dfad) + +- [x] [DKD](/configs/distill/mmcls/dkd) + +- [x] [Factor Transfer](/configs/distill/mmcls/factor_transfer) + +- [x] [FitNets](/configs/distill/mmcls/fitnets) + +- [x] [KD](/configs/distill/mmcls/kd) + +- [x] [OFD](/configs/distill/mmcls/ofd) + +- [x] [RKD](/configs/distill/mmcls/rkd) + +- [x] [ZSKT](/configs/distill/mmcls/zskt) + +- [x] [FBKD](/configs/distill/mmdet/fbkd) + +
    + +
    +Quantization + +- [x] [PTQ](/configs/quantization/ptq/base) + +- [x] [QAT](/configs/quantization/qat/base) + +- [x] [LSQ](/configs/quantization/qat/lsq) + +
    + +## Installation + +MMRazor depends on [PyTorch](https://pytorch.org/), [MMCV](https://github.com/open-mmlab/mmcv) and [MMEngine](https://github.com/open-mmlab/mmengine). + +Please refer to [installation.md](https://mmrazor.readthedocs.io/en/main/get_started/installation.html) for more detailed instruction. + +## Getting Started + +Please refer to [user guides](https://mmrazor.readthedocs.io/en/main/user_guides/index.html) for the basic usage of MMRazor. There are also [advanced guides](https://mmrazor.readthedocs.io/en/main/advanced_guides/index.html): + +## Contributing + +We appreciate all contributions to improve MMRazor. +Please refer to [CONTRUBUTING.md](https://mmrazor.readthedocs.io/en/main/notes/contribution_guide.html) for the contributing guideline. + +## Acknowledgement + +MMRazor is an open source project that is contributed by researchers and engineers from various colleges and companies. We appreciate all the contributors who implement their methods or add new features, as well as users who give valuable feedbacks. +We wish that the toolbox and benchmark could serve the growing research community by providing a flexible toolkit to reimplement existing methods and develop their own new model compression methods. + +## Citation + +If you find this project useful in your research, please consider cite: + +```BibTeX +@misc{2021mmrazor, + title={OpenMMLab Model Compression Toolbox and Benchmark}, + author={MMRazor Contributors}, + howpublished = {\url{https://github.com/open-mmlab/mmrazor}}, + year={2021} +} +``` + +## License + +This project is released under the [Apache 2.0 license](LICENSE). + +## Projects in OpenMMLab + +- [MMCV](https://github.com/open-mmlab/mmcv): OpenMMLab foundational library for computer vision. +- [MIM](https://github.com/open-mmlab/mim): MIM installs OpenMMLab packages. +- [MMClassification](https://github.com/open-mmlab/mmclassification): OpenMMLab image classification toolbox and benchmark. +- [MMDetection](https://github.com/open-mmlab/mmdetection): OpenMMLab detection toolbox and benchmark. +- [MMDetection3D](https://github.com/open-mmlab/mmdetection3d): OpenMMLab's next-generation platform for general 3D object detection. +- [MMRotate](https://github.com/open-mmlab/mmrotate): OpenMMLab rotated object detection toolbox and benchmark. +- [MMYOLO](https://github.com/open-mmlab/mmyolo): OpenMMLab YOLO series toolbox and benchmark. +- [MMSegmentation](https://github.com/open-mmlab/mmsegmentation): OpenMMLab semantic segmentation toolbox and benchmark. +- [MMOCR](https://github.com/open-mmlab/mmocr): OpenMMLab text detection, recognition, and understanding toolbox. +- [MMPose](https://github.com/open-mmlab/mmpose): OpenMMLab pose estimation toolbox and benchmark. +- [MMHuman3D](https://github.com/open-mmlab/mmhuman3d): OpenMMLab 3D human parametric model toolbox and benchmark. +- [MMSelfSup](https://github.com/open-mmlab/mmselfsup): OpenMMLab self-supervised learning toolbox and benchmark. +- [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab model compression toolbox and benchmark. +- [MMFewShot](https://github.com/open-mmlab/mmfewshot): OpenMMLab fewshot learning toolbox and benchmark. +- [MMAction2](https://github.com/open-mmlab/mmaction2): OpenMMLab's next-generation action understanding toolbox and benchmark. +- [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab video perception toolbox and benchmark. +- [MMFlow](https://github.com/open-mmlab/mmflow): OpenMMLab optical flow toolbox and benchmark. +- [MMEditing](https://github.com/open-mmlab/mmediting): OpenMMLab image and video editing toolbox. +- [MMGeneration](https://github.com/open-mmlab/mmgeneration): OpenMMLab image and video generative models toolbox. +- [MMDeploy](https://github.com/open-mmlab/mmdeploy): OpenMMLab model deployment framework. diff --git a/cv/distiller/CWD/mmrazor/README_zh-CN.md b/cv/distiller/CWD/mmrazor/README_zh-CN.md new file mode 100755 index 000000000..fc59086fb --- /dev/null +++ b/cv/distiller/CWD/mmrazor/README_zh-CN.md @@ -0,0 +1,226 @@ +
    + +
     
    +
    + OpenMMLab 官网 + + + HOT + + +      + OpenMMLab å¼€æ”¾å¹³å° + + + TRY IT OUT + + +
    +
     
    + + + +[![PyPI](https://img.shields.io/pypi/v/mmrazor)](https://pypi.org/project/mmrazor) +[![docs](https://img.shields.io/badge/docs-latest-blue)](https://mmrazor.readthedocs.io/en/main/) +[![badge](https://github.com/open-mmlab/mmrazor/workflows/build/badge.svg)](https://github.com/open-mmlab/mmrazor/actions) +[![codecov](https://codecov.io/gh/open-mmlab/mmrazor/branch/master/graph/badge.svg)](https://codecov.io/gh/open-mmlab/mmrazor) +[![license](https://img.shields.io/github/license/open-mmlab/mmrazor.svg)](https://github.com/open-mmlab/mmrazor/blob/master/LICENSE) +[![open issues](https://isitmaintained.com/badge/open/open-mmlab/mmrazor.svg)](https://github.com/open-mmlab/mmrazor/issues) +[![issue resolution](https://isitmaintained.com/badge/resolution/open-mmlab/mmrazor.svg)](https://github.com/open-mmlab/mmrazor/issues) + + + + + +[📘使用文档](https://mmrazor.readthedocs.io/en/main/) | +[🛠ï¸å®‰è£…教程](https://mmrazor.readthedocs.io/en/main/get_started/installation.html) | +[👀👀模型库](https://mmrazor.readthedocs.io/en/main/get_started/model_zoo.html) | +[🤔报告问题](https://github.com/open-mmlab/mmrazor/issues/new/choose) + +
    + + + +
    + +[English](/README.md) | 简体中文 + +
    + +## 说明 + +MMRazor是一个å¯ç”¨äºŽæ¨¡åž‹ç˜¦èº«å’ŒAutoML的模型压缩工具箱,包å«äº†4ç§ä¸»æµçš„æŠ€æœ¯ï¼š + +- 网络结构æœç´¢ (NAS) +- æ¨¡åž‹å‰ªæž +- çŸ¥è¯†è’¸é¦ (KD) +- é‡åŒ– + +MMRazor是[OpenMMLab](https://openmmlab.com/)项目的一部分。 + +主è¦ç‰¹æ€§ + +- **兼容性** + + MMRazorå’ŒOpenMMLab有ç€ç±»ä¼¼çš„æž¶æž„设计,并且实现了轻é‡åŒ–算法和视觉任务间轻耦åˆï¼Œå› æ­¤å¾ˆå®¹æ˜“应用于OpenMMLab中其他的项目。 + +- **çµæ´»æ€§** + + 多ç§è½»é‡åŒ–算法å¯ä»¥ä»¥ä¸€ç§å³æ’å³ç”¨çš„æ–¹å¼æ¥ç»„åˆä½¿ç”¨ï¼Œä»Žè€Œæ­å»ºå‡ºåŠŸèƒ½æ›´å¼ºå¤§çš„ç³»ç»Ÿã€‚ + +- **便利性** + + 得益于更好的模å—化设计,开å‘者仅用修改少é‡ä»£ç ï¼Œç”šè‡³åªç”¨ä¿®æ”¹é…置文件å³å¯å®žçŽ°æ–°çš„è½»é‡åŒ–算法。 + +关于MMRazor设计和实现的概括图, 如果想了解更多的细节,请å‚考 [tutorials](/docs/en/tutorials/Tutorial_1_overview.md)。 + +## 近期更新 + +**默认分支目å‰ä¸º main,且分支上的代ç å·²ç»åˆ‡æ¢åˆ° v1.0.0 版本。旧版 master 分支的代ç çŽ°å­˜åœ¨ 0.x 分支上** + +## 更新日志 + +MMRazor v0.3.1 版本已ç»åœ¨ 2022.5.4 å‘布。 + +## 基准测试和模型库 + +测试结果å¯ä»¥åœ¨ [模型库](https://mmrazor.readthedocs.io/en/main/get_started/model_zoo.html) 中找到. + +å·²ç»æ”¯æŒçš„算法: + +Neural Architecture Search + +- [x] [DARTS(ICLR'2019)](configs/nas/darts) + +- [x] [DetNAS(NeurIPS'2019)](configs/nas/detnas) + +- [x] [SPOS(ECCV'2020)](configs/nas/spos) + +Pruning + +- [x] [AutoSlim(NeurIPS'2019)](/configs/pruning/mmcls/autoslim) + +- [x] [L1-norm](/configs/pruning/mmcls/l1-norm) + +- [x] [Group Fisher](/configs/pruning/base/group_fisher) + +- [x] [DMCP](/configs/pruning/mmcls/dmcp) + +Knowledge Distillation + +- [x] [CWD(ICCV'2021)](/configs/distill/mmdet/cwd) + +- [x] [WSLD(ICLR'2021)](/configs/distill/mmcls/wsld) + +- [x] [ABLoss](/configs/distill/mmcls/abloss) + +- [x] [BYOT](/configs/distill/mmcls/byot) + +- [x] [DAFL](/configs/distill/mmcls/dafl) + +- [x] [DFAD](/configs/distill/mmcls/dfad) + +- [x] [DKD](/configs/distill/mmcls/dkd) + +- [x] [Factor Transfer](/configs/distill/mmcls/factor_transfer) + +- [x] [FitNets](/configs/distill/mmcls/fitnets) + +- [x] [KD](/configs/distill/mmcls/kd) + +- [x] [OFD](/configs/distill/mmcls/ofd) + +- [x] [RKD](/configs/distill/mmcls/rkd) + +- [x] [ZSKT](/configs/distill/mmcls/zskt) + +- [x] [FBKD](/configs/distill/mmdet/fbkd) + +
    +Quantization + +- [x] [PTQ](/configs/quantization/ptq/base) + +- [x] [QAT](/configs/quantization/qat/base) + +- [x] [LSQ](/configs/quantization/qat/lsq) + +
    + +## 安装 + +MMRazor ä¾èµ– [PyTorch](https://pytorch.org/) å’Œ [MMCV](https://github.com/open-mmlab/mmcv)。 + +请å‚考[安装教程](https://mmrazor.readthedocs.io/en/main/get_started/installation.html)èŽ·å–æ›´è¯¦ç»†çš„安装指å—。 + +## 快速入门 + +请å‚考 [用户指引](https://mmrazor.readthedocs.io/en/main/user_guides/index.html) 学习 MMRazor 的基本使用。 我们也æä¾›äº†ä¸€äº›[进阶教程](https://mmrazor.readthedocs.io/en/main/advanced_guides/index.html): + +## è´¡çŒ®æŒ‡å— + +我们感谢所有的贡献者为改进和æå‡ MMRazor 所作出的努力。 +请å‚考[贡献指å—](https://mmrazor.readthedocs.io/en/main/notes/contribution_guide.html)æ¥äº†è§£å‚与项目贡献的相关指引。 + +## 致谢 + +MMRazor 是一款由æ¥è‡ªä¸åŒé«˜æ ¡å’Œä¼ä¸šçš„ç ”å‘人员共åŒå‚与贡献的开æºé¡¹ç›®ã€‚我们感谢所有为项目æä¾›ç®—法å¤çŽ°å’Œæ–°åŠŸèƒ½æ”¯æŒçš„è´¡çŒ®è€…ï¼Œä»¥åŠæä¾›å®è´µå馈的用户。 我们希望这个工具箱和基准测试å¯ä»¥ä¸ºç¤¾åŒºæä¾›çµæ´»çš„代ç å·¥å…·ï¼Œä¾›ç”¨æˆ·å¤çŽ°å·²æœ‰ç®—æ³•å¹¶å¼€å‘è‡ªå·±çš„æ–°æ¨¡åž‹åŽ‹ç¼©ç®—æ³•ï¼Œä»Žè€Œä¸æ–­ä¸ºå¼€æºç¤¾åŒºæä¾›è´¡çŒ®ã€‚ + +## 引用 + +如果您å‘现此项目对您的研究有用,请考虑引用: + +```BibTeX +@misc{2021mmrazor, + title={OpenMMLab Model Compression Toolbox and Benchmark}, + author={MMRazor Contributors}, + howpublished = {\url{https://github.com/open-mmlab/mmrazor}}, + year={2021} +} +``` + +## å¼€æºè®¸å¯è¯ + +该项目采用 [Apache 2.0 å¼€æºè®¸å¯è¯](LICENSE)。 + +## OpenMMLab 的其他项目 + +- [MMCV](https://github.com/open-mmlab/mmcv): OpenMMLab 计算机视觉基础库 +- [MIM](https://github.com/open-mmlab/mim): MIM 是 OpenMMlab 项目ã€ç®—æ³•ã€æ¨¡åž‹çš„ç»Ÿä¸€å…¥å£ +- [MMClassification](https://github.com/open-mmlab/mmclassification): OpenMMLab 图åƒåˆ†ç±»å·¥å…·ç®± +- [MMDetection](https://github.com/open-mmlab/mmdetection): OpenMMLab 目标检测工具箱 +- [MMDetection3D](https://github.com/open-mmlab/mmdetection3d): OpenMMLab 新一代通用 3D ç›®æ ‡æ£€æµ‹å¹³å° +- [MMRotate](https://github.com/open-mmlab/mmrotate): OpenMMLab 旋转框检测工具箱与测试基准 +- [MMYOLO](https://github.com/open-mmlab/mmyolo): OpenMMLab YOLO 系列工具箱与测试基准 +- [MMSegmentation](https://github.com/open-mmlab/mmsegmentation): OpenMMLab 语义分割工具箱 +- [MMOCR](https://github.com/open-mmlab/mmocr): OpenMMLab å…¨æµç¨‹æ–‡å­—检测识别ç†è§£å·¥å…·ç®± +- [MMPose](https://github.com/open-mmlab/mmpose): OpenMMLab å§¿æ€ä¼°è®¡å·¥å…·ç®± +- [MMHuman3D](https://github.com/open-mmlab/mmhuman3d): OpenMMLab äººä½“å‚æ•°åŒ–模型工具箱与测试基准 +- [MMSelfSup](https://github.com/open-mmlab/mmselfsup): OpenMMLab 自监ç£å­¦ä¹ å·¥å…·ç®±ä¸Žæµ‹è¯•基准 +- [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab 模型压缩工具箱与测试基准 +- [MMFewShot](https://github.com/open-mmlab/mmfewshot): OpenMMLab 少样本学习工具箱与测试基准 +- [MMAction2](https://github.com/open-mmlab/mmaction2): OpenMMLab 新一代视频ç†è§£å·¥å…·ç®± +- [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab ä¸€ä½“åŒ–è§†é¢‘ç›®æ ‡æ„ŸçŸ¥å¹³å° +- [MMFlow](https://github.com/open-mmlab/mmflow): OpenMMLab å…‰æµä¼°è®¡å·¥å…·ç®±ä¸Žæµ‹è¯•基准 +- [MMEditing](https://github.com/open-mmlab/mmediting): OpenMMLab 图åƒè§†é¢‘编辑工具箱 +- [MMGeneration](https://github.com/open-mmlab/mmgeneration): OpenMMLab å›¾ç‰‡è§†é¢‘ç”Ÿæˆæ¨¡åž‹å·¥å…·ç®± +- [MMDeploy](https://github.com/open-mmlab/mmdeploy): OpenMMLab 模型部署框架 + +## 欢迎加入 OpenMMLab 社区 + +扫æä¸‹æ–¹çš„二维ç å¯å…³æ³¨ OpenMMLab 团队的 [知乎官方账å·](https://www.zhihu.com/people/openmmlab),加入 OpenMMLab 团队的 [å®˜æ–¹äº¤æµ QQ 群](https://jq.qq.com/?_wv=1027&k=aCvMxdr3),添加OpenMMLab 官方å°åŠ©æ‰‹å¾®ä¿¡ï¼ŒåŠ å…¥ MMSelfSup 微信社区。 + +
    + +
    + +我们会在 OpenMMLab 社区为大家 + +- 📢 分享 AI æ¡†æž¶çš„å‰æ²¿æ ¸å¿ƒæŠ€æœ¯ +- 💻 解读 PyTorch å¸¸ç”¨æ¨¡å—æºç  +- 📰 å‘布 OpenMMLab 的相关新闻 +- 🚀 ä»‹ç» OpenMMLab å¼€å‘çš„å‰æ²¿ç®—法 +- ðŸƒ èŽ·å–æ›´é«˜æ•ˆçš„问题答疑和æ„è§å馈 +- 🔥 æä¾›ä¸Žå„行å„业开å‘者充分交æµçš„å¹³å° + +干货满满 ðŸ“˜ï¼Œç­‰ä½ æ¥æ’© 💗,OpenMMLab 社区期待您的加入 👬 diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/cifar100_bs16_auto_aug.py b/cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/cifar100_bs16_auto_aug.py new file mode 100755 index 000000000..46c31ac72 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/cifar100_bs16_auto_aug.py @@ -0,0 +1,50 @@ +_base_ = ['./pipelines/auto_aug_cifar.py'] + +# dataset settings +dataset_type = 'CIFAR100' +preprocess_cfg = dict( + # RGB format normalization parameters + mean=[129.304, 124.070, 112.434], + std=[68.170, 65.392, 70.418], + # loaded images are already RGB format + to_rgb=False) + +train_pipeline = [ + dict(type='RandomCrop', crop_size=32, padding=4), + dict(type='RandomFlip', prob=0.5, direction='horizontal'), + dict(type='Cutout', shape=16, pad_val=0), + dict(type='AutoAugment', policies={{_base_.policy_cifar}}), + dict(type='PackClsInputs'), +] + +test_pipeline = [ + dict(type='PackClsInputs'), +] + +train_dataloader = dict( + batch_size=16, + num_workers=2, + dataset=dict( + type=dataset_type, + data_prefix='data/cifar100', + test_mode=False, + pipeline=train_pipeline), + sampler=dict(type='DefaultSampler', shuffle=True), + persistent_workers=True, +) + +val_dataloader = dict( + batch_size=16, + num_workers=2, + dataset=dict( + type=dataset_type, + data_prefix='data/cifar100/', + test_mode=True, + pipeline=test_pipeline), + sampler=dict(type='DefaultSampler', shuffle=False), + persistent_workers=True, +) +val_evaluator = dict(type='Accuracy', topk=(1, 5)) + +test_dataloader = val_dataloader +test_evaluator = val_evaluator diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/pipelines/auto_aug_cifar.py b/cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/pipelines/auto_aug_cifar.py new file mode 100755 index 000000000..4767a8fe1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/pipelines/auto_aug_cifar.py @@ -0,0 +1,125 @@ +# Policy for CIFAR, refer to +# https://github.com/DeepVoltaire/AutoAugment/blame/master/autoaugment.py +policy_cifar = [ + # Group 1 + [ + dict(type='Invert', prob=0.1), + dict(type='Contrast', magnitude=0.5, prob=0.2) + ], + [ + dict(type='Rotate', angle=10., prob=0.7), + dict(type='Translate', magnitude=150 / 331, prob=0.3) + ], + [ + dict(type='Sharpness', magnitude=0.9, prob=0.8), + dict(type='Sharpness', magnitude=0.3, prob=0.9) + ], + [ + dict( + type='Shear', + magnitude=0.3 / 9 * 8, + direction='vertical', + prob=0.5), + dict( + type='Translate', + magnitude=150 / 331, + direction='vertical', + prob=0.3) + ], + [dict(type='AutoContrast', prob=0.5), + dict(type='Equalize', prob=0.9)], + # Group 2 + [ + dict( + type='Shear', + magnitude=0.3 / 9 * 7, + direction='vertical', + prob=0.2), + dict(type='Posterize', bits=5, prob=0.3) + ], + [ + dict(type='ColorTransform', magnitude=0.3, prob=0.4), + dict(type='Brightness', magnitude=0.7, prob=0.7) + ], + [ + dict(type='Sharpness', magnitude=1.0, prob=0.3), + dict(type='Brightness', magnitude=1.0, prob=0.7) + ], + [dict(type='Equalize', prob=0.6), + dict(type='Equalize', prob=0.5)], + [ + dict(type='Contrast', magnitude=0.6, prob=0.6), + dict(type='Sharpness', magnitude=0.4, prob=0.8), + ], + # Group 3 + [ + dict(type='ColorTransform', magnitude=0.6, prob=0.7), + dict(type='Translate', magnitude=150 / 331 / 9 * 7, prob=0.5) + ], + [dict(type='Equalize', prob=0.3), + dict(type='AutoContrast', prob=0.4)], + [ + dict( + type='Translate', + magnitude=150 / 331 / 9 * 2, + direction='vertical', + prob=0.4), + dict(type='Sharpness', magnitude=0.5, prob=0.2) + ], + [ + dict(type='Brightness', magnitude=0.5, prob=0.9), + dict(type='ColorTransform', magnitude=0.7, prob=0.2), + ], + [ + dict(type='Solarize', thr=256 / 9 * 7, prob=0.5), + dict(type='Invert', prob=0.0), + ], + # Group 4 + [dict(type='Equalize', prob=0.2), + dict(type='AutoContrast', prob=0.6)], + [dict(type='Equalize', prob=0.2), + dict(type='Equalize', prob=0.6)], + [ + dict(type='ColorTransform', magnitude=0.9, prob=0.9), + dict(type='Equalize', prob=0.6) + ], + [ + dict(type='AutoContrast', prob=0.8), + dict(type='Solarize', thr=256 / 9 * 1, prob=0.2), + ], + [ + dict(type='Brightness', magnitude=0.3, prob=0.1), + dict(type='ColorTransform', magnitude=0.0, prob=0.7) + ], + # Group 5 + [ + dict(type='Solarize', thr=256 / 9 * 4, prob=0.4), + dict(type='AutoContrast', prob=0.9) + ], + [ + dict( + type='Translate', + magnitude=150 / 331, + direction='vertical', + prob=0.9), + dict( + type='Translate', + magnitude=150 / 331, + direction='vertical', + prob=0.7) + ], + [ + dict(type='AutoContrast', prob=0.9), + dict(type='Solarize', thr=256 / 9 * 6, prob=0.8) + ], + [dict(type='Equalize', prob=0.8), + dict(type='Invert', prob=0.1)], + [ + dict( + type='Translate', + magnitude=150 / 331, + direction='vertical', + prob=0.7), + dict(type='AutoContrast', prob=0.9) + ] +] diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/attentive_mobilenetv3_supernet.py b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/attentive_mobilenetv3_supernet.py new file mode 100755 index 000000000..5e5af29ad --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/attentive_mobilenetv3_supernet.py @@ -0,0 +1,49 @@ +# search space +arch_setting = dict( + kernel_size=[ # [min_kernel_size, max_kernel_size, step] + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + ], + num_blocks=[ # [min_num_blocks, max_num_blocks, step] + [1, 2, 1], + [3, 5, 1], + [3, 6, 1], + [3, 6, 1], + [3, 8, 1], + [3, 8, 1], + [1, 2, 1], + ], + expand_ratio=[ # [min_expand_ratio, max_expand_ratio, step] + [1, 1, 1], + [4, 6, 1], + [4, 6, 1], + [4, 6, 1], + [4, 6, 1], + [6, 6, 1], + [6, 6, 1], + [6, 6, 1], # last layer + ], + num_out_channels=[ # [min_channel, max_channel, step] + [16, 24, 8], # first layer + [16, 24, 8], + [24, 32, 8], + [32, 40, 8], + [64, 72, 8], + [112, 128, 8], + [192, 216, 8], + [216, 224, 8], + [1792, 1984, 1984 - 1792], # last layer + ]) + +input_resizer_cfg = dict( + input_sizes=[[192, 192], [224, 224], [256, 256], [288, 288]]) + +nas_backbone = dict( + type='AttentiveMobileNetV3', + arch_setting=arch_setting, + norm_cfg=dict(type='DynamicBatchNorm2d', momentum=0.0)) diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/darts_supernet.py b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/darts_supernet.py new file mode 100755 index 000000000..36cec1328 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/darts_supernet.py @@ -0,0 +1,31 @@ +mutable_cfg = dict( + type='mmrazor.DiffMutableOP', + candidates=dict( + zero=dict(type='mmrazor.DartsZero'), + skip_connect=dict(type='mmrazor.DartsSkipConnect', use_drop_path=True), + max_pool_3x3=dict( + type='mmrazor.DartsPoolBN', pool_type='max', use_drop_path=True), + avg_pool_3x3=dict( + type='mmrazor.DartsPoolBN', pool_type='avg', use_drop_path=True), + sep_conv_3x3=dict( + type='mmrazor.DartsSepConv', kernel_size=3, use_drop_path=True), + sep_conv_5x5=dict( + type='mmrazor.DartsSepConv', kernel_size=5, use_drop_path=True), + dil_conv_3x3=dict( + type='mmrazor.DartsDilConv', kernel_size=3, use_drop_path=True), + dil_conv_5x5=dict( + type='mmrazor.DartsDilConv', kernel_size=5, use_drop_path=True))) + +route_cfg = dict(type='mmrazor.DiffChoiceRoute', with_arch_param=True) + +nas_backbone = dict( + type='mmrazor.DartsBackbone', + in_channels=3, + base_channels=16, + num_layers=8, + num_nodes=4, + stem_multiplier=3, + out_indices=(7, ), + mutable_cfg=mutable_cfg, + route_cfg=route_cfg, + norm_cfg=dict(type='BN', affine=False)) diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/dsnas_shufflenet_supernet.py b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/dsnas_shufflenet_supernet.py new file mode 100755 index 000000000..f73c8b90e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/dsnas_shufflenet_supernet.py @@ -0,0 +1,28 @@ +norm_cfg = dict(type='BN', eps=0.01) + +_STAGE_MUTABLE = dict( + type='mmrazor.OneHotMutableOP', + fix_threshold=0.3, + candidates=dict( + shuffle_3x3=dict( + type='ShuffleBlock', kernel_size=3, norm_cfg=norm_cfg), + shuffle_5x5=dict( + type='ShuffleBlock', kernel_size=5, norm_cfg=norm_cfg), + shuffle_7x7=dict( + type='ShuffleBlock', kernel_size=7, norm_cfg=norm_cfg), + shuffle_xception=dict(type='ShuffleXception', norm_cfg=norm_cfg))) + +arch_setting = [ + # Parameters to build layers. 3 parameters are needed to construct a + # layer, from left to right: channel, num_blocks, mutable_cfg. + [64, 4, _STAGE_MUTABLE], + [160, 4, _STAGE_MUTABLE], + [320, 8, _STAGE_MUTABLE], + [640, 4, _STAGE_MUTABLE] +] + +nas_backbone = dict( + type='mmrazor.SearchableShuffleNetV2', + widen_factor=1.0, + arch_setting=arch_setting, + norm_cfg=norm_cfg) diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/ofa_mobilenetv3_supernet.py b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/ofa_mobilenetv3_supernet.py new file mode 100755 index 000000000..d39d7fdfb --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/ofa_mobilenetv3_supernet.py @@ -0,0 +1,57 @@ +# search space +arch_setting = dict( + kernel_size=[ # [min_kernel_size, max_kernel_size, step] + [3, 3, 1], + [3, 7, 2], + [3, 7, 2], + [3, 7, 2], + [3, 7, 2], + [3, 7, 2], + ], + num_blocks=[ # [min_num_blocks, max_num_blocks, step] + [1, 1, 1], + [2, 4, 1], + [2, 4, 1], + [2, 4, 1], + [2, 4, 1], + [2, 4, 1], + ], + expand_ratio=[ # [min_expand_ratio, max_expand_ratio, step] + [1, 1, 1], + [3, 6, 1], + [3, 6, 1], + [3, 6, 1], + [3, 6, 1], + [3, 6, 1], + [6, 6, 1], # last layer + ], + # [16, 16, 24, 40, 80, 112, 160, 960, 1280] + num_out_channels=[ # [min_channel, max_channel, step] + [16, 16, 8], # first layer + [16, 16, 8], + [16, 24, 8], + [24, 40, 8], + [40, 80, 8], + [80, 112, 8], + [112, 160, 8], + [1024, 1280, 1280 - 1024], # last layer + ]) + +input_resizer_cfg = dict( + input_sizes=[[128, 128], [140, 140], [144, 144], [152, 152], [192, 192], + [204, 204], [224, 224], [256, 256]]) + +nas_backbone = dict( + type='mmrazor.AttentiveMobileNetV3', + arch_setting=arch_setting, + out_indices=(6, ), + stride_list=[1, 2, 2, 2, 1, 2], + with_se_list=[False, False, True, False, True, True], + act_cfg_list=[ + 'HSwish', 'ReLU', 'ReLU', 'ReLU', 'HSwish', 'HSwish', 'HSwish', + 'HSwish', 'HSwish' + ], + conv_cfg=dict(type='OFAConv2d'), + norm_cfg=dict(type='mmrazor.DynamicBatchNorm2d', momentum=0.1), + fine_grained_mode=True, + with_attentive_shortcut=False) diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_mobilenet_supernet.py b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_mobilenet_supernet.py new file mode 100755 index 000000000..f65ef88d8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_mobilenet_supernet.py @@ -0,0 +1,65 @@ +_STAGE_MUTABLE = dict( + _scope_='mmrazor', + type='OneShotMutableOP', + candidates=dict( + mb_k3e3=dict( + type='MBBlock', + kernel_size=3, + expand_ratio=3, + act_cfg=dict(type='ReLU6')), + mb_k5e3=dict( + type='MBBlock', + kernel_size=5, + expand_ratio=3, + act_cfg=dict(type='ReLU6')), + mb_k7e3=dict( + type='MBBlock', + kernel_size=7, + expand_ratio=3, + act_cfg=dict(type='ReLU6')), + mb_k3e6=dict( + type='MBBlock', + kernel_size=3, + expand_ratio=6, + act_cfg=dict(type='ReLU6')), + mb_k5e6=dict( + type='MBBlock', + kernel_size=5, + expand_ratio=6, + act_cfg=dict(type='ReLU6')), + mb_k7e6=dict( + type='MBBlock', + kernel_size=7, + expand_ratio=6, + act_cfg=dict(type='ReLU6')), + identity=dict(type='Identity'))) + +_FIRST_MUTABLE = dict( + _scope_='mmrazor', + type='OneShotMutableOP', + candidates=dict( + mb_k3e1=dict( + type='MBBlock', + kernel_size=3, + expand_ratio=1, + act_cfg=dict(type='ReLU6')))) + +arch_setting = [ + # Parameters to build layers. 3 parameters are needed to construct a + # layer, from left to right: channel, num_blocks, stride, mutable_cfg. + [24, 1, 1, _FIRST_MUTABLE], + [32, 4, 2, _STAGE_MUTABLE], + [56, 4, 2, _STAGE_MUTABLE], + [112, 4, 2, _STAGE_MUTABLE], + [128, 4, 1, _STAGE_MUTABLE], + [256, 4, 2, _STAGE_MUTABLE], + [432, 1, 1, _STAGE_MUTABLE] +] + +nas_backbone = dict( + _scope_='mmrazor', + type='SearchableMobileNetV2', + first_channels=40, + last_channels=1728, + widen_factor=1.0, + arch_setting=arch_setting) diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_shufflenet_supernet.py b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_shufflenet_supernet.py new file mode 100755 index 000000000..6f57e8acf --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_shufflenet_supernet.py @@ -0,0 +1,23 @@ +_STAGE_MUTABLE = dict( + _scope_='mmrazor', + type='OneShotMutableOP', + candidates=dict( + shuffle_3x3=dict(type='ShuffleBlock', kernel_size=3), + shuffle_5x5=dict(type='ShuffleBlock', kernel_size=5), + shuffle_7x7=dict(type='ShuffleBlock', kernel_size=7), + shuffle_xception=dict(type='ShuffleXception'))) + +arch_setting = [ + # Parameters to build layers. 3 parameters are needed to construct a + # layer, from left to right: channel, num_blocks, mutable_cfg. + [64, 4, _STAGE_MUTABLE], + [160, 4, _STAGE_MUTABLE], + [320, 8, _STAGE_MUTABLE], + [640, 4, _STAGE_MUTABLE] +] + +nas_backbone = dict( + _scope_='mmrazor', + type='SearchableShuffleNetV2', + widen_factor=1.0, + arch_setting=arch_setting) diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_subnet.py b/cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_subnet.py new file mode 100755 index 000000000..5eacb9510 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_subnet.py @@ -0,0 +1,68 @@ +# dataset settings +dataset_type = 'mmcls.CIFAR10' +preprocess_cfg = dict( + # RGB format normalization parameters + mean=[125.307, 122.961, 113.8575], + std=[51.5865, 50.847, 51.255], + # loaded images are already RGB format + to_rgb=False) + +train_pipeline = [ + dict(type='mmcls.RandomCrop', crop_size=32, padding=4), + dict(type='mmcls.RandomFlip', prob=0.5, direction='horizontal'), + dict(type='mmcls.Cutout', shape=16, pad_val=0, prob=1.0), + dict(type='mmcls.PackClsInputs'), +] + +test_pipeline = [ + dict(type='mmcls.PackClsInputs'), +] + +train_dataloader = dict( + batch_size=96, + num_workers=2, + dataset=dict( + type=dataset_type, + data_prefix='data/cifar10', + test_mode=False, + pipeline=train_pipeline), + sampler=dict(type='mmcls.DefaultSampler', shuffle=True), + persistent_workers=True, +) + +val_dataloader = dict( + batch_size=16, + num_workers=2, + dataset=dict( + type=dataset_type, + data_prefix='data/cifar10/', + test_mode=True, + pipeline=test_pipeline), + sampler=dict(type='DefaultSampler', shuffle=False), + persistent_workers=True, +) +val_evaluator = dict(type='mmcls.Accuracy', topk=(1, )) + +test_dataloader = val_dataloader +test_evaluator = val_evaluator + +# optimizer +optim_wrapper = dict( + optimizer=dict(type='SGD', lr=0.025, momentum=0.9, weight_decay=3e-4), + clip_grad=dict(max_norm=5, norm_type=2)) + +# leanring policy +param_scheduler = [ + dict( + type='CosineAnnealingLR', + T_max=600, + by_epoch=True, + begin=0, + end=600, + ) +] + +# train, val, test setting +train_cfg = dict(by_epoch=True, max_epochs=600) +val_cfg = dict() # validate each epoch +test_cfg = dict() # dataset settings diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_supernet.py b/cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_supernet.py new file mode 100755 index 000000000..66fb75fe4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_supernet.py @@ -0,0 +1,88 @@ +# dataset settings +dataset_type = 'mmcls.CIFAR10' +preprocess_cfg = dict( + # RGB format normalization parameters + mean=[125.307, 122.961, 113.8575], + std=[51.5865, 50.847, 51.255], + # loaded images are already RGB format + to_rgb=False) + +train_pipeline = [ + dict(type='mmcls.RandomCrop', crop_size=32, padding=4), + dict(type='mmcls.RandomFlip', prob=0.5, direction='horizontal'), + dict(type='mmcls.PackClsInputs'), +] + +test_pipeline = [ + dict(type='mmcls.PackClsInputs'), +] + +train_dataloader = dict( + batch_size=64, + num_workers=4, + dataset=dict( + type=dataset_type, + data_prefix='data/cifar10', + indices=-25000, + test_mode=False, + pipeline=train_pipeline), + sampler=dict(type='mmcls.DefaultSampler', shuffle=True), + persistent_workers=True, +) + +val_dataloader = dict( + batch_size=128, + num_workers=4, + dataset=dict( + type=dataset_type, + data_prefix='data/cifar10/', + test_mode=True, + pipeline=test_pipeline), + sampler=dict(type='mmcls.DefaultSampler', shuffle=False), + persistent_workers=True, +) +val_evaluator = dict(type='mmcls.Accuracy', topk=(1, )) + +test_dataloader = val_dataloader +test_evaluator = val_evaluator + +# optimizer +optim_wrapper = dict( + constructor='mmrazor.SeparateOptimWrapperConstructor', + architecture=dict( + optimizer=dict( + type='mmcls.SGD', lr=0.025, momentum=0.9, weight_decay=3e-4), + clip_grad=dict(max_norm=5, norm_type=2)), + mutator=dict( + optimizer=dict(type='mmcls.Adam', lr=3e-4, weight_decay=1e-3))) + +search_epochs = 50 +# leanring policy +param_scheduler = [ + dict( + type='mmcls.CosineAnnealingLR', + T_max=search_epochs, + eta_min=1e-3, + begin=0, + end=search_epochs), +] + +# train, val, test setting +train_cfg = dict( + type='mmrazor.DartsEpochBasedTrainLoop', + mutator_dataloader=dict( + batch_size=64, + num_workers=4, + dataset=dict( + type=dataset_type, + data_prefix='data/cifar10', + indices=25000, + test_mode=False, + pipeline=train_pipeline), + sampler=dict(type='mmcls.DefaultSampler', shuffle=True), + persistent_workers=True, + ), + max_epochs=search_epochs) + +val_cfg = dict() # validate each epoch +test_cfg = dict() # dataset settings diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_dsnas.py b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_dsnas.py new file mode 100755 index 000000000..bf266c51c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_dsnas.py @@ -0,0 +1,102 @@ +# dataset settings +dataset_type = 'mmcls.ImageNet' +data_preprocessor = dict( + type='mmcls.ClsDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True, +) + +train_pipeline = [ + dict(type='mmcls.LoadImageFromFile'), + dict(type='mmcls.RandomResizedCrop', scale=224), + dict(type='mmcls.RandomFlip', prob=0.5, direction='horizontal'), + dict(type='mmcls.PackClsInputs'), +] + +test_pipeline = [ + dict(type='mmcls.LoadImageFromFile'), + dict(type='mmcls.ResizeEdge', scale=256, edge='short'), + dict(type='mmcls.CenterCrop', crop_size=224), + dict(type='mmcls.PackClsInputs'), +] + +train_dataloader = dict( + batch_size=128, + num_workers=4, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/train.txt', + data_prefix='train', + pipeline=train_pipeline), + sampler=dict(type='mmcls.DefaultSampler', shuffle=True), + persistent_workers=True, +) + +val_dataloader = dict( + batch_size=128, + num_workers=4, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/val.txt', + data_prefix='val', + pipeline=test_pipeline), + sampler=dict(type='mmcls.DefaultSampler', shuffle=False), + persistent_workers=True, +) +val_evaluator = dict(type='mmcls.Accuracy', topk=(1, 5)) + +# If you want standard test, please manually configure the test dataset +test_dataloader = val_dataloader +test_evaluator = val_evaluator + +# optimizer +paramwise_cfg = dict(bias_decay_mult=0.0, norm_decay_mult=0.0) + +optim_wrapper = dict( + constructor='mmrazor.SeparateOptimWrapperConstructor', + architecture=dict( + optimizer=dict( + type='mmcls.SGD', lr=0.5, momentum=0.9, weight_decay=4e-5), + paramwise_cfg=paramwise_cfg), + mutator=dict( + optimizer=dict( + type='mmcls.Adam', lr=0.001, weight_decay=0.0, betas=(0.5, + 0.999)))) + +search_epochs = 85 +# leanring policy +param_scheduler = dict( + architecture=[ + dict( + type='mmcls.LinearLR', + end=5, + start_factor=0.2, + by_epoch=True, + convert_to_iter_based=True), + dict( + type='mmcls.CosineAnnealingLR', + T_max=240, + begin=5, + end=search_epochs, + by_epoch=True, + convert_to_iter_based=True), + dict( + type='mmcls.CosineAnnealingLR', + T_max=160, + begin=search_epochs, + end=240, + eta_min=0.0, + by_epoch=True, + convert_to_iter_based=True) + ], + mutator=[]) + +# train, val, test setting +train_cfg = dict(by_epoch=True, max_epochs=240) +val_cfg = dict() +test_cfg = dict() diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_spos.py b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_spos.py new file mode 100755 index 000000000..1ae2fcd60 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_spos.py @@ -0,0 +1,83 @@ +# dataset settings +dataset_type = 'mmcls.ImageNet' +preprocess_cfg = dict( + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True, +) + +train_pipeline = [ + dict(_scope_='mmcls', type='LoadImageFromFile'), + dict(_scope_='mmcls', type='RandomResizedCrop', scale=224), + dict( + _scope_='mmcls', + type='ColorJitter', + brightness=0.4, + contrast=0.4, + saturation=0.4), + dict(_scope_='mmcls', type='RandomFlip', prob=0.5, direction='horizontal'), + dict(_scope_='mmcls', type='PackClsInputs'), +] + +test_pipeline = [ + dict(_scope_='mmcls', type='LoadImageFromFile'), + dict(_scope_='mmcls', type='ResizeEdge', scale=256, edge='short'), + dict(_scope_='mmcls', type='CenterCrop', crop_size=224), + dict(_scope_='mmcls', type='PackClsInputs'), +] + +train_dataloader = dict( + batch_size=128, + num_workers=4, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/train.txt', + data_prefix='train', + pipeline=train_pipeline), + sampler=dict(type='DefaultSampler', shuffle=True), + persistent_workers=True, +) + +val_dataloader = dict( + batch_size=128, + num_workers=4, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/val.txt', + data_prefix='val', + pipeline=test_pipeline), + sampler=dict(type='DefaultSampler', shuffle=False), + persistent_workers=True, +) +val_evaluator = dict(type='Accuracy', topk=(1, 5), _scope_='mmcls') + +# If you want standard test, please manually configure the test dataset +test_dataloader = val_dataloader +test_evaluator = val_evaluator + +# optimizer +paramwise_cfg = dict( + bias_decay_mult=0.0, norm_decay_mult=0.0, dwconv_decay_mult=0.0) + +optim_wrapper = dict( + optimizer=dict(type='SGD', lr=0.5, momentum=0.9, weight_decay=4e-5), + paramwise_cfg=paramwise_cfg, + clip_grad=None) + +# leanring policy +param_scheduler = dict( + type='PolyLR', + power=1.0, + eta_min=0.0, + by_epoch=True, + end=300, + convert_to_iter_based=True) + +# train, val, test setting +train_cfg = dict(by_epoch=True, max_epochs=300) +val_cfg = dict() +test_cfg = dict() diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_AdamW.py b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_AdamW.py new file mode 100755 index 000000000..7b7b29097 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_AdamW.py @@ -0,0 +1,180 @@ +# dataset settings +dataset_type = 'mmcls.ImageNet' +preprocess_cfg = dict( + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True, +) + +bgr_mean = preprocess_cfg['mean'][::-1] +bgr_std = preprocess_cfg['std'][::-1] + +# Refers to `_RAND_INCREASING_TRANSFORMS` in pytorch-image-models +rand_increasing_policies = [ + dict(type='mmcls.AutoContrast'), + dict(type='mmcls.Equalize'), + dict(type='mmcls.Invert'), + dict(type='mmcls.Rotate', magnitude_key='angle', magnitude_range=(0, 30)), + dict(type='mmcls.Posterize', magnitude_key='bits', magnitude_range=(4, 0)), + dict(type='mmcls.Solarize', magnitude_key='thr', magnitude_range=(256, 0)), + dict( + type='mmcls.SolarizeAdd', + magnitude_key='magnitude', + magnitude_range=(0, 110)), + dict( + type='mmcls.ColorTransform', + magnitude_key='magnitude', + magnitude_range=(0, 0.9)), + dict( + type='mmcls.Contrast', + magnitude_key='magnitude', + magnitude_range=(0, 0.9)), + dict( + type='mmcls.Brightness', + magnitude_key='magnitude', + magnitude_range=(0, 0.9)), + dict( + type='mmcls.Sharpness', + magnitude_key='magnitude', + magnitude_range=(0, 0.9)), + dict( + type='mmcls.Shear', + magnitude_key='magnitude', + magnitude_range=(0, 0.3), + direction='horizontal'), + dict( + type='mmcls.Shear', + magnitude_key='magnitude', + magnitude_range=(0, 0.3), + direction='vertical'), + dict( + type='mmcls.Translate', + magnitude_key='magnitude', + magnitude_range=(0, 0.45), + direction='horizontal'), + dict( + type='mmcls.Translate', + magnitude_key='magnitude', + magnitude_range=(0, 0.45), + direction='vertical') +] + +train_pipeline = [ + dict(type='mmcls.LoadImageFromFile'), + dict( + type='mmcls.RandomResizedCrop', + scale=224, + backend='pillow', + interpolation='bicubic'), + dict(type='mmcls.RandomFlip', prob=0.5, direction='horizontal'), + dict( + type='mmcls.RandAugment', + policies=rand_increasing_policies, + num_policies=2, + total_level=10, + magnitude_level=9, + magnitude_std=0.5, + hparams=dict( + pad_val=[round(x) for x in bgr_mean], interpolation='bicubic')), + dict( + type='mmcls.RandomErasing', + erase_prob=0.25, + mode='rand', + min_area_ratio=0.02, + max_area_ratio=1 / 3, + fill_color=bgr_mean, + fill_std=bgr_std), + dict(type='mmcls.PackClsInputs'), +] + +test_pipeline = [ + dict(type='mmcls.LoadImageFromFile'), + dict( + type='mmcls.ResizeEdge', + scale=248, + edge='short', + backend='pillow', + interpolation='bicubic'), + dict(type='mmcls.CenterCrop', crop_size=224), + dict(type='mmcls.PackClsInputs') +] + +train_dataloader = dict( + batch_size=64, + num_workers=6, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/train.txt', + data_prefix='train', + pipeline=train_pipeline), + sampler=dict(type='mmcls.RepeatAugSampler'), + persistent_workers=True, +) + +val_dataloader = dict( + batch_size=256, + num_workers=6, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/val.txt', + data_prefix='val', + pipeline=test_pipeline), + sampler=dict(type='mmcls.DefaultSampler', shuffle=False), + persistent_workers=True, +) +val_evaluator = dict(type='mmcls.Accuracy', topk=(1, 5)) + +# If you want standard test, please manually configure the test dataset +test_dataloader = val_dataloader +test_evaluator = val_evaluator + +# optimizer +paramwise_cfg = dict( + bias_decay_mult=0.0, norm_decay_mult=0.0, dwconv_decay_mult=0.0) + +optim_wrapper = dict( + optimizer=dict( + type='AdamW', + lr=0.002, + weight_decay=0.05, + eps=1e-8, + betas=(0.9, 0.999)), + # specific to vit pretrain + paramwise_cfg=dict(custom_keys={ + '.cls_token': dict(decay_mult=0.0), + '.pos_embed': dict(decay_mult=0.0) + })) + +# leanring policy +param_scheduler = [ + # warm up learning rate scheduler + dict( + type='LinearLR', + start_factor=1e-3, + by_epoch=True, + begin=0, + # about 10000 iterations for ImageNet-1k + end=20, + # update by iter + convert_to_iter_based=True), + # main learning rate scheduler + dict( + type='CosineAnnealingLR', + T_max=500, + eta_min=1e-5, + by_epoch=True, + begin=20, + end=500, + convert_to_iter_based=True), +] + +# train, val, test setting +train_cfg = dict(by_epoch=True, max_epochs=500) +val_cfg = dict() +test_cfg = dict() + +auto_scale_lr = dict(base_batch_size=2048) diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim.py b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim.py new file mode 100755 index 000000000..120258763 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim.py @@ -0,0 +1,15 @@ +_base_ = [ + './imagenet_bs1024_spos.py', +] + +_RandomResizedCrop_cfg = _base_.train_dataloader.dataset.pipeline[1] +assert _RandomResizedCrop_cfg.type == 'RandomResizedCrop' +_RandomResizedCrop_cfg.crop_ratio_range = (0.25, 1.0) + +optim_wrapper = dict(optimizer=dict(weight_decay=1e-4, nesterov=True)) + +train_dataloader = dict(batch_size=256) + +val_dataloader = dict(batch_size=256) + +test_dataloader = dict(batch_size=256) diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim_pil.py b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim_pil.py new file mode 100755 index 000000000..90a88cb1f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim_pil.py @@ -0,0 +1,13 @@ +_base_ = 'imagenet_bs2048_autoslim.py' + +_RandomResizedCrop_cfg = _base_.train_dataloader.dataset.pipeline[1] +assert _RandomResizedCrop_cfg.type == 'RandomResizedCrop' +_RandomResizedCrop_cfg.backend = 'pillow' + +_ResizeEdge_cfg_val = _base_.val_dataloader.dataset.pipeline[1] +assert _ResizeEdge_cfg_val.type == 'ResizeEdge' +_ResizeEdge_cfg_val.backend = 'pillow' + +_ResizeEdge_cfg_test = _base_.test_dataloader.dataset.pipeline[1] +assert _ResizeEdge_cfg_test.type == 'ResizeEdge' +_ResizeEdge_cfg_test.backend = 'pillow' diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_bignas.py b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_bignas.py new file mode 100755 index 000000000..617b72ef1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_bignas.py @@ -0,0 +1,400 @@ +# dataset settings +dataset_type = 'mmcls.ImageNet' + +# data preprocessor +data_preprocessor = dict( + type='mmcls.ClsDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True, +) + +bgr_mean = data_preprocessor['mean'][::-1] +bgr_std = data_preprocessor['std'][::-1] + +extra_params = dict( + translate_const=int(224 * 0.45), + img_mean=tuple(round(x) for x in data_preprocessor['mean']), +) +policies = [ + [ + dict( + type='mmrazor.EqualizeV2', + prob=0.8, + magnitude=1, + extra_params=extra_params), + dict( + type='mmrazor.ShearY', + prob=0.8, + magnitude=4, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.Color', + prob=0.4, + magnitude=9, + extra_params=extra_params), + dict( + type='mmrazor.EqualizeV2', + prob=0.6, + magnitude=3, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.Color', + prob=0.4, + magnitude=1, + extra_params=extra_params), + dict( + type='mmrazor.RotateV2', + prob=0.6, + magnitude=8, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.SolarizeV2', + prob=0.8, + magnitude=3, + extra_params=extra_params), + dict( + type='mmrazor.EqualizeV2', + prob=0.4, + magnitude=7, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.SolarizeV2', + prob=0.4, + magnitude=2, + extra_params=extra_params), + dict( + type='mmrazor.SolarizeV2', + prob=0.6, + magnitude=2, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.Color', + prob=0.2, + magnitude=0, + extra_params=extra_params), + dict( + type='mmrazor.EqualizeV2', + prob=0.8, + magnitude=8, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.EqualizeV2', + prob=0.4, + magnitude=8, + extra_params=extra_params), + dict( + type='mmrazor.SolarizeAddV2', + prob=0.8, + magnitude=3, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.ShearX', + prob=0.2, + magnitude=9, + extra_params=extra_params), + dict( + type='mmrazor.RotateV2', + prob=0.6, + magnitude=8, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.Color', + prob=0.6, + magnitude=1, + extra_params=extra_params), + dict( + type='mmrazor.EqualizeV2', + prob=1.0, + magnitude=2, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.InvertV2', + prob=0.4, + magnitude=9, + extra_params=extra_params), + dict( + type='mmrazor.RotateV2', + prob=0.6, + magnitude=0, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.EqualizeV2', + prob=1.0, + magnitude=9, + extra_params=extra_params), + dict( + type='mmrazor.ShearY', + prob=0.6, + magnitude=3, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.Color', + prob=0.4, + magnitude=7, + extra_params=extra_params), + dict( + type='mmrazor.EqualizeV2', + prob=0.6, + magnitude=0, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.PosterizeV2', + prob=0.4, + magnitude=6, + extra_params=extra_params), + dict( + type='mmrazor.AutoContrastV2', + prob=0.4, + magnitude=7, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.SolarizeV2', + prob=0.6, + magnitude=8, + extra_params=extra_params), + dict( + type='mmrazor.Color', + prob=0.6, + magnitude=9, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.SolarizeV2', + prob=0.2, + magnitude=4, + extra_params=extra_params), + dict( + type='mmrazor.RotateV2', + prob=0.8, + magnitude=9, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.RotateV2', + prob=1.0, + magnitude=7, + extra_params=extra_params), + dict( + type='mmrazor.TranslateYRel', + prob=0.8, + magnitude=9, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.ShearX', + prob=0.0, + magnitude=0, + extra_params=extra_params), + dict( + type='mmrazor.SolarizeV2', + prob=0.8, + magnitude=4, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.ShearY', + prob=0.8, + magnitude=0, + extra_params=extra_params), + dict( + type='mmrazor.Color', + prob=0.6, + magnitude=4, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.Color', + prob=1.0, + magnitude=0, + extra_params=extra_params), + dict( + type='mmrazor.RotateV2', + prob=0.6, + magnitude=2, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.EqualizeV2', + prob=0.8, + magnitude=4, + extra_params=extra_params), + dict( + type='mmrazor.EqualizeV2', + prob=0.0, + magnitude=8, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.EqualizeV2', + prob=1.0, + magnitude=4, + extra_params=extra_params), + dict( + type='mmrazor.AutoContrastV2', + prob=0.6, + magnitude=2, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.ShearY', + prob=0.4, + magnitude=7, + extra_params=extra_params), + dict( + type='mmrazor.SolarizeAddV2', + prob=0.6, + magnitude=7, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.PosterizeV2', + prob=0.8, + magnitude=2, + extra_params=extra_params), + dict( + type='mmrazor.SolarizeV2', + prob=0.6, + magnitude=10, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.SolarizeV2', + prob=0.6, + magnitude=8, + extra_params=extra_params), + dict( + type='mmrazor.EqualizeV2', + prob=0.6, + magnitude=1, + extra_params=extra_params), + ], + [ + dict( + type='mmrazor.Color', + prob=0.8, + magnitude=6, + extra_params=extra_params), + dict( + type='mmrazor.RotateV2', + prob=0.4, + magnitude=5, + extra_params=extra_params), + ], +] + +train_pipeline = [ + dict(type='mmcls.LoadImageFromFile'), + dict(type='mmcls.RandomResizedCrop', scale=224, backend='pillow'), + dict(type='mmcls.RandomFlip', prob=0.5, direction='horizontal'), + dict(type='mmrazor.AutoAugmentV2', policies=policies), + dict(type='mmcls.PackClsInputs'), +] + +test_pipeline = [ + dict(type='mmcls.LoadImageFromFile'), + dict( + type='mmcls.ResizeEdge', + scale=256, + edge='short', + backend='pillow', + interpolation='bilinear'), + dict(type='mmcls.CenterCrop', crop_size=224), + dict(type='mmcls.PackClsInputs') +] + +train_dataloader = dict( + batch_size=64, + num_workers=16, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/train.txt', + data_prefix='train', + pipeline=train_pipeline), + sampler=dict(type='mmcls.RepeatAugSampler', shuffle=True), + persistent_workers=True, +) + +val_dataloader = dict( + batch_size=64, + num_workers=16, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/val.txt', + data_prefix='val', + pipeline=test_pipeline), + sampler=dict(type='mmcls.DefaultSampler', shuffle=False), + persistent_workers=True, +) +val_evaluator = dict(type='mmcls.Accuracy', topk=(1, 5)) + +# If you want standard test, please manually configure the test dataset +test_dataloader = val_dataloader +test_evaluator = val_evaluator + +# optimizer +optim_wrapper = dict( + optimizer=dict( + type='SGD', lr=0.8, momentum=0.9, weight_decay=0.00001, nesterov=True), + paramwise_cfg=dict(bias_decay_mult=0., norm_decay_mult=0.)) + +# learning policy +max_epochs = 360 +param_scheduler = [ + dict( + type='LinearLR', start_factor=0.001, by_epoch=False, begin=0, + end=3125), + dict( + type='CosineAnnealingLR', + T_max=max_epochs, + eta_min=0, + by_epoch=True, + begin=0, + end=max_epochs, + convert_to_iter_based=True) +] + +# train, val, test setting +train_cfg = dict(by_epoch=True, max_epochs=max_epochs, val_interval=1) +val_cfg = dict(type='mmrazor.SubnetValLoop', calibrate_sample_num=4096) +test_cfg = dict(type='mmrazor.SubnetValLoop', calibrate_sample_num=4096) diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_dmcp.py b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_dmcp.py new file mode 100755 index 000000000..3532423fc --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_dmcp.py @@ -0,0 +1,98 @@ +# dataset settings +dataset_type = 'mmcls.ImageNet' + +max_search_epochs = 100 +# learning rate setting +param_scheduler = [ + # warm up learning rate scheduler + dict( + type='LinearLR', + start_factor=0.5, + by_epoch=True, + begin=0, + end=10, + convert_to_iter_based=True), + dict( + type='CosineAnnealingLR', + T_max=max_search_epochs, + eta_min=0.08, + by_epoch=True, + begin=10, + end=max_search_epochs, + convert_to_iter_based=True), +] + +# optimizer setting +paramwise_cfg = dict(norm_decay_mult=0.0, bias_decay_mult=0.0) + +optim_wrapper = dict( + constructor='mmrazor.SeparateOptimWrapperConstructor', + architecture=dict( + type='OptimWrapper', + optimizer=dict(type='SGD', lr=0.5, momentum=0.9, weight_decay=3e-4), + paramwise_cfg=paramwise_cfg), + mutator=dict( + type='OptimWrapper', + optimizer=dict(type='Adam', lr=0.5, weight_decay=1e-3))) + +# data preprocessor +data_preprocessor = dict( + type='mmcls.ClsDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True, +) +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='RandomResizedCrop', scale=224), + dict(type='ColorJitter', brightness=0.2, contrast=0.2, saturation=0.2), + dict(type='RandomFlip', prob=0.5, direction='horizontal'), + dict(type='PackClsInputs'), +] + +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='ResizeEdge', scale=256, edge='short'), + dict(type='CenterCrop', crop_size=224), + dict(type='PackClsInputs'), +] + +train_dataloader = dict( + batch_size=64, + num_workers=4, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/train.txt', + data_prefix='train', + pipeline=train_pipeline), + sampler=dict(type='DefaultSampler', shuffle=True, _scope_='mmcls'), + persistent_workers=True, +) + +val_dataloader = dict( + batch_size=64, + num_workers=4, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/val.txt', + data_prefix='val', + pipeline=test_pipeline), + sampler=dict(type='DefaultSampler', shuffle=True, _scope_='mmcls'), + persistent_workers=True, +) +val_evaluator = dict(type='mmcls.Accuracy', topk=(1, 5)) + +# If you want standard test, please manually configure the test dataset +test_dataloader = val_dataloader +test_evaluator = val_evaluator + +evaluation = dict(interval=1, metric='accuracy') + +train_cfg = dict(by_epoch=True, max_epochs=max_search_epochs, val_interval=1) +val_cfg = dict() +test_cfg = dict() +custom_hooks = [dict(type='DMCPSubnetHook')] diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_ofa.py b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_ofa.py new file mode 100755 index 000000000..fe9ff75b4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_ofa.py @@ -0,0 +1,98 @@ +# dataset settings +dataset_type = 'mmcls.ImageNet' + +# data preprocessor +data_preprocessor = dict( + type='mmcls.ClsDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True, +) + +bgr_mean = data_preprocessor['mean'][::-1] +bgr_std = data_preprocessor['std'][::-1] + +extra_params = dict( + translate_const=int(224 * 0.45), + img_mean=tuple(round(x) for x in data_preprocessor['mean']), +) + +train_pipeline = [ + dict(type='mmcls.LoadImageFromFile'), + dict(type='mmcls.RandomResizedCrop', scale=224), + dict(type='mmcls.RandomFlip', prob=0.5, direction='horizontal'), + dict(type='mmcls.ColorJitter', brightness=0.1254, saturation=0.5), + dict(type='mmcls.PackClsInputs'), +] + +test_pipeline = [ + dict(type='mmcls.LoadImageFromFile'), + dict( + type='mmcls.ResizeEdge', + scale=256, + edge='short', + backend='pillow', + interpolation='bilinear'), + dict(type='mmcls.CenterCrop', crop_size=224), + dict(type='mmcls.PackClsInputs') +] + +train_dataloader = dict( + batch_size=64, + num_workers=16, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/train.txt', + data_prefix='train', + pipeline=train_pipeline), + sampler=dict(type='mmcls.RepeatAugSampler', shuffle=True), + persistent_workers=True, +) + +val_dataloader = dict( + batch_size=64, + num_workers=16, + dataset=dict( + type=dataset_type, + data_root='data/imagenet', + ann_file='meta/val.txt', + data_prefix='val', + pipeline=test_pipeline), + sampler=dict(type='mmcls.DefaultSampler', shuffle=False), + persistent_workers=True, +) +val_evaluator = dict(type='mmcls.Accuracy', topk=(1, 5)) + +# If you want standard test, please manually configure the test dataset +test_dataloader = val_dataloader +test_evaluator = val_evaluator + +# optimizer +optim_wrapper = dict( + optimizer=dict( + type='SGD', lr=0.8, momentum=0.9, weight_decay=0.00001, nesterov=True), + paramwise_cfg=dict(bias_decay_mult=0., norm_decay_mult=0.)) + +# learning policy +max_epochs = 360 +param_scheduler = [ + dict( + type='LinearLR', start_factor=0.001, by_epoch=False, begin=0, + end=3125), + dict( + type='CosineAnnealingLR', + T_max=max_epochs, + eta_min=0, + by_epoch=True, + begin=0, + end=max_epochs, + convert_to_iter_based=True) +] + +# train, val, test setting +train_cfg = dict(by_epoch=True, max_epochs=max_epochs, val_interval=1) +val_cfg = dict(type='mmrazor.SubnetValLoop', calibrate_sample_num=4096) +test_cfg = dict(type='mmrazor.SubnetValLoop', calibrate_sample_num=4096) diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/vanilla_models/wrn16_2_cifar10.py b/cv/distiller/CWD/mmrazor/configs/_base_/vanilla_models/wrn16_2_cifar10.py new file mode 100755 index 000000000..4e0a83bf5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/_base_/vanilla_models/wrn16_2_cifar10.py @@ -0,0 +1,20 @@ +model = dict( + _scope_='mmcls', + type='ImageClassifier', + backbone=dict( + _scope_='mmrazor', + type='WideResNet', + depth=16, + num_stages=3, + widen_factor=2, + ), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=10, + in_channels=128, + loss=dict(type='CrossEntropyLoss', loss_weight=1.0), + topk=(1, 5), + )) + +find_unused_parameters = True diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/README.md new file mode 100755 index 000000000..1e6e19512 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/README.md @@ -0,0 +1,69 @@ +# Activation Boundaries Loss (ABLoss) + +> [Knowledge Transfer via Distillation of Activation Boundaries Formed by Hidden Neurons](https://arxiv.org/pdf/1811.03233.pdf) + + + +## Abstract + +An activation boundary for a neuron refers to a separating hyperplane that determines whether the neuron is activated or deactivated. It has been long considered in neural networks that the activations of neurons, rather than their exact output values, play the most important role in forming classification friendly partitions of the hidden feature space. However, as far as we know, this aspect of neural networks has not been considered in the literature of knowledge transfer. In this pa- per, we propose a knowledge transfer method via distillation of activation boundaries formed by hidden neurons. For the distillation, we propose an activation transfer loss that has the minimum value when the boundaries generated by the stu- dent coincide with those by the teacher. Since the activation transfer loss is not differentiable, we design a piecewise differentiable loss approximating the activation transfer loss. By the proposed method, the student learns a separating bound- ary between activation region and deactivation region formed by each neuron in the teacher. Through the experiments in various aspects of knowledge transfer, it is verified that the proposed method outperforms the current state-of-the-art [link](https://github.com/bhheo/AB_distillation) + +pipeline + +## Results and models + +### Classification + +| Location | Dataset | Teacher | Student | Acc | Acc(T) | Acc(S) | Config | Download | +| :-----------------: | :------: | :----------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------: | :---: | :----: | :----: | :------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| backbone (pretrain) | ImageNet | [resnet50](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet50_8xb32_in1k.py) | [resnet18](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet18_8xb32_in1k.py) | | 76.55 | 69.90 | [pretrain_config](./abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/ABLoss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k_20220830_165724-a6284e9f.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/ABLoss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k_20220830_165724-a6284e9f.json) | +| logits (train) | ImageNet | [resnet50](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet50_8xb32_in1k.py) | [resnet18](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet18_8xb32_in1k.py) | 69.94 | 76.55 | 69.90 | [train_config](./abloss_logits_resnet50_resnet18_8xb32_in1k.py) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/ABLoss/abloss_logits_resnet50_resnet18_8xb32_in1k_20220830_202129-f35edde8.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/ABLoss/abloss_logits_resnet50_resnet18_8xb32_in1k_20220830_202129-f35edde8.json) | + +## Citation + +```latex +@inproceedings{DBLP:conf/aaai/HeoLY019a, + author = {Byeongho Heo, Minsik Lee, Sangdoo Yun and Jin Young Choi}, + title = {Knowledge Transfer via Distillation of Activation Boundaries Formed + by Hidden Neurons}, + booktitle = {The Thirty-Third {AAAI} Conference on Artificial Intelligence, {AAAI} + 2019, The Thirty-First Innovative Applications of Artificial Intelligence + Conference, {IAAI} 2019, The Ninth {AAAI} Symposium on Educational + Advances in Artificial Intelligence, {EAAI} 2019, Honolulu, Hawaii, + USA, January 27 - February 1, 2019}, + pages = {3779--3787}, + publisher = {{AAAI} Press}, + year = {2019}, + url = {https://doi.org/10.1609/aaai.v33i01.33013779}, + doi = {10.1609/aaai.v33i01.33013779}, + timestamp = {Fri, 07 May 2021 11:57:04 +0200}, + biburl = {https://dblp.org/rec/conf/aaai/HeoLY019a.bib}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} +``` + +## Getting Started + +### Pre-training. + +```bash +sh tools/dist_train.sh configs/distill/mmcls/abloss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k.py 8 +``` + +### Modify Distillation training config + +open file 'configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py' + +```python +# Modify init_cfg in model settings. +# 'pretrain_work_dir' is same as the 'work_dir of pre-training'. +# 'last_epoch' defaults to 'epoch_20' in ABLoss. +init_cfg=dict( + type='Pretrained', checkpoint='pretrain_work_dir/last_epoch.pth'), +``` + +### Distillation training. + +```bash +sh tools/dist_train.sh configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py 8 +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py new file mode 100755 index 000000000..e1e9c3a7c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py @@ -0,0 +1,40 @@ +_base_ = [ + 'mmcls::_base_/datasets/imagenet_bs32.py', + 'mmcls::_base_/schedules/imagenet_bs256.py', + 'mmcls::_base_/default_runtime.py' +] + +# Modify pretrain_checkpoint before training. +pretrain_checkpoint = 'work_dir_of_abloss_pretrain/last_epoch.pth' +model = dict( + _scope_='mmrazor', + type='SingleTeacherDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb32_in1k.py', pretrained=False), + teacher=dict( + cfg_path='mmcls::resnet/resnet50_8xb32_in1k.py', pretrained=False), + init_cfg=dict(type='Pretrained', checkpoint=pretrain_checkpoint), + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict( + type='KLDivergence', loss_weight=6.25, reduction='mean')), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(from_student=True, recorder='fc'), + preds_T=dict(from_student=False, recorder='fc'))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k.py new file mode 100755 index 000000000..fe7fdc82c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k.py @@ -0,0 +1,97 @@ +_base_ = [ + 'mmcls::_base_/datasets/imagenet_bs32.py', + 'mmcls::_base_/schedules/imagenet_bs256.py', + 'mmcls::_base_/default_runtime.py' +] + +teacher_ckpt = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth' # noqa: E501 +model = dict( + _scope_='mmrazor', + type='SingleTeacherDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb32_in1k.py', pretrained=False), + teacher=dict( + cfg_path='mmcls::resnet/resnet50_8xb32_in1k.py', pretrained=True), + teacher_ckpt=teacher_ckpt, + calculate_student_loss=False, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + bb_s4=dict(type='ModuleOutputs', source='backbone.layer4.1.conv2'), + bb_s3=dict(type='ModuleOutputs', source='backbone.layer3.1.conv2'), + bb_s2=dict(type='ModuleOutputs', source='backbone.layer2.1.conv2'), + bb_s1=dict(type='ModuleOutputs', + source='backbone.layer1.1.conv2')), + teacher_recorders=dict( + bb_s4=dict(type='ModuleOutputs', source='backbone.layer4.2.conv3'), + bb_s3=dict(type='ModuleOutputs', source='backbone.layer3.5.conv3'), + bb_s2=dict(type='ModuleOutputs', source='backbone.layer2.3.conv3'), + bb_s1=dict(type='ModuleOutputs', + source='backbone.layer1.2.conv3')), + distill_losses=dict( + loss_s4=dict(type='ABLoss', loss_weight=1.0), + loss_s3=dict(type='ABLoss', loss_weight=0.5), + loss_s2=dict(type='ABLoss', loss_weight=0.25), + loss_s1=dict(type='ABLoss', loss_weight=0.125)), + connectors=dict( + loss_s4_sfeat=dict( + type='ConvModuleConnector', + in_channel=512, + out_channel=2048, + norm_cfg=dict(type='BN'), + act_cfg=None), + loss_s3_sfeat=dict( + type='ConvModuleConnector', + in_channel=256, + out_channel=1024, + norm_cfg=dict(type='BN'), + act_cfg=None), + loss_s2_sfeat=dict( + type='ConvModuleConnector', + in_channel=128, + out_channel=512, + norm_cfg=dict(type='BN'), + act_cfg=None), + loss_s1_sfeat=dict( + type='ConvModuleConnector', + in_channel=64, + out_channel=256, + norm_cfg=dict(type='BN'), + act_cfg=None)), + loss_forward_mappings=dict( + loss_s4=dict( + s_feature=dict( + from_student=True, + recorder='bb_s4', + connector='loss_s4_sfeat'), + t_feature=dict(from_student=False, recorder='bb_s4')), + loss_s3=dict( + s_feature=dict( + from_student=True, + recorder='bb_s3', + connector='loss_s3_sfeat'), + t_feature=dict(from_student=False, recorder='bb_s3')), + loss_s2=dict( + s_feature=dict( + from_student=True, + recorder='bb_s2', + connector='loss_s2_sfeat'), + t_feature=dict(from_student=False, recorder='bb_s2')), + loss_s1=dict( + s_feature=dict( + from_student=True, + recorder='bb_s1', + connector='loss_s1_sfeat'), + t_feature=dict(from_student=False, recorder='bb_s1'))))) + +find_unused_parameters = True + +train_cfg = dict(by_epoch=True, max_epochs=20, val_interval=1) +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/metafile.yml new file mode 100755 index 000000000..df230a9c9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/metafile.yml @@ -0,0 +1,36 @@ +Collections: + - Name: ABLoss + Metadata: + Training Data: + - ImageNet-1k + Paper: + URL: https://arxiv.org/pdf/1811.03233.pdf + Title: Knowledge Transfer via Distillation of Activation Boundaries Formed by Hidden Neurons + README: configs/distill/mmcls/abloss/README.md + Converted From: + Code: + URL: https://github.com/bhheo/AB_distillation +Models: + - Name: abloss_logits_resnet50_resnet18_8xb32_in1k + In Collection: ABLoss + Metadata: + Location: logits + Student: + Config: mmcls::resnet/resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth + Metrics: + Top 1 Accuracy: 69.90 + Top 5 Accuracy: 89.43 + Teacher: + Config: mmcls::resnet/resnet50_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth + Metrics: + Top 1 Accuracy: 76.55 + Top 5 Accuracy: 93.06 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 69.94 + Config: configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/ABLoss/abloss_logits_resnet50_resnet18_8xb32_in1k_20220830_202129-f35edde8.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/README.md new file mode 100755 index 000000000..95d82ecb5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/README.md @@ -0,0 +1,57 @@ +# BYOT + +> [Be Your Own Teacher: Improve the Performance of Convolutional Neural Networks via Self Distillation](https://arxiv.org/abs/1905.08094) + + + +## Abstract + +Convolutional neural networks have been widely deployed in various application scenarios. In order to extend the applications' boundaries to some accuracy-crucial domains, researchers have been investigating approaches to boost accuracy through either deeper or wider network structures, which brings with them the exponential increment of the computational and storage cost, delaying the responding time. In this paper, we propose a general training framework named self distillation, which notably enhances the performance (accuracy) of convolutional neural networks through shrinking the size of the network rather than aggrandizing it. Different from traditional knowledge distillation - a knowledge transformation methodology among networks, which forces student neural networks to approximate the softmax layer outputs of pre-trained teacher neural networks, the proposed self distillation framework distills knowledge within network itself. The networks are firstly divided into several sections. Then the knowledge in the deeper portion of the networks is squeezed into the shallow ones. Experiments further prove the generalization of the proposed self distillation framework: enhancement of accuracy at average level is 2.65%, varying from 0.61% in ResNeXt as minimum to 4.07% in VGG19 as maximum. In addition, it can also provide flexibility of depth-wise scalable inference on resource-limited edge devices.Our codes will be released on github soon. [Unofficial code](https://github.com/luanyunteng/pytorch-be-your-own-teacher) + +## Pipeline + +![byot](https://user-images.githubusercontent.com/88702197/187422992-e7bd692d-b6d4-44d8-8b36-741e0cf1c4f6.png) + +## Results and models + +#### Classification + +| Location | Dataset | Model | Params(M) | Flops(G) | Top-1 (%) | Top-5 (%) | Download | +| :------: | :------: | :-------------------------------------------: | :-------: | :------: | :-------: | :-------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| logits | CIFAR100 | [R18_BYOT](./byot_resnet18_8xb16_cifar100.py) | 11.22 | 0.56 | 80.66 | 95.76 | [model](https://download.openmmlab.com/mmrazor/v1/byot/byot_resnet18_8xb16_cifar100_20220817_191217-0251084e.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/byot/byot_resnet18_8xb16_cifar100_20220817_191217-0251084e.json) | + +## Citation + +```latex +@ARTICLE{2019arXiv190508094Z, + author = {{Zhang}, Linfeng and {Song}, Jiebo and {Gao}, Anni and {Chen}, Jingwei and {Bao}, Chenglong and {Ma}, Kaisheng}, + title = {Be Your Own Teacher: Improve the Performance of Convolutional Neural Networks via Self Distillation}, + journal = {arXiv e-prints}, + keywords = {Computer Science - Machine Learning, Statistics - Machine Learning}, + year = 2019, + month = may, + eid = {arXiv:1905.08094}, + pages = {arXiv:1905.08094}, +archivePrefix = {arXiv}, + eprint = {1905.08094}, + primaryClass = {cs.LG}, + adsurl = {https://ui.adsabs.harvard.edu/abs/2019arXiv190508094Z}, + adsnote = {Provided by the SAO/NASA Astrophysics Data System} +} +``` + +## Get Started + +### Distillation training. + +```bash +sh tools/dist_train.sh \ + configs/distill/mmcls/byot/byot_logits_resnet18_cifar100_8xb16_in1k.py 8 +``` + +### Test + +```bash +sh tools/dist_train.sh \ + configs/distill/mmcls/byot/byot_logits_resnet18_cifar100_8xb16_in1k.py 8 +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/byot_resnet18_8xb16_cifar100.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/byot_resnet18_8xb16_cifar100.py new file mode 100755 index 000000000..9f5fc8b7f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/byot_resnet18_8xb16_cifar100.py @@ -0,0 +1,155 @@ +_base_ = [ + '../../../_base_/datasets/mmcls/cifar100_bs16_auto_aug.py', + 'mmcls::_base_/schedules/cifar10_bs128.py', + 'mmcls::_base_/default_runtime.py' +] + +optim_wrapper = dict( + optimizer=dict(type='SGD', lr=0.1, momentum=0.9, weight_decay=0.0005)) +param_scheduler = dict( + type='MultiStepLR', by_epoch=True, milestones=[80, 160, 240], gamma=0.1) +train_cfg = dict(by_epoch=True, max_epochs=250, val_interval=1) + +model = dict( + _scope_='mmrazor', + type='SelfDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[129.304, 124.070, 112.434], + std=[68.170, 65.392, 70.418], + # convert image from BGR to RGB + bgr_to_rgb=False), + architecture=dict( + type='mmcls.ImageClassifier', + backbone=dict( + type='mmcls.ResNet_CIFAR', + depth=18, + num_stages=4, + out_indices=(3, ), + style='pytorch'), + neck=dict(type='mmcls.GlobalAveragePooling'), + head=dict( + type='mmcls.LinearClsHead', + num_classes=100, + in_channels=512, + loss=dict(type='mmcls.CrossEntropyLoss', loss_weight=1.0))), + distiller=dict( + type='BYOTDistiller', + student_recorders=dict( + bb_s1=dict(type='ModuleOutputs', source='backbone.layer1.1.relu'), + bb_s2=dict(type='ModuleOutputs', source='backbone.layer2.1.relu'), + bb_s3=dict(type='ModuleOutputs', source='backbone.layer3.1.relu')), + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc'), + neck_gap=dict(type='ModuleOutputs', source='neck.gap'), + gt_labels=dict(type='ModuleInputs', source='head.loss_module')), + distill_losses=dict( + loss_fet_1=dict( + type='L2Loss', normalize=False, loss_weight=0.03, dist=True), + loss_label_1=dict(type='mmcls.CrossEntropyLoss', loss_weight=0.7), + loss_softl_1=dict(type='KLDivergence', tau=3, loss_weight=0.3), + loss_fet_2=dict( + type='L2Loss', normalize=False, loss_weight=0.03, dist=True), + loss_label_2=dict(type='mmcls.CrossEntropyLoss', loss_weight=0.7), + loss_softl_2=dict(type='KLDivergence', tau=3, loss_weight=0.3), + loss_fet_3=dict( + type='L2Loss', normalize=False, loss_weight=0., dist=True), + loss_label_3=dict(type='mmcls.CrossEntropyLoss', loss_weight=0.7), + loss_softl_3=dict(type='KLDivergence', tau=3, loss_weight=0.3)), + connectors=dict( + loss_s1_sfeat=dict( + type='BYOTConnector', + in_channel=64, + out_channel=512, + expansion=1, + kernel_size=3, + stride=2, + num_classes=100), + loss_s2_sfeat=dict( + type='BYOTConnector', + in_channel=128, + out_channel=512, + expansion=1, + kernel_size=3, + stride=2, + num_classes=100), + loss_s3_sfeat=dict( + type='BYOTConnector', + in_channel=256, + out_channel=512, + expansion=1, + kernel_size=3, + stride=2, + num_classes=100)), + loss_forward_mappings=dict( + loss_fet_1=dict( + s_feature=dict( + recorder='bb_s1', + from_student=True, + connector='loss_s1_sfeat', + connector_idx=0), + t_feature=dict(recorder='neck_gap', from_student=False)), + loss_label_1=dict( + cls_score=dict( + recorder='bb_s1', + from_student=True, + connector='loss_s1_sfeat', + connector_idx=1), + label=dict( + recorder='gt_labels', from_student=False, data_idx=1)), + loss_softl_1=dict( + preds_S=dict( + recorder='bb_s1', + from_student=True, + connector='loss_s1_sfeat', + connector_idx=1), + preds_T=dict(recorder='fc', from_student=False)), + loss_fet_2=dict( + s_feature=dict( + recorder='bb_s2', + from_student=True, + connector='loss_s2_sfeat', + connector_idx=0), + t_feature=dict(recorder='neck_gap', from_student=False)), + loss_label_2=dict( + cls_score=dict( + recorder='bb_s2', + from_student=True, + connector='loss_s2_sfeat', + connector_idx=1), + label=dict( + recorder='gt_labels', from_student=False, data_idx=1)), + loss_softl_2=dict( + preds_S=dict( + recorder='bb_s2', + from_student=True, + connector='loss_s2_sfeat', + connector_idx=1), + preds_T=dict(recorder='fc', from_student=False)), + loss_fet_3=dict( + s_feature=dict( + recorder='bb_s3', + from_student=True, + connector='loss_s3_sfeat', + connector_idx=0), + t_feature=dict(recorder='neck_gap', from_student=False)), + loss_label_3=dict( + cls_score=dict( + recorder='bb_s3', + from_student=True, + connector='loss_s3_sfeat', + connector_idx=1), + label=dict( + recorder='gt_labels', from_student=False, data_idx=1)), + loss_softl_3=dict( + preds_S=dict( + recorder='bb_s3', + from_student=True, + connector='loss_s3_sfeat', + connector_idx=1), + preds_T=dict(recorder='fc', from_student=False))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SelfDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/metafile.yml new file mode 100755 index 000000000..2855dd6e0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/metafile.yml @@ -0,0 +1,31 @@ +Collections: + - Name: BYOT + Metadata: + Training Data: + - CIFAR100 + Paper: + URL: https://arxiv.org/pdf/2107.06916.pdf + Title: Training Compact CNNs for Image Classification using Dynamic-coded Filter Fusion + README: configs/distill/mmcls/byot/README.md + Converted From: + Code: + URL: https://github.com/luanyunteng/pytorch-be-your-own-teacher +Models: + - Name: byot_resnet18_8xb16_cifar100 + In Collection: BYOT + Metadata: + inference time (ms/im): + - value: 0.62 + hardware: V100 + backend: PyTorch + batch size: 16 + mode: FP32 + resolution: (32, 32) + Results: + - Task: Classification + Dataset: CIFAR100 + Metrics: + Top 1 Accuracy: 80.66 + Top 5 Accuracy: 95.76 + Weights: https://download.openmmlab.com/mmrazor/v1/byot/byot_resnet18_8xb16_cifar100_20220817_191217-0251084e.pth + Config: configs/distill/mmcls/byot/byot_resnet18_8xb16_cifar100.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/README.md new file mode 100755 index 000000000..0f02f365e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/README.md @@ -0,0 +1,30 @@ +# CONTRASTIVE REPRESENTATION DISTILLATION + +> [CONTRASTIVE REPRESENTATION DISTILLATION](https://arxiv.org/abs/1910.10699) + +## Abstract + +Often we wish to transfer representational knowledge from one neural network to another. Examples include distilling a large network into a smaller one, transferring knowledge from one sensory modality to a second, or ensembling a collection of models into a single estimator. Knowledge distillation, the standard approach to these problems, minimizes the KL divergence between the probabilistic outputs of a teacher and student network. We demonstrate that this objective ignores important structural knowledge of the teacher network. This motivates an alternative objective by which we train a student to capture signiï¬cantly more information in the teacher’s representation of the data. We formulate this objective as contrastive learning. Experiments demonstrate that our resulting new objective outperforms knowledge distillation and other cutting-edge distillers on a variety of knowledge transfer tasks, including single model compression, ensemble distillation, and cross-modal transfer. Our method sets a new state-of-the-art in many transfer tasks, and sometimes even outperforms the teacher network when combined with knowledge distillation.[Original code](http://github.com/HobbitLong/RepDistiller) + +![pipeline](../../../../docs/en/imgs/model_zoo/crd/pipeline.jpg) + +## Citation + +```latex +@article{tian2019contrastive, + title={Contrastive representation distillation}, + author={Tian, Yonglong and Krishnan, Dilip and Isola, Phillip}, + journal={arXiv preprint arXiv:1910.10699}, + year={2019} +} +``` + +## Results and models + +| Dataset | Model | Teacher | Top-1 (%) | Top-5 (%) | Configs | Download | +| ------- | --------- | --------- | --------- | --------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| CIFAR10 | ResNet-18 | ResNet-50 | 94.79 | 99.86 | [config](crd_neck_r50_r18_8xb16_cifar10.py) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_b16x8_cifar10_20210528-f54bfad9.pth) \|[model](<>) \| [log](<>) | + +## Acknowledgement + +Shout out to @chengshuang18 for his special contribution. diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/crd_neck_r50_r18_8xb16_cifar10.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/crd_neck_r50_r18_8xb16_cifar10.py new file mode 100755 index 000000000..4e36e9a2a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/crd_neck_r50_r18_8xb16_cifar10.py @@ -0,0 +1,108 @@ +_base_ = [ + 'mmcls::_base_/datasets/cifar10_bs16.py', + 'mmcls::_base_/schedules/cifar10_bs128.py', + 'mmcls::_base_/default_runtime.py' +] + +model = dict( + _scope_='mmrazor', + type='SingleTeacherDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb16_cifar10.py', pretrained=False), + teacher=dict( + cfg_path='mmcls::resnet/resnet50_8xb16_cifar10.py', pretrained=True), + teacher_ckpt='resnet50_b16x8_cifar10_20210528-f54bfad9.pth', + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + neck=dict(type='ModuleOutputs', source='neck.gap'), + data_samples=dict(type='ModuleInputs', source='')), + teacher_recorders=dict( + neck=dict(type='ModuleOutputs', source='neck.gap')), + distill_losses=dict(loss_crd=dict(type='CRDLoss', loss_weight=0.8)), + connectors=dict( + loss_crd_stu=dict(type='CRDConnector', dim_in=512, dim_out=128), + loss_crd_tea=dict(type='CRDConnector', dim_in=2048, dim_out=128)), + loss_forward_mappings=dict( + loss_crd=dict( + s_feats=dict( + from_student=True, + recorder='neck', + connector='loss_crd_stu'), + t_feats=dict( + from_student=False, + recorder='neck', + connector='loss_crd_tea'), + data_samples=dict( + from_student=True, recorder='data_samples', data_idx=1))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') + +# change `CIFAR10` dataset to `CRDDataset` dataset. +dataset_type = 'CIFAR10' +train_pipeline = [ + dict(_scope_='mmcls', type='RandomCrop', crop_size=32, padding=4), + dict(_scope_='mmcls', type='RandomFlip', prob=0.5, direction='horizontal'), + dict(_scope_='mmrazor', type='PackCRDClsInputs'), +] + +test_pipeline = [ + dict(_scope_='mmrazor', type='PackCRDClsInputs'), +] + +ori_train_dataset = dict( + _scope_='mmcls', + type=dataset_type, + data_prefix='data/cifar10', + test_mode=False, + pipeline=train_pipeline) + +crd_train_dataset = dict( + _scope_='mmrazor', + type='CRDDataset', + dataset=ori_train_dataset, + neg_num=16384, + sample_mode='exact', + percent=1.0) + +ori_test_dataset = dict( + _scope_='mmcls', + type=dataset_type, + data_prefix='data/cifar10/', + test_mode=True, + pipeline=test_pipeline) + +crd_test_dataset = dict( + _scope_='mmrazor', + type='CRDDataset', + dataset=ori_test_dataset, + neg_num=16384, + sample_mode='exact', + percent=1.0) + +train_dataloader = dict( + _delete_=True, + batch_size=16, + num_workers=2, + dataset=crd_train_dataset, + sampler=dict(type='DefaultSampler', shuffle=True), + persistent_workers=True, +) + +val_dataloader = dict( + _delete_=True, + batch_size=16, + num_workers=2, + dataset=crd_test_dataset, + sampler=dict(type='DefaultSampler', shuffle=False), + persistent_workers=True, +) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/datasets/crd_cifar10_bs16.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/datasets/crd_cifar10_bs16.py new file mode 100755 index 000000000..c7cb74c39 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/datasets/crd_cifar10_bs16.py @@ -0,0 +1,49 @@ +# dataset settings +dataset_type = 'CIFAR10' +preprocess_cfg = dict( + # RGB format normalization parameters + mean=[125.307, 122.961, 113.8575], + std=[51.5865, 50.847, 51.255], + # loaded images are already RGB format + to_rgb=False) + +train_pipeline = [ + dict(type='RandomCrop', crop_size=32, padding=4), + dict(type='RandomFlip', prob=0.5, direction='horizontal'), + dict(type='PackClsInputs'), +] + +test_pipeline = [ + dict(type='PackClsInputs'), +] + +neg_num = 16384 +train_dataloader = dict( + batch_size=16, + num_workers=2, + dataset=dict( + type=dataset_type, + data_prefix='data/cifar10', + test_mode=False, + pipeline=train_pipeline, + neg_num=neg_num), + sampler=dict(type='DefaultSampler', shuffle=True), + persistent_workers=True, +) + +val_dataloader = dict( + batch_size=16, + num_workers=2, + dataset=dict( + type=dataset_type, + data_prefix='data/cifar10/', + test_mode=True, + pipeline=test_pipeline, + neg_num=neg_num), + sampler=dict(type='DefaultSampler', shuffle=False), + persistent_workers=True, +) +val_evaluator = dict(type='Accuracy', topk=(1, )) + +test_dataloader = val_dataloader +test_evaluator = val_evaluator diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/README.md new file mode 100755 index 000000000..76bf6dee6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/README.md @@ -0,0 +1,38 @@ +# Data-Free Learning of Student Networks (DAFL) + +> [Data-Free Learning of Student Networks](https://doi.org/10.1109/ICCV.2019.00361) + + + +## Abstract + +Learning portable neural networks is very essential for computer vision for the purpose that pre-trained heavy deep models can be well applied on edge devices such as mobile phones and micro sensors. Most existing deep neural network compression and speed-up methods are very effective for training compact deep models, when we can directly access the training dataset. However, training data for the given deep network are often unavailable due to some practice problems (e.g. privacy, legal issue, and transmission), and the architecture of the given network are also unknown except some interfaces. To this end, we propose a novel framework for training efficient deep neural networks by exploiting generative adversarial networks (GANs). To be specific, the pre-trained teacher networks are regarded as a fixed discriminator and the generator is utilized for deviating training samples which can obtain the maximum response on the discriminator. Then, an efficient network with smaller model size and computational complexity is trained using the generated data and the teacher network, simultaneously. Efficient student networks learned using the pro- posed Data-Free Learning (DAFL) method achieve 92.22% and 74.47% accuracies using ResNet-18 without any training data on the CIFAR-10 and CIFAR-100 datasets, respectively. Meanwhile, our student network obtains an 80.56% accuracy on the CelebA benchmark. + +pipeline + +## Results and models + +### Classification + +| Location | Dataset | Teacher | Student | Acc | Acc(T) | Acc(S) | Config | Download | +| :---------------: | :-----: | :-------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------: | :---: | :----: | :----: | :---------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| backbone & logits | Cifar10 | [resnet34](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet34_8xb16_cifar10.py) | [resnet18](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet18_8xb16_cifar10.py) | 93.27 | 95.34 | 94.82 | [config](./dafl_logits_resnet34_resnet18_8xb256_cifar10.py) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_b16x8_cifar10_20210528-a8aa36a6.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/DAFL/dafl_logits_resnet34_resnet18_8xb256_cifar10_20220815_202654-67142167.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/DAFL/dafl_logits_resnet34_resnet18_8xb256_cifar10_20220815_202654-67142167.json) | + +## Citation + +```latex +@inproceedings{DBLP:conf/iccv/ChenW0YLSXX019, + author = {Hanting Chen, Yunhe Wang, Chang Xu, Zhaohui Yang, Chuanjian Liu, + Boxin Shi, Chunjing Xu, Chao Xu and Qi Tian}, + title = {Data-Free Learning of Student Networks}, + booktitle = {2019 {IEEE/CVF} International Conference on Computer Vision, {ICCV} + 2019, Seoul, Korea (South), October 27 - November 2, 2019}, + pages = {3513--3521}, + publisher = {{IEEE}}, + year = {2019}, + url = {https://doi.org/10.1109/ICCV.2019.00361}, + doi = {10.1109/ICCV.2019.00361}, + timestamp = {Mon, 17 May 2021 08:18:18 +0200}, + biburl = {https://dblp.org/rec/conf/iccv/ChenW0YLSXX019.bib}, + bibsource = {dblp computer science bibliography, https://dblp.org} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/dafl_logits_resnet34_resnet18_8xb256_cifar10.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/dafl_logits_resnet34_resnet18_8xb256_cifar10.py new file mode 100755 index 000000000..5a3a3f264 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/dafl_logits_resnet34_resnet18_8xb256_cifar10.py @@ -0,0 +1,105 @@ +_base_ = [ + 'mmcls::_base_/datasets/cifar10_bs16.py', + 'mmcls::_base_/schedules/cifar10_bs128.py', + 'mmcls::_base_/default_runtime.py' +] + +res34_ckpt_path = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_b16x8_cifar10_20210528-a8aa36a6.pth' # noqa: E501 +model = dict( + _scope_='mmrazor', + type='DAFLDataFreeDistillation', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[125.307, 122.961, 113.8575], + std=[51.5865, 50.847, 51.255], + # convert image from BGR to RGB + bgr_to_rgb=False), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb16_cifar10.py', pretrained=False), + teachers=dict( + res34=dict( + build_cfg=dict( + cfg_path='mmcls::resnet/resnet34_8xb16_cifar10.py', + pretrained=True), + ckpt_path=res34_ckpt_path)), + generator=dict( + type='DAFLGenerator', + img_size=32, + latent_dim=1000, + hidden_channels=128), + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + teacher_recorders=dict( + res34_fc=dict(type='ModuleOutputs', source='res34.head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=6, loss_weight=1)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(from_student=True, recorder='fc'), + preds_T=dict(from_student=False, recorder='res34_fc')))), + generator_distiller=dict( + type='ConfigurableDistiller', + teacher_recorders=dict( + res34_neck_gap=dict(type='ModuleOutputs', source='res34.neck.gap'), + res34_fc=dict(type='ModuleOutputs', source='res34.head.fc')), + distill_losses=dict( + loss_res34_oh=dict(type='OnehotLikeLoss', loss_weight=0.05), + loss_res34_ie=dict(type='InformationEntropyLoss', loss_weight=5), + loss_res34_ac=dict(type='ActivationLoss', loss_weight=0.01)), + loss_forward_mappings=dict( + loss_res34_oh=dict( + preds_T=dict(from_student=False, recorder='res34_fc')), + loss_res34_ie=dict( + preds_T=dict(from_student=False, recorder='res34_fc')), + loss_res34_ac=dict( + feat_T=dict(from_student=False, recorder='res34_neck_gap'))))) + +# model wrapper +model_wrapper_cfg = dict( + type='mmengine.MMSeparateDistributedDataParallel', + broadcast_buffers=False, + find_unused_parameters=False) + +find_unused_parameters = True + +# optimizer wrapper +optim_wrapper = dict( + _delete_=True, + constructor='mmrazor.SeparateOptimWrapperConstructor', + architecture=dict(optimizer=dict(type='AdamW', lr=1e-1)), + generator=dict(optimizer=dict(type='AdamW', lr=1e-3))) + +auto_scale_lr = dict(base_batch_size=256) + +param_scheduler = dict( + _delete_=True, + architecture=[ + dict(type='LinearLR', end=500, by_epoch=False, start_factor=0.0001), + dict( + type='MultiStepLR', + begin=500, + milestones=[100 * 120, 200 * 120], + by_epoch=False) + ], + generator=dict( + type='LinearLR', end=500, by_epoch=False, start_factor=0.0001)) + +train_cfg = dict( + _delete_=True, by_epoch=False, max_iters=250 * 120, val_interval=150) + +train_dataloader = dict( + batch_size=256, sampler=dict(type='InfiniteSampler', shuffle=True)) +val_dataloader = dict(batch_size=256) +val_evaluator = dict(type='Accuracy', topk=(1, 5)) + +default_hooks = dict( + logger=dict(type='LoggerHook', interval=75, log_metric_by_epoch=False), + checkpoint=dict( + type='CheckpointHook', by_epoch=False, interval=150, max_keep_ckpts=2)) + +log_processor = dict(by_epoch=False) +# Must set diff_rank_seed to True! +randomness = dict(seed=None, diff_rank_seed=True) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/metafile.yml new file mode 100755 index 000000000..9438b8781 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/metafile.yml @@ -0,0 +1,43 @@ +Collections: + - Name: DAFL + Metadata: + Training Data: + - CIFAR-10 + Paper: + URL: https://doi.org/10.1109/ICCV.2019.00361 + Title: Data-Free Learning of Student Networks + README: configs/distill/mmcls/dafl/README.md + Converted From: + Code: + URL: https://github.com/huawei-noah/Efficient-Computing/tree/master/Data-Efficient-Model-Compression/DAFL +Models: + - Name: dafl_logits_resnet34_resnet18_8xb256_cifar10 + In Collection: DAFL + Metadata: + inference time (ms/im): + - value: 0.34 + hardware: NVIDIA A100-SXM4-80GB + backend: PyTorch + batch size: 256 + mode: FP32 + resolution: (32, 32) + Location: logits + Student: + Config: mmcls::resnet/resnet18_8xb16_cifar10.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth + Metrics: + Top 1 Accuracy: 94.82 + Top 5 Accuracy: 99.87 + Teacher: + Config: mmcls::resnet/resnet34_8xb16_cifar10.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_b16x8_cifar10_20210528-a8aa36a6.pth + Metrics: + Top 1 Accuracy: 95.34 + Top 5 Accuracy: 99.87 + Results: + - Task: Image Classification + Dataset: CIFAR-10 + Metrics: + Top 1 Accuracy: 93.27 + Config: configs/distill/mmcls/dafl/dafl_logits_resnet34_resnet18_8xb256_cifar10.py + Weights: https://download.openmmlab.com/mmrazor/v1/DAFL/dafl_logits_resnet34_resnet18_8xb256_cifar10_20220815_202654-67142167.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/README.md new file mode 100755 index 000000000..4ccfa8cc9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/README.md @@ -0,0 +1,45 @@ +# DeiT + +> [](https://arxiv.org/abs/2012.12877) +> Training data-efficient image transformers & distillation through attention + + + +## Abstract + +Recently, neural networks purely based on attention were shown to address image understanding tasks such as image classification. However, these visual transformers are pre-trained with hundreds of millions of images using an expensive infrastructure, thereby limiting their adoption. In this work, we produce a competitive convolution-free transformer by training on Imagenet only. We train them on a single computer in less than 3 days. Our reference vision transformer (86M parameters) achieves top-1 accuracy of 83.1% (single-crop evaluation) on ImageNet with no external data. More importantly, we introduce a teacher-student strategy specific to transformers. It relies on a distillation token ensuring that the student learns from the teacher through attention. We show the interest of this token-based distillation, especially when using a convnet as a teacher. This leads us to report results competitive with convnets for both Imagenet (where we obtain up to 85.2% accuracy) and when transferring to other tasks. We share our code and models. + +
    + +
    + +## Results and models + +### Classification + +| Dataset | Model | Teacher | Top-1 (%) | Top-5 (%) | Configs | Download | +| -------- | --------- | ----------- | --------- | --------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ImageNet | Deit-base | RegNety-160 | 83.24 | 96.33 | [config](deit-base_regnety160_pt-16xb64_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/deit/deit-base/deit-base_regnety160_pt-16xb64_in1k_20221011_113403-a67bf475.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/deit/deit-base/deit-base_regnety160_pt-16xb64_in1k_20221011_113403-a67bf475.json) | + +```{warning} +Before training, please first install `timm`. + +pip install timm +or +git clone https://github.com/rwightman/pytorch-image-models +cd pytorch-image-models && pip install -e . +``` + +## Citation + +``` +@InProceedings{pmlr-v139-touvron21a, + title = {Training data-efficient image transformers & distillation through attention}, + author = {Touvron, Hugo and Cord, Matthieu and Douze, Matthijs and Massa, Francisco and Sablayrolles, Alexandre and Jegou, Herve}, + booktitle = {International Conference on Machine Learning}, + pages = {10347--10357}, + year = {2021}, + volume = {139}, + month = {July} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/deit-base_regnety160_pt-16xb64_in1k.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/deit-base_regnety160_pt-16xb64_in1k.py new file mode 100755 index 000000000..c2cfaf56a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/deit-base_regnety160_pt-16xb64_in1k.py @@ -0,0 +1,64 @@ +_base_ = ['mmcls::deit/deit-base_pt-16xb64_in1k.py'] + +# student settings +student = _base_.model +student.backbone.type = 'DistilledVisionTransformer' +student.head = dict( + type='mmrazor.DeiTClsHead', + num_classes=1000, + in_channels=768, + loss=dict( + type='mmcls.LabelSmoothLoss', + label_smooth_val=0.1, + mode='original', + loss_weight=0.5)) + +data_preprocessor = dict( + type='mmcls.ClsDataPreprocessor', batch_augments=student.train_cfg) + +# teacher settings +checkpoint_path = 'https://dl.fbaipublicfiles.com/deit/regnety_160-a5fe301d.pth' # noqa: E501 +teacher = dict( + _scope_='mmcls', + type='ImageClassifier', + backbone=dict( + type='TIMMBackbone', model_name='regnety_160', pretrained=True), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=1000, + in_channels=3024, + loss=dict( + type='LabelSmoothLoss', + label_smooth_val=0.1, + mode='original', + loss_weight=0.5), + topk=(1, 5), + init_cfg=dict( + type='Pretrained', checkpoint=checkpoint_path, prefix='head.'))) + +model = dict( + _scope_='mmrazor', + _delete_=True, + type='SingleTeacherDistill', + architecture=student, + teacher=teacher, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.layers.head_dist')), + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_distill=dict( + type='CrossEntropyLoss', + loss_weight=0.5, + )), + loss_forward_mappings=dict( + loss_distill=dict( + preds_S=dict(from_student=True, recorder='fc'), + preds_T=dict(from_student=False, recorder='fc'))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/metafile.yml new file mode 100755 index 000000000..6fe41c3a9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/metafile.yml @@ -0,0 +1,34 @@ +Collections: + - Name: DEIT + Metadata: + Training Data: + - ImageNet-1k + Paper: + URL: https://arxiv.org/abs/2012.12877 + Title: Training data-efficient image transformers & distillation through attention + README: configs/distill/mmcls/deit/README.md + +Models: + - Name: deit-base_regnety160_pt-16xb64_in1k + In Collection: DEIT + Metadata: + Student: + Config: mmcls::deit/deit-base_pt-16xb64_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/deit/deit-base_pt-16xb64_in1k_20220216-db63c16c.pth + Metrics: + Top 1 Accuracy: 81.76 + Top 5 Accuracy: 95.81 + Teacher: + Config: mmrazor::distill/mmcls/deit/deit-base_regnety160_pt-16xb64_in1k.py + Weights: https://dl.fbaipublicfiles.com/deit/regnety_160-a5fe301d.pth + Metrics: + Top 1 Accuracy: 82.83 + Top 5 Accuracy: 96.42 + Results: + - Task: Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 83.24 + Top 5 Accuracy: 96.33 + Weights: https://download.openmmlab.com/mmrazor/v1/deit/deit-base/deit-base_regnety160_pt-16xb64_in1k_20221011_113403-a67bf475.pth + Config: configs/distill/mmcls/deit/deit-base_regnety160_pt-16xb64_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/README.md new file mode 100755 index 000000000..4f81fcc47 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/README.md @@ -0,0 +1,30 @@ +# Data-Free Adversarial Distillation (DFAD) + +> [Data-Free Adversarial Distillation](https://arxiv.org/pdf/1912.11006.pdf) + + + +## Abstract + +Knowledge Distillation (KD) has made remarkable progress in the last few years and become a popular paradigm for model compression and knowledge transfer. However, almost all existing KD algorithms are data-driven, i.e., relying on a large amount of original training data or alternative data, which is usually unavailable in real-world scenarios. In this paper, we devote ourselves to this challenging problem and propose a novel adversarial distillation mechanism to craft a compact student model without any real-world data. We introduce a model discrepancy to quantificationally measure the difference between student and teacher models and construct an optimizable upper bound. In our work, the student and the teacher jointly act the role of the discriminator to reduce this discrepancy, when a generator adversarially produces some "hard samples" to enlarge it. Extensive experiments demonstrate that the proposed data-free method yields comparable performance to existing data-driven methods. More strikingly, our approach can be directly extended to semantic segmentation, which is more complicated than classification, and our approach achieves state-of-the-art results. + +pipeline + +## Results and models + +### Classification + +| Location | Dataset | Teacher | Student | Acc | Acc(T) | Acc(S) | Config | Download | +| :------: | :-----: | :-------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------: | :---: | :----: | :----: | :--------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| logits | Cifar10 | [resnet34](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet34_8xb16_cifar10.py) | [resnet18](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet18_8xb16_cifar10.py) | 92.80 | 95.34 | 94.82 | [config](./dfad_logits_resnet34_resnet18_8xb32_cifar10.py) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_b16x8_cifar10_20210528-a8aa36a6.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/DFAD/dfad_logits_resnet34_resnet18_8xb32_cifar10_20220819_051141-961a5b09.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/DFAD/dfad_logits_resnet34_resnet18_8xb32_cifar10_20220819_051141-961a5b09.json) | + +## Citation + +```latex +@article{fang2019data, + title={Data-free adversarial distillation}, + author={Fang, Gongfan and Song, Jie and Shen, Chengchao and Wang, Xinchao and Chen, Da and Song, Mingli}, + journal={arXiv preprint arXiv:1912.11006}, + year={2019} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/dfad_logits_resnet34_resnet18_8xb32_cifar10.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/dfad_logits_resnet34_resnet18_8xb32_cifar10.py new file mode 100755 index 000000000..59bc4d325 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/dfad_logits_resnet34_resnet18_8xb32_cifar10.py @@ -0,0 +1,100 @@ +_base_ = [ + 'mmcls::_base_/datasets/cifar10_bs16.py', + 'mmcls::_base_/schedules/cifar10_bs128.py', + 'mmcls::_base_/default_runtime.py' +] + +res34_ckpt_path = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_b16x8_cifar10_20210528-a8aa36a6.pth' # noqa: E501 +model = dict( + _scope_='mmrazor', + type='DataFreeDistillation', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[125.307, 122.961, 113.8575], + std=[51.5865, 50.847, 51.255], + # convert image from BGR to RGB + bgr_to_rgb=False), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb16_cifar10.py', pretrained=False), + teachers=dict( + res34=dict( + build_cfg=dict( + cfg_path='mmcls::resnet/resnet34_8xb16_cifar10.py', + pretrained=True), + ckpt_path=res34_ckpt_path)), + generator=dict( + type='DAFLGenerator', + img_size=32, + latent_dim=256, + hidden_channels=128, + bn_eps=1e-5), + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + teacher_recorders=dict( + res34_fc=dict(type='ModuleOutputs', source='res34.head.fc')), + distill_losses=dict(loss_kl=dict(type='L1Loss', loss_weight=1.0)), + loss_forward_mappings=dict( + loss_kl=dict( + s_feature=dict(from_student=True, recorder='fc'), + t_feature=dict(from_student=False, recorder='res34_fc')))), + generator_distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + teacher_recorders=dict( + res34_fc=dict(type='ModuleOutputs', source='res34.head.fc')), + distill_losses=dict(loss_l1=dict(type='L1Loss', loss_weight=-1.0)), + loss_forward_mappings=dict( + loss_l1=dict( + s_feature=dict(from_student=True, recorder='fc'), + t_feature=dict(from_student=False, recorder='res34_fc')))), + student_iter=5, + student_train_first=True) + +# model wrapper +model_wrapper_cfg = dict( + type='mmengine.MMSeparateDistributedDataParallel', + broadcast_buffers=False, + find_unused_parameters=True) + +# optimizer wrapper +optim_wrapper = dict( + _delete_=True, + constructor='mmrazor.SeparateOptimWrapperConstructor', + architecture=dict( + optimizer=dict(type='SGD', lr=0.1, weight_decay=5e-4, momentum=0.9)), + generator=dict(optimizer=dict(type='AdamW', lr=1e-3))) + +auto_scale_lr = dict(base_batch_size=32) + +iter_size = 50 +param_scheduler = dict( + _delete_=True, + architecture=dict( + type='MultiStepLR', + milestones=[100 * iter_size, 200 * iter_size], + by_epoch=False), + generator=dict( + type='MultiStepLR', + milestones=[100 * iter_size, 200 * iter_size], + by_epoch=False)) + +train_cfg = dict( + _delete_=True, by_epoch=False, max_iters=500 * iter_size, val_interval=250) + +train_dataloader = dict( + batch_size=32, sampler=dict(type='InfiniteSampler', shuffle=True)) +val_dataloader = dict(batch_size=32) +val_evaluator = dict(type='Accuracy', topk=(1, 5)) + +default_hooks = dict( + logger=dict(type='LoggerHook', interval=50, log_metric_by_epoch=False), + checkpoint=dict( + type='CheckpointHook', by_epoch=False, interval=100, max_keep_ckpts=2)) + +log_processor = dict(by_epoch=False) +# Must set diff_rank_seed to True! +randomness = dict(seed=None, diff_rank_seed=True) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/metafile.yml new file mode 100755 index 000000000..0601f895c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/metafile.yml @@ -0,0 +1,43 @@ +Collections: + - Name: DFAD + Metadata: + Training Data: + - CIFAR-10 + Paper: + URL: https://arxiv.org/pdf/1912.11006.pdf + Title: Data-Free Adversarial Distillation + README: configs/distill/mmcls/dfad/README.md + Converted From: + Code: + URL: https://github.com/VainF/Data-Free-Adversarial-Distillation +Models: + - Name: dfad_logits_resnet34_resnet18_8xb32_cifar10 + In Collection: DFAD + Metadata: + inference time (ms/im): + - value: 0.38 + hardware: NVIDIA A100-SXM4-80GB + backend: PyTorch + batch size: 32 + mode: FP32 + resolution: (32, 32) + Location: logits + Student: + Config: mmcls::resnet/resnet18_8xb16_cifar10.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth + Metrics: + Top 1 Accuracy: 94.82 + Top 5 Accuracy: 99.87 + Teacher: + Config: mmcls::resnet/resnet34_8xb16_cifar10.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_b16x8_cifar10_20210528-a8aa36a6.pth + Metrics: + Top 1 Accuracy: 95.34 + Top 5 Accuracy: 99.87 + Results: + - Task: Image Classification + Dataset: CIFAR-10 + Metrics: + Top 1 Accuracy: 92.80 + Config: configs/distill/mmcls/dfad/dfad_logits_resnet34_resnet18_8xb32_cifar10.py + Weights: https://download.openmmlab.com/mmrazor/v1/DFAD/dfad_logits_resnet34_resnet18_8xb32_cifar10_20220819_051141-961a5b09.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/README.md new file mode 100755 index 000000000..e040d54b4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/README.md @@ -0,0 +1,47 @@ +# Decoupled Knowledge Distillation + +> [Decoupled Knowledge Distillation](https://arxiv.org/pdf/2203.08679.pdf) + + + +## Abstract + +State-of-the-art distillation methods are mainly based on distilling deep features from intermediate layers, while the significance of logit distillation is greatly overlooked. To provide a novel viewpoint to study logit distillation, we reformulate the classical KD loss into two parts, i.e., target class knowledge distillation (TCKD) and non-target class knowledge distillation (NCKD). We empirically investigate and prove the effects of the two parts: TCKD transfers knowledge concerning the "difficulty" of training samples, while NCKD is the prominent reason why logit distillation works. More importantly, we reveal that the classical KD loss is a coupled formulation, which (1) suppresses the effectiveness of NCKD and (2) limits the flexibility to balance these two parts. To address these issues, we present Decoupled Knowledge Distillation (DKD), enabling TCKD and NCKD to play their roles more efficiently and flexibly. Compared with complex feature-based methods, our DKD achieves comparable or even better results and has better training efficiency on CIFAR-100, ImageNet, and MS-COCO datasets for image classification and object detection tasks. This paper proves the great potential of logit distillation, and we hope it will be helpful for future research. The code is available at https://github.com/megvii-research/mdistiller. + +dkd + +## Results and models + +### Classification + +| Dataset | Model | Teacher | Top-1 (%) | Top-5 (%) | Configs | Download | +| -------- | --------- | --------- | --------- | --------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ImageNet | ResNet-18 | ResNet-34 | 71.368 | 90.256 | [config](dkd_resnet34_resnet18_8xb32_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/dkd/dkd_resnet34_resnet18_8xb32_in1k_20220804_202619-f9519768.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/dkd/dkd_resnet34_resnet18_8xb32_in1k_20220804_202619-f9519768.json) | + +## Citation + +```latex +@article{zhao2022decoupled, + title={Decoupled Knowledge Distillation}, + author={Zhao, Borui and Cui, Quan and Song, Renjie and Qiu, Yiyu and Liang, Jiajun}, + journal={arXiv preprint arXiv:2203.08679}, + year={2022} +} +``` + +## Getting Started + +### Download teacher ckpt from + +https://mmclassification.readthedocs.io/en/latest/papers/resnet.html + +### Distillation training. + +```bash +sh tools/dist_train.sh \ + configs/distill/mmcls/dkd/dkd_logits_r34_r18_8xb32_in1k.py 8 +``` + +## Acknowledgement + +Shout out to Davidgzx for his special contribution. diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/dkd_resnet34_resnet18_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/dkd_resnet34_resnet18_8xb32_in1k.py new file mode 100755 index 000000000..391ccf5b6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/dkd_resnet34_resnet18_8xb32_in1k.py @@ -0,0 +1,47 @@ +_base_ = [ + 'mmcls::_base_/datasets/imagenet_bs32.py', + 'mmcls::_base_/schedules/imagenet_bs256.py', + 'mmcls::_base_/default_runtime.py' +] + +teacher_ckpt = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.pth' # noqa: E501 + +model = dict( + _scope_='mmrazor', + type='SingleTeacherDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb32_in1k.py', pretrained=False), + teacher=dict( + cfg_path='mmcls::resnet/resnet34_8xb32_in1k.py', pretrained=True), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc'), + gt_labels=dict(type='ModuleInputs', source='head.loss_module')), + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_dkd=dict( + type='DKDLoss', + tau=1, + beta=0.5, + loss_weight=1, + reduction='mean')), + loss_forward_mappings=dict( + loss_dkd=dict( + preds_S=dict(from_student=True, recorder='fc'), + preds_T=dict(from_student=False, recorder='fc'), + gt_labels=dict( + recorder='gt_labels', from_student=True, data_idx=1))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/metafile.yml new file mode 100755 index 000000000..72d65b96a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/metafile.yml @@ -0,0 +1,43 @@ +Collections: + - Name: DKD + Metadata: + Training Data: + - ImageNet-1k + Paper: + URL: https://arxiv.org/pdf/2203.08679.pdf + Title: Decoupled Knowledge Distillation + README: configs/distill/mmcls/dkd/README.md + Converted From: + Code: + URL: https://github.com/megvii-research/mdistiller +Models: + - Name: dkd_resnet34_resnet18_8xb32_in1k + In Collection: DKD + Metadata: + inference time (ms/im): + - value: 0.75 + hardware: V100 + backend: PyTorch + batch size: 16 + mode: FP32 + resolution: (224, 224) + Student: + Config: mmcls::resnet/resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth + Metrics: + Top 1 Accuracy: 69.90 + Top 5 Accuracy: 89.43 + Teacher: + Config: mmcls::resnet/resnet34_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.pth + Metrics: + Top 1 Accuracy: 73.62 + Top 5 Accuracy: 91.59 + Results: + - Task: Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 71.368 + Top 5 Accuracy: 90.256 + Weights: https://download.openmmlab.com/mmrazor/v1/dkd/dkd_resnet34_resnet18_8xb32_in1k_20220804_202619-f9519768.pth + Config: configs/distill/mmcls/dkd/dkd_resnet34_resnet18_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/README.md new file mode 100755 index 000000000..795df563c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/README.md @@ -0,0 +1,53 @@ +# Paraphrasing Complex Network: Network Compression via Factor Transfer + +> [Paraphrasing Complex Network: Network Compression via Factor Transfer](https://arxiv.org/abs/1802.04977) + + + +## Abstract + +Many researchers have sought ways of model compression to reduce the size of a deep neural network (DNN) with minimal performance degradation in order to use DNNs in embedded systems. Among the model compression methods, a method called knowledge transfer is to train a student network with a stronger teacher network. In this paper, we propose a novel knowledge transfer method which uses convolutional operations to paraphrase teacher’s knowledge and to translate it for the student. This is done by two convolutional modules, which are called a paraphraser and a translator. The paraphraser is trained in an unsupervised manner to extract the teacher factors which are defined as paraphrased information of the teacher network. The translator located at the student network extracts the student factors and helps to translate the teacher factors by mimicking them. We observed that our student network trained with the proposed factor transfer method outperforms the ones trained with conventional knowledge transfer methods. The original code is available at this [link](https://github.com/Jangho-Kim/Factor-Transfer-pytorch) + +## Results and models + +| Dataset | Model | Teacher | Top-1 (%) | Top-5 (%) | Configs | Download | +| ------- | --------- | --------- | --------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| CIFAR10 | ResNet-18 | ResNet-50 | 94.86 | 99.88 | [pretrain](./factor-transfer_backbone_resnet50_resnet18_8xb32_cifar10_pretrain.py) \| [train](./factor-transfer_backbone_resnet50_resnet18_8xb32_cifar10_train.py) | [pretrain model](https://download.openmmlab.com/mmrazor/v1/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain_20220831_173259-ebdb09e2.pth) \| [pretrain log](https://download.openmmlab.com/mmrazor/v1/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain_20220831_173259-ebdb09e2.json) \| [train model](https://download.openmmlab.com/mmrazor/v1/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train_20220831_201322-943df33f.pth) \| [train log](https://download.openmmlab.com/mmrazor/v1/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train_20220831_201322-943df33f.json) | + +## Getting Started + +### Connectors pre-training. + +```bash +sh tools/dist_train.sh $PARTITION $JOB_NAME \ + configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb32_cifar10_pretrain.py \ + $PRETRAIN_WORK_DIR +``` + +### Distillation training. + +```bash +sh tools/dist_train.sh $PARTITION $JOB_NAME \ + configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb32_cifar10_train.py \ + $DISTILLATION_WORK_DIR +``` + +### Test + +```bash +sh tools/dist_test.sh $PARTITION $JOB_NAME \ + configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb32_cifar10_train.py \ + $DISTILLATION_WORK_DIR/latest.sh --eval $EVAL_SETTING +``` + +## Citation + +```latex +@inproceedings{kim2018paraphrasing, + title={Paraphrasing complex network: network compression via factor transfer}, + author={Kim, Jangho and Park, SeongUk and Kwak, Nojun}, + booktitle={Proceedings of the 32nd International Conference on Neural Information Processing Systems}, + pages={2765--2774}, + year={2018} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain.py new file mode 100755 index 000000000..33903cdf2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain.py @@ -0,0 +1,59 @@ +_base_ = [ + 'mmcls::_base_/datasets/cifar10_bs16.py', + 'mmcls::_base_/schedules/cifar10_bs128.py', + 'mmcls::_base_/default_runtime.py' +] + +train_cfg = dict(by_epoch=True, max_epochs=20, val_interval=1) + +model = dict( + _scope_='mmrazor', + type='SingleTeacherDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb16_cifar10.py', pretrained=False), + teacher=dict( + cfg_path='mmcls::resnet/resnet50_8xb16_cifar10.py', pretrained=True), + teacher_ckpt= # noqa: E251 + 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_b16x8_cifar10_20210528-f54bfad9.pth', # noqa: E501 + calculate_student_loss=False, + student_trainable=False, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + bb_s4=dict(type='ModuleOutputs', + source='backbone.layer4.1.conv2')), + teacher_recorders=dict( + bb_s4=dict(type='ModuleOutputs', + source='backbone.layer4.2.conv3')), + distill_losses=dict( + loss_s4_pretrain=dict(type='L2Loss', loss_weight=1.0)), + connectors=dict( + loss_s4_sfeat=dict( + type='Translator', in_channel=512, out_channel=1024), + loss_s4_tfeat=dict( + type='Paraphraser', + phase='pretrain', + in_channel=2048, + out_channel=1024)), + loss_forward_mappings=dict( + loss_s4_pretrain=dict( + s_feature=dict( + # it actually is t_feature + from_student=False, + recorder='bb_s4'), + t_feature=dict( + from_student=False, + recorder='bb_s4', + connector='loss_s4_tfeat'), + )))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train.py new file mode 100755 index 000000000..ba1b9f258 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train.py @@ -0,0 +1,29 @@ +_base_ = [ + './factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain.py' +] + +train_cfg = dict(by_epoch=True, max_epochs=200, val_interval=1) + +model = dict( + calculate_student_loss=True, + student_trainable=True, + distiller=dict( + distill_losses=dict(loss_s4=dict(type='FTLoss', loss_weight=1.0)), + connectors=dict(loss_s4_tfeat=dict(phase='train')), + loss_forward_mappings=dict( + _delete_=True, + loss_s4=dict( + s_feature=dict( + from_student=True, + recorder='bb_s4', + connector='loss_s4_sfeat'), + t_feature=dict( + from_student=False, + recorder='bb_s4', + connector='loss_s4_tfeat'), + ))), + init_cfg=dict( + type='Pretrained', + checkpoint= # noqa: E251 + 'https://download.openmmlab.com/mmrazor/v1/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain_20220831_173259-ebdb09e2.pth' # noqa: E501 + )) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/metafile.yml new file mode 100755 index 000000000..615dc3499 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/metafile.yml @@ -0,0 +1,38 @@ +Collections: + - Name: FactorTransfer + Metadata: + Training Data: + - CIFAR-10 + Paper: + URL: https://arxiv.org/abs/1802.04977 + Title: 'Paraphrasing Complex Network: Network Compression via Factor Transfer' + README: configs/distill/mmcls/factor_transfer/README.md + Code: + URL: https://github.com/open-mmlab/mmrazor/blob/dev-1.x/mmrazor/models/losses/factor_transfer_loss.py + Version: v2.0.0 + Converted From: + Code: https://github.com/Jangho-Kim/Factor-Transfer-pytorch +Models: + - Name: factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train + In Collection: FactorTransfer + Metadata: + Location: backbone + Student: + Config: mmcls::resnet/resnet18_8xb16_cifar10.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth + Metrics: + Top 1 Accuracy: 94.82 + Top 5 Accuracy: 99.87 + Teacher: + Config: mmcls::resnet/resnet50_8xb16_cifar10.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_b16x8_cifar10_20210528-f54bfad9.pth + Metrics: + Top 1 Accuracy: 95.55 + Top 5 Accuracy: 99.91 + Results: + - Task: Image Classification + Dataset: CIFAR-10 + Metrics: + Top 1 Accuracy: 94.8800 + Config: configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train.py + Weights: https://download.openmmlab.com/mmrazor/v1/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train_20220831_201322-943df33f.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/README.md new file mode 100755 index 000000000..8a6515a3c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/README.md @@ -0,0 +1,48 @@ +# FitNets + +> [FitNets: Hints for Thin Deep Nets](https://arxiv.org/abs/1412.6550) + + + +## Abstract + +While depth tends to improve network performances, it also makes gradient-based +training more difficult since deeper networks tend to be more non-linear. The recently +proposed knowledge distillation approach is aimed at obtaining small and fast-to-execute +models, and it has shown that a student network could imitate the soft output of a larger +teacher network or ensemble of networks. In this paper, we extend this idea to allow the +training of a student that is deeper and thinner than the teacher, using not only the outputs +but also the intermediate representations learned by the teacher as hints to improve the +training process and final performance of the student. Because the student intermediate hidden +layer will generally be smaller than the teacher's intermediate hidden layer, additional parameters +are introduced to map the student hidden layer to the prediction of the teacher hidden layer. This +allows one to train deeper students that can generalize better or run faster, a trade-off that is +controlled by the chosen student capacity. For example, on CIFAR-10, a deep student network with +almost 10.4 times less parameters outperforms a larger, state-of-the-art teacher network. + +pipeline + +## Results and models + +### Classification + +| Location | Dataset | Teacher | Student | Acc | Acc(T) | Acc(S) | Config | Download | +| :---------------: | :------: | :----------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------: | :---: | :----: | :----: | :-----------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| backbone & logits | ImageNet | [resnet50](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet50_8xb32_in1k.py) | [resnet18](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet18_8xb32_in1k.py) | 70.58 | 76.55 | 69.90 | [config](./fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k.py) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/FieNets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k_20220830_155608-00ccdbe2.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/FieNets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k_20220830_155608-00ccdbe2.json) | + +## Citation + +```latex +@inproceedings{DBLP:journals/corr/RomeroBKCGB14, + author = {Adriana Romero, Nicolas Ballas, Samira Ebrahimi Kahou, Antoine Chassang, Carlo Gatta and Yoshua Bengio}, + editor = {Yoshua Bengio and Yann LeCun}, + title = {FitNets: Hints for Thin Deep Nets}, + booktitle = {3rd International Conference on Learning Representations, {ICLR} 2015, + San Diego, CA, USA, May 7-9, 2015, Conference Track Proceedings}, + year = {2015}, + url = {http://arxiv.org/abs/1412.6550}, + timestamp = {Thu, 25 Jul 2019 14:25:38 +0200}, + biburl = {https://dblp.org/rec/journals/corr/RomeroBKCGB14.bib}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k.py new file mode 100755 index 000000000..5947684a6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k.py @@ -0,0 +1,72 @@ +_base_ = [ + 'mmcls::_base_/datasets/imagenet_bs32.py', + 'mmcls::_base_/schedules/imagenet_bs256.py', + 'mmcls::_base_/default_runtime.py' +] + +teacher_ckpt = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth' # noqa: E501 +model = dict( + _scope_='mmrazor', + type='SingleTeacherDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb32_in1k.py', pretrained=False), + teacher=dict( + cfg_path='mmcls::resnet/resnet50_8xb32_in1k.py', pretrained=True), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + bb_s4=dict(type='ModuleOutputs', source='backbone.layer4.1.relu'), + bb_s3=dict(type='ModuleOutputs', source='backbone.layer3.1.relu'), + fc=dict(type='ModuleOutputs', source='head.fc')), + teacher_recorders=dict( + bb_s4=dict(type='ModuleOutputs', source='backbone.layer4.2.relu'), + bb_s3=dict(type='ModuleOutputs', source='backbone.layer3.5.relu'), + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_s4=dict(type='L2Loss', loss_weight=10), + loss_s3=dict(type='L2Loss', loss_weight=10), + loss_kl=dict( + type='KLDivergence', tau=6, loss_weight=10, reduction='mean')), + connectors=dict( + loss_s4_sfeat=dict( + type='ConvModuleConnector', + in_channel=512, + out_channel=2048, + norm_cfg=dict(type='BN')), + loss_s3_sfeat=dict( + type='ConvModuleConnector', + in_channel=256, + out_channel=1024, + norm_cfg=dict(type='BN'))), + loss_forward_mappings=dict( + loss_s4=dict( + s_feature=dict( + from_student=True, + recorder='bb_s4', + record_idx=1, + connector='loss_s4_sfeat'), + t_feature=dict( + from_student=False, recorder='bb_s4', record_idx=2)), + loss_s3=dict( + s_feature=dict( + from_student=True, + recorder='bb_s3', + record_idx=1, + connector='loss_s3_sfeat'), + t_feature=dict( + from_student=False, recorder='bb_s3', record_idx=2)), + loss_kl=dict( + preds_S=dict(from_student=True, recorder='fc'), + preds_T=dict(from_student=False, recorder='fc'))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/metafile.yml new file mode 100755 index 000000000..4dd7eb85d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/metafile.yml @@ -0,0 +1,40 @@ +Collections: + - Name: FitNets + Metadata: + Training Data: + - ImageNet-1k + Paper: + URL: https://arxiv.org/abs/1412.6550 + Title: FitNets- Hints for Thin Deep Nets + README: configs/distill/mmcls/fitnets/README.md +Models: + - Name: fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k + In Collection: FitNets + Metadata: + inference time (ms/im): + - value: 0.18 + hardware: NVIDIA A100-SXM4-80GB + backend: PyTorch + batch size: 32 + mode: FP32 + resolution: (224, 224) + Location: backbone & logits + Student: + Config: mmcls::resnet/resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth + Metrics: + Top 1 Accuracy: 69.90 + Top 5 Accuracy: 89.43 + Teacher: + Config: mmcls::resnet/resnet50_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth + Metrics: + Top 1 Accuracy: 76.55 + Top 5 Accuracy: 93.06 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 70.58 + Config: configs/distill/mmcls/fitnets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/FieNets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k_20220830_155608-00ccdbe2.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/README.md new file mode 100755 index 000000000..0fbe7bd9a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/README.md @@ -0,0 +1,34 @@ +# KD + +> [Distilling the Knowledge in a Neural Network](https://arxiv.org/abs/1503.02531) + + + +## Abstract + +A very simple way to improve the performance of almost any machine learning algorithm is to train many different models on the same data and then to average their predictions. Unfortunately, making predictions using a whole ensemble of models is cumbersome and may be too computationally expensive to allow deployment to a large number of users, especially if the individual models are large neural nets. Caruana and his collaborators have shown that it is possible to compress the knowledge in an ensemble into a single model which is much easier to deploy and we develop this approach further using a different compression technique. We achieve some surprising results on MNIST and we show that we can significantly improve the acoustic model of a heavily used commercial system by distilling the knowledge in an ensemble of models into a single model. We also introduce a new type of ensemble composed of one or more full models and many specialist models which learn to distinguish fine-grained classes that the full models confuse. Unlike a mixture of experts, these specialist models can be trained rapidly and in parallel. + +![pipeline](https://user-images.githubusercontent.com/88702197/187423762-e932dd3e-16cb-4714-a85f-cddfc906c1b7.png) + +## Results and models + +### Classification + +| Location | Dataset | Teacher | Student | Acc | Acc(T) | Acc(S) | Config | Download | +| :------: | :------: | :-----------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: | :---: | :----: | :----: | :------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| logits | ImageNet | [resnet34](https://github.com/open-mmlab/mmclassification/blob/dev-1.x/configs/resnet/resnet34_8xb32_in1k.py) | [resnet18](https://github.com/open-mmlab/mmclassification/blob/dev-1.x/configs/resnet/resnet18_8xb32_in1k.py) | 71.81 | 73.62 | 69.90 | [config](./kd_logits_resnet34_resnet18_8xb32_in1k.py) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/kd/kl_r18_w3/kd_logits_resnet34_resnet18_8xb32_in1k_w3_20221011_181115-5c6a834d.pth?versionId=CAEQThiBgID1_Me0oBgiIDE3NTk3MDgxZmU2YjRlMjVhMzg1ZTQwMmRhNmYyNGU2) \| [log](https://download.openmmlab.com/mmrazor/v1/kd/kl_r18_w3/kd_logits_resnet34_resnet18_8xb32_in1k_w3_20221011_181115-5c6a834d.json?versionId=CAEQThiBgMDx_se0oBgiIDQxNTM2MWZjZGRhNjRhZDZiZTIzY2Y0NDU3NDA4ODBl) | +| logits | ImageNet | [resnet50](https://github.com/open-mmlab/mmclassification/blob/dev-1.x/configs/resnet/resnet50_8xb32_in1k.py) | [mobilenet-v2](https://github.com/open-mmlab/mmclassification/blob/dev-1.x/configs/mobilenet_v2/mobilenet-v2_8xb32_in1k.py) | 73.56 | 76.55 | 71.86 | [config](./kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/kd/kl_mbv2_w3t1/kd_logits_resnet50_mobilenet-v2_8xb32_in1k_20221025_212407-6ea9e2a5.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/kd/kl_mbv2_w3t1/kd_logits_resnet50_mobilenet-v2_8xb32_in1k_20221025_212407-6ea9e2a5.json) | +| logits | ImageNet | [resnet50](https://github.com/open-mmlab/mmclassification/blob/dev-1.x/configs/resnet/resnet50_8xb32_in1k.py) | [shufflenet-v2](https://github.com/open-mmlab/mmclassification/blob/dev-1.x/configs/shufflenet_v2/shufflenet-v2-1x_16xb64_in1k.py) | 70.87 | 76.55 | 69.55 | [config](./kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/kd/kl_shuffle_w3t1/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k_20221025_224424-5d748c1b.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/kd/kl_shuffle_w3t1/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k_20221025_224424-5d748c1b.json) | + +## Citation + +```latex +@article{hinton2015distilling, + title={Distilling the knowledge in a neural network}, + author={Hinton, Geoffrey and Vinyals, Oriol and Dean, Jeff and others}, + journal={arXiv preprint arXiv:1503.02531}, + volume={2}, + number={7}, + year={2015} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet34_resnet18_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet34_resnet18_8xb32_in1k.py new file mode 100755 index 000000000..35921c03b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet34_resnet18_8xb32_in1k.py @@ -0,0 +1,39 @@ +_base_ = [ + 'mmcls::_base_/datasets/imagenet_bs32.py', + 'mmcls::_base_/schedules/imagenet_bs256.py', + 'mmcls::_base_/default_runtime.py' +] + +teacher_ckpt = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.pth' # noqa: E501 + +model = dict( + _scope_='mmrazor', + type='SingleTeacherDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb32_in1k.py', pretrained=False), + teacher=dict( + cfg_path='mmcls::resnet/resnet34_8xb32_in1k.py', pretrained=False), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=3)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(from_student=True, recorder='fc'), + preds_T=dict(from_student=False, recorder='fc'))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py new file mode 100755 index 000000000..4f82fb3b0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py @@ -0,0 +1,37 @@ +_base_ = ['mmcls::mobilenet_v2/mobilenet-v2_8xb32_in1k.py'] + +student = _base_.model + +teacher_ckpt = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth' # noqa: E501 + +model = dict( + _scope_='mmrazor', + _delete_=True, + type='SingleTeacherDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True), + architecture=student, + teacher=dict( + cfg_path='mmcls::resnet/resnet50_8xb32_in1k.py', pretrained=False), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=3)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(from_student=True, recorder='fc'), + preds_T=dict(from_student=False, recorder='fc'))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py new file mode 100755 index 000000000..fe9dd5891 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py @@ -0,0 +1,37 @@ +_base_ = ['mmcls::shufflenet_v2/shufflenet-v2-1x_16xb64_in1k.py'] + +student = _base_.model + +teacher_ckpt = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth' # noqa: E501 + +model = dict( + _scope_='mmrazor', + _delete_=True, + type='SingleTeacherDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True), + architecture=student, + teacher=dict( + cfg_path='mmcls::resnet/resnet50_8xb32_in1k.py', pretrained=False), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=3)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(from_student=True, recorder='fc'), + preds_T=dict(from_student=False, recorder='fc'))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/metafile.yml new file mode 100755 index 000000000..a208de783 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/metafile.yml @@ -0,0 +1,82 @@ +Collections: + - Name: KD + Metadata: + Training Data: + - ImageNet-1k + Paper: + URL: https://arxiv.org/abs/1503.02531 + Title: Distilling the Knowledge in a Neural Network + README: configs/distill/mmcls/kd/README.md + +Models: + - Name: kd_logits_resnet34_resnet18_8xb32_in1k + In Collection: KD + Metadata: + Location: logits + Student: + Config: mmcls::resnet/resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth + Metrics: + Top 1 Accuracy: 69.90 + Top 5 Accuracy: 89.43 + Teacher: + Config: mmcls::resnet/resnet34_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.pth + Metrics: + Top 1 Accuracy: 73.62 + Top 5 Accuracy: 91.59 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 71.81 + Config: configs/distill/mmcls/kd/kd_logits_resnet34_resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/kd/kl_r18_w3/kd_logits_resnet34_resnet18_8xb32_in1k_w3_20221011_181115-5c6a834d.pth?versionId=CAEQThiBgID1_Me0oBgiIDE3NTk3MDgxZmU2YjRlMjVhMzg1ZTQwMmRhNmYyNGU2 + + - Name: kd_logits_resnet50_mobilenet-v2_8xb32_in1k + In Collection: KD + Metadata: + Location: logits + Student: + Config: mmcls::mobilenet_v2/mobilenet-v2_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/mobilenet_v2/mobilenet_v2_batch256_imagenet_20200708-3b2dc3af.pth + Metrics: + Top 1 Accuracy: 71.86 + Top 5 Accuracy: 90.42 + Teacher: + Config: mmcls::resnet/resnet50_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth + Metrics: + Top 1 Accuracy: 76.55 + Top 5 Accuracy: 93.06 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 73.56 + Config: configs/distill/mmcls/kd/kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/kd/kl_mbv2_w3t1/kd_logits_resnet50_mobilenet-v2_8xb32_in1k_20221025_212407-6ea9e2a5.pth + + - Name: kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k + In Collection: KD + Metadata: + Location: logits + Student: + Config: mmcls::shufflenet_v2/shufflenet-v2-1x_16xb64_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/shufflenet_v2/shufflenet_v2_batch1024_imagenet_20200812-5bf4721e.pth + Metrics: + Top 1 Accuracy: 69.55 + Top 5 Accuracy: 88.92 + Teacher: + Config: mmcls::resnet/resnet50_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth + Metrics: + Top 1 Accuracy: 76.55 + Top 5 Accuracy: 93.06 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 70.87 + Config: configs/distill/mmcls/kd/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/kd/kl_shuffle_w3t1/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k_20221025_224424-5d748c1b.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/README.md new file mode 100755 index 000000000..eb789e840 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/README.md @@ -0,0 +1,63 @@ +# Overhaul + +> [A Comprehensive Overhaul of Feature Distillation](https://arxiv.org/abs/1904.01866) + + + +## Abstract + +We investigate the design aspects of feature distillation methods achieving network compression and propose a novel feature distillation method in which the distillation loss is designed to make a synergy among various aspects: teacher transform, student transform, distillation feature position and distance function. Our proposed distillation loss includes a feature transform with a newly designed margin ReLU, a new distillation feature position, and a partial L2 distance function to skip redundant information giving adverse effects to the compression of student. In ImageNet, our proposed method achieves 21.65% of top-1 error with ResNet50, which outperforms the performance of the teacher network, ResNet152. Our proposed method is evaluated on various tasks such as image classification, object detection and semantic segmentation and achieves a significant performance improvement in all tasks. The code is available at [link](https://sites.google.com/view/byeongho-heo/overhaul) + +### Feature-based Distillation + +![feature_base](https://user-images.githubusercontent.com/88702197/187423965-bb3bde16-c71a-43c6-903c-69aff1005415.png) + +### Margin ReLU + +![margin_relu](https://user-images.githubusercontent.com/88702197/187423981-67106ac2-48d9-4002-8b32-b92a90b1dacd.png) + +## Results and models + +### 1. Classification + +#### Vanilla + +| Dataset | Model | Top-1 (%) | Download | +| ------- | ----------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| CIFAR10 | [WRN16-2](../../../vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py) | 93.43 | [model](https://download.openmmlab.com/mmrazor/v1/wide_resnet/wrn16_2_b16x8_cifar10_20220831_204709-446b466e.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/wide_resnet/wrn16_2_b16x8_cifar10_20220831_204709-446b466e.json) | +| CIFAR10 | [WRN28-4](../../../vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py) | 95.49 | [model](https://download.openmmlab.com/mmrazor/v1/wide_resnet/wrn28_4_b16x8_cifar10_20220831_173536-d6f8725c.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/wide_resnet/wrn28_4_b16x8_cifar10_20220831_173536-d6f8725c.json) | + +#### Distillation + +| Dataset | Model | Flops(M) | Teacher | Top-1 (%) | Configs | Download | +| ------- | ------- | -------- | ------- | --------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| CIFAR10 | WRN16-2 | 101 | WRN28-4 | 94.21 | [config](./ofd_backbone_resnet50_resnet18_8xb16_cifar10.py) | [model](https://download.openmmlab.com/mmrazor/v1/overhaul/ofd_backbone_resnet50_resnet18_8xb16_cifar10_20230417_192216-ace2908f.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/overhaul/ofd_backbone_resnet50_resnet18_8xb16_cifar10_20230417_192216-ace2908f.log) | + +## Getting Started + +### Distillation training. + +```bash +sh tools/slurm_train.sh $PARTITION $JOB_NAME \ + configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py \ + $DISTILLATION_WORK_DIR +``` + +### Test + +```bash +sh tools/slurm_test.sh $PARTITION $JOB_NAME \ + configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py \ + $DISTILLATION_WORK_DIR/latest.pth --eval $EVAL_SETTING +``` + +## Citation + +```latex +@inproceedings{heo2019overhaul, + title={A Comprehensive Overhaul of Feature Distillation}, + author={Heo, Byeongho and Kim, Jeesoo and Yun, Sangdoo and Park, Hyojin and Kwak, Nojun and Choi, Jin Young}, + booktitle = {International Conference on Computer Vision (ICCV)}, + year={2019} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/metafile.yml new file mode 100755 index 000000000..cb176b1c3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/metafile.yml @@ -0,0 +1,38 @@ +Collections: + - Name: OFD + Metadata: + Training Data: + - CIFAR-10 + Paper: + URL: https://arxiv.org/abs/1904.01866 + Title: A Comprehensive Overhaul of Feature Distillation + README: configs/distill/mmcls/ofd/README.md + Code: + URL: https://github.com/open-mmlab/mmrazor/blob/dev-1.x/mmrazor/models/algorithms/distill/configurable/overhaul_feature_distillation.py + Version: v2.0.0 + Converted From: + Code: https://github.com/clovaai/overhaul-distillation +Models: + - Name: ofd_backbone_resnet50_resnet18_8xb16_cifar10 + In Collection: OFD + Metadata: + Location: backbone + Student: + Config: mmrazor::vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py + Weights: https://download.openmmlab.com/mmrazor/v1/wide_resnet/wrn16_2_b16x8_cifar10_20220831_204709-446b466e.pth + Metrics: + Top 1 Accuracy: 93.2600 + Top 5 Accuracy: 99.8000 + Teacher: + Config: mmrazor::vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py + Weights: https://download.openmmlab.com/mmrazor/v1/wide_resnet/wrn28_4_b16x8_cifar10_20220831_173536-d6f8725c.pth + Metrics: + Top 1 Accuracy: 95.4400 + Top 5 Accuracy: 99.8200 + Results: + - Task: Image Classification + Dataset: CIFAR-10 + Metrics: + Top 1 Accuracy: 94.21 + Config: configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py + Weights: https://download.openmmlab.com/mmrazor/v1/overhaul/ofd_backbone_resnet50_resnet18_8xb16_cifar10_20230417_192216-ace2908f.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py new file mode 100755 index 000000000..d47088ee7 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py @@ -0,0 +1,100 @@ +_base_ = [ + 'mmcls::_base_/datasets/cifar10_bs16.py', + 'mmcls::_base_/schedules/cifar10_bs128.py', + 'mmcls::_base_/default_runtime.py' +] + +model = dict( + _scope_='mmrazor', + type='OverhaulFeatureDistillation', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[125.307, 122.961, 113.8575], + std=[51.5865, 50.847, 51.255], + # convert image from BGR to RGB + bgr_to_rgb=False), + architecture=dict( + cfg_path= # noqa: E251 + 'mmrazor::vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py', + pretrained=False), + teacher=dict( + cfg_path= # noqa: E251 + 'mmrazor::vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py', + pretrained=False), + teacher_ckpt= # noqa: E251 + 'https://download.openmmlab.com/mmrazor/v1/wide_resnet/wrn28_4_b16x8_cifar10_20220831_173536-d6f8725c.pth', # noqa: E501 + calculate_student_loss=True, + student_trainable=True, + distiller=dict( + type='OFDDistiller', + student_recorders=dict( + bb_1=dict(type='ModuleOutputs', source='backbone.layer2.0.bn1'), + bb_2=dict(type='ModuleOutputs', source='backbone.layer3.0.bn1'), + bb_3=dict(type='ModuleOutputs', source='backbone.bn1')), + teacher_recorders=dict( + bb_1=dict(type='ModuleOutputs', source='backbone.layer2.0.bn1'), + bb_2=dict(type='ModuleOutputs', source='backbone.layer3.0.bn1'), + bb_3=dict(type='ModuleOutputs', source='backbone.bn1')), + distill_losses=dict( + loss_1=dict(type='OFDLoss', loss_weight=0.25), + loss_2=dict(type='OFDLoss', loss_weight=0.5), + loss_3=dict(type='OFDLoss', loss_weight=1.0)), + connectors=dict( + loss_1_sfeat=dict( + type='ConvModuleConnector', + in_channel=32, + out_channel=64, + norm_cfg=dict(type='BN'), + act_cfg=None), + loss_1_tfeat=dict(type='OFDTeacherConnector'), + loss_2_sfeat=dict( + type='ConvModuleConnector', + in_channel=64, + out_channel=128, + norm_cfg=dict(type='BN'), + act_cfg=None), + loss_2_tfeat=dict(type='OFDTeacherConnector'), + loss_3_sfeat=dict( + type='ConvModuleConnector', + in_channel=128, + out_channel=256, + norm_cfg=dict(type='BN'), + act_cfg=None), + loss_3_tfeat=dict(type='OFDTeacherConnector')), + loss_forward_mappings=dict( + loss_1=dict( + s_feature=dict( + from_student=True, + recorder='bb_1', + connector='loss_1_sfeat'), + t_feature=dict( + from_student=False, + recorder='bb_1', + connector='loss_1_tfeat'), + ), + loss_2=dict( + s_feature=dict( + from_student=True, + recorder='bb_2', + connector='loss_2_sfeat'), + t_feature=dict( + from_student=False, + recorder='bb_2', + connector='loss_2_tfeat'), + ), + loss_3=dict( + s_feature=dict( + from_student=True, + recorder='bb_3', + connector='loss_3_sfeat'), + t_feature=dict( + from_student=False, + recorder='bb_3', + connector='loss_3_tfeat'), + ), + ))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/README.md new file mode 100755 index 000000000..3b25e5e7d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/README.md @@ -0,0 +1,43 @@ +# RKD + +> [Relational Knowledge Distillation](https://arxiv.org/abs/1904.05068) + + + +## Abstract + +Knowledge distillation aims at transferring knowledge acquired +in one model (a teacher) to another model (a student) that is +typically smaller. Previous approaches can be expressed as +a form of training the student to mimic output activations of +individual data examples represented by the teacher. We introduce +a novel approach, dubbed relational knowledge distillation (RKD), +that transfers mutual relations of data examples instead. +For concrete realizations of RKD, we propose distance-wise and +angle-wise distillation losses that penalize structural differences +in relations. Experiments conducted on different tasks show that the +proposed method improves educated student models with a significant margin. +In particular for metric learning, it allows students to outperform their +teachers' performance, achieving the state of the arts on standard benchmark datasets. + +![pipeline](https://user-images.githubusercontent.com/88702197/187424092-b58742aa-6724-4a89-8d28-62960efb58b4.png) + +## Results and models + +### Classification + +| Location | Dataset | Teacher | Student | Acc | Acc(T) | Acc(S) | Config | Download | +| :------: | :------: | :----------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------: | :---: | :----: | :----: | :--------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| neck | ImageNet | [resnet34](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet34_8xb32_in1k.py) | [resnet18](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet18_8xb32_in1k.py) | 70.23 | 73.62 | 69.90 | [config](./rkd_neck_resnet34_resnet18_8xb32_in1k.py) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_b16x8_cifar10_20210528-a8aa36a6.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k_acc-70.23_20220401-a91e223f.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.3/distill/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k_20220312_130419.log.json) | + +## Citation + +```latex +@inproceedings{park2019relational, + title={Relational knowledge distillation}, + author={Park, Wonpyo and Kim, Dongju and Lu, Yan and Cho, Minsu}, + booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, + pages={3967--3976}, + year={2019} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/metafile.yml new file mode 100755 index 000000000..820d81ce9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/metafile.yml @@ -0,0 +1,38 @@ +Collections: + - Name: RKD + Metadata: + Training Data: + - ImageNet-1k + Paper: + URL: https://arxiv.org/abs/1904.05068 + Title: Relational Knowledge Distillation + README: configs/distill/mmcls/rkd/README.md + Code: + URL: https://github.com/open-mmlab/mmrazor/blob/v0.3.0/mmrazor/models/losses/relation_kd.py + Version: v0.3.0 + Converted From: + Code: https://github.com/lenscloth/RKD +Models: + - Name: rkd_neck_resnet34_resnet18_8xb32_in1k + In Collection: RKD + Metadata: + Location: neck + Student: + Config: mmcls::resnet/resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth + Metrics: + Top 1 Accuracy: 69.90 + Top 5 Accuracy: 89.43 + Teacher: + Config: mmcls::resnet/resnet34_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.pth + Metrics: + Top 1 Accuracy: 73.62 + Top 5 Accuracy: 91.59 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 70.23 + Config: configs/distill/mmcls/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k_acc-70.23_20220401-a91e223f.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k.py new file mode 100755 index 000000000..6d5e878d5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k.py @@ -0,0 +1,44 @@ +_base_ = [ + 'mmcls::_base_/datasets/imagenet_bs32.py', + 'mmcls::_base_/schedules/imagenet_bs256.py', + 'mmcls::_base_/default_runtime.py' +] + +model = dict( + _scope_='mmrazor', + type='SingleTeacherDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb32_in1k.py', pretrained=False), + teacher=dict( + cfg_path='mmcls::resnet/resnet34_8xb32_in1k.py', pretrained=True), + teacher_ckpt= # noqa + 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.pth', # noqa + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + feat=dict(type='ModuleOutputs', source='neck.gap')), + teacher_recorders=dict( + feat=dict(type='ModuleOutputs', source='neck.gap')), + distill_losses=dict( + loss_dw=dict( + type='DistanceWiseRKD', with_l2_norm=True, loss_weight=25), + loss_aw=dict( + type='AngleWiseRKD', with_l2_norm=True, loss_weight=50)), + loss_forward_mappings=dict( + loss_dw=dict( + preds_S=dict(from_student=True, recorder='feat'), + preds_T=dict(from_student=False, recorder='feat')), + loss_aw=dict( + preds_S=dict(from_student=True, recorder='feat'), + preds_T=dict(from_student=False, recorder='feat'))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/README.md new file mode 100755 index 000000000..be35af6cd --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/README.md @@ -0,0 +1,43 @@ +# WSLD + +> [Rethinking Soft Labels for Knowledge Distillation: A Bias-Variance Tradeoff Perspective](https://arxiv.org/abs/2102.00650) + + + +## Abstract + +Knowledge distillation is an effective approach to leverage a well-trained network +or an ensemble of them, named as the teacher, to guide the training of a student +network. The outputs from the teacher network are used as soft labels for supervising the training of a new network. Recent studies (Muller et al., 2019; Yuan ¨ +et al., 2020) revealed an intriguing property of the soft labels that making labels +soft serves as a good regularization to the student network. From the perspective of statistical learning, regularization aims to reduce the variance, however +how bias and variance change is not clear for training with soft labels. In this +paper, we investigate the bias-variance tradeoff brought by distillation with soft +labels. Specifically, we observe that during training the bias-variance tradeoff +varies sample-wisely. Further, under the same distillation temperature setting, we +observe that the distillation performance is negatively associated with the number of some specific samples, which are named as regularization samples since +these samples lead to bias increasing and variance decreasing. Nevertheless, we +empirically find that completely filtering out regularization samples also deteriorates distillation performance. Our discoveries inspired us to propose the novel +weighted soft labels to help the network adaptively handle the sample-wise biasvariance tradeoff. Experiments on standard evaluation benchmarks validate the +effectiveness of our method. + +pipeline + +## Results and models + +### Classification + +| Location | Dataset | Teacher | Student | Acc | Acc(T) | Acc(S) | Config | Download | +| :------: | :------: | :----------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------: | :---: | :----: | :----: | :-------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| cls head | ImageNet | [resnet34](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet34_8xb32_in1k.py) | [resnet18](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet18_8xb32_in1k.py) | 71.54 | 73.62 | 69.90 | [config](./wsld_cls_head_resnet34_resnet18_8xb32_in1k.py) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/wsld/wsld_cls_head_resnet34_resnet18_8xb32_in1k/wsld_cls_head_resnet34_resnet18_8xb32_in1k_acc-71.54_20211222-57925cbf.pth) \| [log](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v0.1/distill/wsld/wsld_cls_head_resnet34_resnet18_8xb32_in1k/wsld_cls_head_resnet34_resnet18_8xb32_in1k_20211221_181516.log.json?versionId=CAEQHxiBgIDLmemK7xciIGNkM2FiN2Y4N2E5YjRhNDE4NDVlNmExNDczZDIxN2E5) | + +## Citation + +```latex +@inproceedings{zhou2021wsl, + title={Rethinking soft labels for knowledge distillation: a bias-variance tradeoff perspective}, + author={Helong, Zhou and Liangchen, Song and Jiajie, Chen and Ye, Zhou and Guoli, Wang and Junsong, Yuan and Qian Zhang}, + booktitle = {International Conference on Learning Representations (ICLR)}, + year={2021} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/metafile.yml new file mode 100755 index 000000000..0ba40d523 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/metafile.yml @@ -0,0 +1,38 @@ +Collections: + - Name: WSLD + Metadata: + Training Data: + - ImageNet-1k + Paper: + URL: https://arxiv.org/abs/2102.00650 + Title: Rethinking Soft Labels for Knowledge Distillation:A Bias-Variance Tradeoff Perspective + README: configs/distill/mmcls/wsld/README.md + Code: + URL: https://github.com/open-mmlab/mmrazor/blob/v0.1.0/mmrazor/models/losses/weighted_soft_label_distillation.py + Version: v0.1.0 + Converted From: + Code: https://github.com/bellymonster/Weighted-Soft-Label-Distillation +Models: + - Name: wsld_logits_resnet34_resnet18_8xb32_in1k + In Collection: WSLD + Metadata: + Location: logits + Student: + Config: mmcls::resnet/resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth + Metrics: + Top 1 Accuracy: 69.90 + Top 5 Accuracy: 89.43 + Teacher: + Config: mmcls::resnet/resnet34_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.pth + Metrics: + Top 1 Accuracy: 73.62 + Top 5 Accuracy: 91.59 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 71.54 + Config: configs/distill/mmcls/wsld/wsld_logits_resnet34_resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/wsld/wsld_cls_head_resnet34_resnet18_8xb32_in1k/wsld_cls_head_resnet34_resnet18_8xb32_in1k_acc-71.54_20211222-57925cbf.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/wsld_logits_resnet34_resnet18_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/wsld_logits_resnet34_resnet18_8xb32_in1k.py new file mode 100755 index 000000000..4cf8106b2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/wsld_logits_resnet34_resnet18_8xb32_in1k.py @@ -0,0 +1,41 @@ +_base_ = [ + 'mmcls::_base_/datasets/imagenet_bs32.py', + 'mmcls::_base_/schedules/imagenet_bs256.py', + 'mmcls::_base_/default_runtime.py' +] + +model = dict( + _scope_='mmrazor', + type='SingleTeacherDistill', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb32_in1k.py', pretrained=False), + teacher=dict( + cfg_path='mmcls::resnet/resnet34_8xb32_in1k.py', pretrained=True), + teacher_ckpt= # noqa + 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.pth', # noqa + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc'), + gt_labels=dict(type='ModuleInputs', source='head.loss_module')), + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_wsld=dict(type='WSLD', tau=2, loss_weight=2.5)), + loss_forward_mappings=dict( + loss_wsld=dict( + student=dict(recorder='fc', from_student=True), + teacher=dict(recorder='fc', from_student=False), + gt_labels=dict( + recorder='gt_labels', from_student=True, data_idx=1))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/README.md new file mode 100755 index 000000000..fff123617 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/README.md @@ -0,0 +1,37 @@ +# Zero-shot Knowledge Transfer via Adversarial Belief Matching (ZSKT) + +> [Zero-shot Knowledge Transfer via Adversarial Belief Matching](https://arxiv.org/abs/1905.09768) + + + +## Abstract + +Performing knowledge transfer from a large teacher network to a smaller student is a popular task in modern deep learning applications. However, due to growing dataset sizes and stricter privacy regulations, it is increasingly common not to have access to the data that was used to train the teacher. We propose a novel method which trains a student to match the predictions of its teacher without using any data or metadata. We achieve this by training an adversarial generator to search for images on which the student poorly matches the teacher, and then using them to train the student. Our resulting student closely approximates its teacher for simple datasets like SVHN, and on CIFAR10 we improve on the state-of-the-art for few-shot distillation (with 100 images per class), despite using no data. Finally, we also propose a metric to quantify the degree of belief matching between teacher and student in the vicinity of decision boundaries, and observe a significantly higher match between our zero-shot student and the teacher, than between a student distilled with real data and the teacher. Code available at: https://github.com/polo5/ZeroShotKnowledgeTransfer + +## The teacher and student decision boundaries + +distribution + +## Pseudo images sampled from the generator + +synthesis + +## Results and models + +### Classification + +| Location | Dataset | Teacher | Student | Acc | Acc(T) | Acc(S) | Config | Download | +| :---------------: | :-----: | :-------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------: | :---: | :----: | :----: | :-----------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| backbone & logits | Cifar10 | [resnet34](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet34_8xb16_cifar10.py) | [resnet18](https://github.com/open-mmlab/mmclassification/blob/master/configs/resnet/resnet18_8xb16_cifar10.py) | 93.05 | 95.34 | 94.82 | [config](./zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10.py) | [teacher](https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_b16x8_cifar10_20210528-a8aa36a6.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/ZSKT/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10_20220823_114006-28584c2e.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/ZSKT/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10_20220823_114006-28584c2e.json) | + +## Citation + +```latex +@article{micaelli2019zero, + title={Zero-shot knowledge transfer via adversarial belief matching}, + author={Micaelli, Paul and Storkey, Amos J}, + journal={Advances in Neural Information Processing Systems}, + volume={32}, + year={2019} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/metafile.yml new file mode 100755 index 000000000..54494fa70 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/metafile.yml @@ -0,0 +1,43 @@ +Collections: + - Name: ZSKT + Metadata: + Training Data: + - CIFAR-10 + Paper: + URL: https://arxiv.org/abs/1905.09768 + Title: Zero-shot Knowledge Transfer via Adversarial Belief Matching + README: configs/distill/mmcls/zskt/README.md + Converted From: + Code: + URL: https://github.com/polo5/ZeroShotKnowledgeTransfer +Models: + - Name: zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10 + In Collection: ZSKT + Metadata: + inference time (ms/im): + - value: 0.12 + hardware: NVIDIA A100-SXM4-80GB + backend: PyTorch + batch size: 16 + mode: FP32 + resolution: (32, 32) + Location: backbone & logits + Student: + Config: mmcls::resnet/resnet18_8xb16_cifar10.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_b16x8_cifar10_20210528-bd6371c8.pth + Metrics: + Top 1 Accuracy: 94.82 + Top 5 Accuracy: 99.87 + Teacher: + Config: mmcls::resnet/resnet34_8xb16_cifar10.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_b16x8_cifar10_20210528-a8aa36a6.pth + Metrics: + Top 1 Accuracy: 95.34 + Top 5 Accuracy: 99.87 + Results: + - Task: Image Classification + Dataset: CIFAR-10 + Metrics: + Top 1 Accuracy: 93.05 + Config: configs/distill/mmcls/zskt/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10.py + Weights: https://download.openmmlab.com/mmrazor/v1/ZSKT/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10_20220823_114006-28584c2e.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10.py b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10.py new file mode 100755 index 000000000..5c1ab4242 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10.py @@ -0,0 +1,139 @@ +_base_ = [ + 'mmcls::_base_/datasets/cifar10_bs16.py', + 'mmcls::_base_/schedules/cifar10_bs128.py', + 'mmcls::_base_/default_runtime.py' +] + +res34_ckpt_path = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_b16x8_cifar10_20210528-a8aa36a6.pth' # noqa: E501 +model = dict( + _scope_='mmrazor', + type='DataFreeDistillation', + data_preprocessor=dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[125.307, 122.961, 113.8575], + std=[51.5865, 50.847, 51.255], + # convert image from BGR to RGB + bgr_to_rgb=False), + architecture=dict( + cfg_path='mmcls::resnet/resnet18_8xb16_cifar10.py', pretrained=False), + teachers=dict( + res34=dict( + build_cfg=dict( + cfg_path='mmcls::resnet/resnet34_8xb16_cifar10.py', + pretrained=True), + ckpt_path=res34_ckpt_path)), + generator=dict( + type='ZSKTGenerator', img_size=32, latent_dim=256, + hidden_channels=128), + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + bb_s1=dict(type='ModuleOutputs', source='backbone.layer1.1.relu'), + bb_s2=dict(type='ModuleOutputs', source='backbone.layer2.1.relu'), + bb_s3=dict(type='ModuleOutputs', source='backbone.layer3.1.relu'), + bb_s4=dict(type='ModuleOutputs', source='backbone.layer4.1.relu'), + fc=dict(type='ModuleOutputs', source='head.fc')), + teacher_recorders=dict( + res34_bb_s1=dict( + type='ModuleOutputs', source='res34.backbone.layer1.2.relu'), + res34_bb_s2=dict( + type='ModuleOutputs', source='res34.backbone.layer2.3.relu'), + res34_bb_s3=dict( + type='ModuleOutputs', source='res34.backbone.layer3.5.relu'), + res34_bb_s4=dict( + type='ModuleOutputs', source='res34.backbone.layer4.2.relu'), + res34_fc=dict(type='ModuleOutputs', source='res34.head.fc')), + distill_losses=dict( + loss_s1=dict(type='ATLoss', loss_weight=250.0), + loss_s2=dict(type='ATLoss', loss_weight=250.0), + loss_s3=dict(type='ATLoss', loss_weight=250.0), + loss_s4=dict(type='ATLoss', loss_weight=250.0), + loss_kl=dict( + type='KLDivergence', loss_weight=2.0, reduction='mean')), + loss_forward_mappings=dict( + loss_s1=dict( + s_feature=dict( + from_student=True, recorder='bb_s1', record_idx=1), + t_feature=dict( + from_student=False, recorder='res34_bb_s1', record_idx=1)), + loss_s2=dict( + s_feature=dict( + from_student=True, recorder='bb_s2', record_idx=1), + t_feature=dict( + from_student=False, recorder='res34_bb_s2', record_idx=1)), + loss_s3=dict( + s_feature=dict( + from_student=True, recorder='bb_s3', record_idx=1), + t_feature=dict( + from_student=False, recorder='res34_bb_s3', record_idx=1)), + loss_s4=dict( + s_feature=dict( + from_student=True, recorder='bb_s4', record_idx=1), + t_feature=dict( + from_student=False, recorder='res34_bb_s4', record_idx=1)), + loss_kl=dict( + preds_S=dict(from_student=True, recorder='fc'), + preds_T=dict(from_student=False, recorder='res34_fc')))), + generator_distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + teacher_recorders=dict( + res34_fc=dict(type='ModuleOutputs', source='res34.head.fc')), + distill_losses=dict( + loss_kl=dict( + type='KLDivergence', + loss_weight=-2.0, + reduction='mean', + teacher_detach=False)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(from_student=True, recorder='fc'), + preds_T=dict(from_student=False, recorder='res34_fc')))), + student_iter=10) + +# model wrapper +model_wrapper_cfg = dict( + type='mmengine.MMSeparateDistributedDataParallel', + broadcast_buffers=False, + find_unused_parameters=True) + +# optimizer wrapper +optim_wrapper = dict( + _delete_=True, + constructor='mmrazor.SeparateOptimWrapperConstructor', + architecture=dict( + optimizer=dict(type='SGD', lr=0.1, weight_decay=0.0005, momentum=0.9)), + generator=dict(optimizer=dict(type='Adam', lr=1e-3))) +auto_scale_lr = dict(base_batch_size=16) + +iter_size = 50 + +param_scheduler = dict( + _delete_=True, + architecture=dict( + type='MultiStepLR', + milestones=[100 * iter_size, 200 * iter_size], + by_epoch=False), + generator=dict( + type='MultiStepLR', + milestones=[100 * iter_size, 200 * iter_size], + by_epoch=False)) + +train_cfg = dict( + _delete_=True, by_epoch=False, max_iters=500 * iter_size, val_interval=250) + +train_dataloader = dict( + batch_size=16, sampler=dict(type='InfiniteSampler', shuffle=True)) +val_dataloader = dict(batch_size=16) +val_evaluator = dict(type='Accuracy', topk=(1, 5)) + +default_hooks = dict( + logger=dict(type='LoggerHook', interval=50, log_metric_by_epoch=False), + checkpoint=dict( + type='CheckpointHook', by_epoch=False, interval=100, max_keep_ckpts=2)) + +log_processor = dict(by_epoch=False) +# Must set diff_rank_seed to True! +randomness = dict(seed=None, diff_rank_seed=True) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/README.md new file mode 100755 index 000000000..4805c0696 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/README.md @@ -0,0 +1,37 @@ +# CWD + +> [Channel-wise Knowledge Distillation for Dense Prediction](https://arxiv.org/abs/2011.13256) + + + +## Abstract + +Knowledge distillation (KD) has been proven to be a simple and effective tool for training compact models. Almost all KD variants for dense prediction tasks align the student and teacher networks' feature maps in the spatial domain, typically by minimizing point-wise and/or pair-wise discrepancy. Observing that in semantic segmentation, some layers' feature activations of each channel tend to encode saliency of scene categories (analogue to class activation mapping), we propose to align features channel-wise between the student and teacher networks. To this end, we first transform the feature map of each channel into a probability map using softmax normalization, and then minimize the Kullback-Leibler (KL) divergence of the corresponding channels of the two networks. By doing so, our method focuses on mimicking the soft distributions of channels between networks. In particular, the KL divergence enables learning to pay more attention to the most salient regions of the channel-wise maps, presumably corresponding to the most useful signals for semantic segmentation. Experiments demonstrate that our channel-wise distillation outperforms almost all existing spatial distillation methods for semantic segmentation considerably, and requires less computational cost during training. We consistently achieve superior performance on three benchmarks with various network structures. + +![pipeline](https://user-images.githubusercontent.com/88702197/187424502-d8efb7a3-c40c-4e53-a36c-bd947de464a4.png) + +## Results and models + +### Segmentation + +| Location | Dataset | Teacher | Student | mIoU | mIoU(T) | mIou(S) | Config | Download | +| :------: | :--------: | :------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------: | :---: | :-----: | :-----: | :----------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| logits | cityscapes | [pspnet_r101](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes.py) | [pspnet_r18](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/pspnet/pspnet_r18-d8_512x1024_80k_cityscapes.py) | 75.54 | 79.76 | 74.87 | [config](<>) | [teacher](https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes/pspnet_r101-d8_512x1024_80k_cityscapes_20200606_112211-e1e1100f.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/cwd/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k_mIoU-75.54_20211222-3e643f6f.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/distill/cwd/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k_20211212_205711.log.json) | + +### Detection + +| Location | Dataset | Teacher | Student | mAP | mAP(T) | mAP(S) | Config | Download | +| :------: | :-----: | :--------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | :--: | :----: | :----: | :----------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| cls head | COCO | [gfl_r101_2x](https://github.com/open-mmlab/mmdetection/tree/master/configs/gfl/gfl_r101_fpn_mstrain_2x_coco.py) | [gfl_r50_1x](https://github.com/open-mmlab/mmdetection/tree/master/configs/gfl/gfl_r50_fpn_1x_coco.py) | 41.9 | 44.7 | 40.2 | [config](<>) | [teacher](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_mstrain_2x_coco/gfl_r101_fpn_mstrain_2x_coco_20200629_200126-dd12f847.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco_20211222-c134bb21.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/distill/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco_20211212_205444.log.json) | + +## Citation + +```latex +@inproceedings{shu2021channel, + title={Channel-Wise Knowledge Distillation for Dense Prediction}, + author={Shu, Changyong and Liu, Yifan and Gao, Jianfei and Yan, Zheng and Shen, Chunhua}, + booktitle={Proceedings of the IEEE/CVF International Conference on Computer Vision}, + pages={5311--5320}, + year={2021} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py new file mode 100755 index 000000000..92612046f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py @@ -0,0 +1,9 @@ +_base_ = ['./cwd_fpn_retina_r101_retina_r50_1x_coco.py'] + +teacher_ckpt = 'https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_mstrain_2x_coco/gfl_r101_fpn_mstrain_2x_coco_20200629_200126-dd12f847.pth' # noqa: E501 +model = dict( + architecture=dict( + cfg_path='mmdet::gfl/gfl_r50_fpn_1x_coco.py', pretrained=False), + teacher=dict( + cfg_path='mmdet::gfl/gfl_r101_fpn_ms-2x_coco.py', pretrained=True), + teacher_ckpt=teacher_ckpt) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py new file mode 100755 index 000000000..56756d426 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py @@ -0,0 +1,54 @@ +_base_ = [ + 'mmdet::_base_/datasets/coco_detection.py', + 'mmdet::_base_/schedules/schedule_1x.py', + 'mmdet::_base_/default_runtime.py' +] + +# default_scope = 'mmrazor' +teacher_ckpt = 'faster_rcnn_r101_fpn_2x_coco_bbox_mAP-0.398_20200504_210455-1d2dac9c.pth' # noqa: E501 +model = dict( + _scope_='mmrazor', + type='FpnTeacherDistill', + architecture=dict( + cfg_path='mmdet::faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py', + pretrained=False), + teacher=dict( + cfg_path='mmdet::faster_rcnn/faster_rcnn_r101_fpn_2x_coco.py', + pretrained=False), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict(fpn=dict(type='ModuleOutputs', source='neck')), + teacher_recorders=dict(fpn=dict(type='ModuleOutputs', source='neck')), + distill_losses=dict( + loss_cwd_fpn0=dict( + type='ChannelWiseDivergence', tau=1, loss_weight=10), + loss_cwd_fpn1=dict( + type='ChannelWiseDivergence', tau=1, loss_weight=10), + loss_cwd_fpn2=dict( + type='ChannelWiseDivergence', tau=1, loss_weight=10), + loss_cwd_fpn3=dict( + type='ChannelWiseDivergence', tau=1, loss_weight=10), + loss_cwd_fpn4=dict( + type='ChannelWiseDivergence', tau=1, loss_weight=10)), + loss_forward_mappings=dict( + loss_cwd_fpn0=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=0), + preds_T=dict(from_student=False, recorder='fpn', data_idx=0)), + loss_cwd_fpn1=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=1), + preds_T=dict(from_student=False, recorder='fpn', data_idx=1)), + loss_cwd_fpn2=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=2), + preds_T=dict(from_student=False, recorder='fpn', data_idx=2)), + loss_cwd_fpn3=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=3), + preds_T=dict(from_student=False, recorder='fpn', data_idx=3)), + loss_cwd_fpn4=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=4), + preds_T=dict(from_student=False, recorder='fpn', + data_idx=4))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco.py new file mode 100755 index 000000000..682a5cfc8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco.py @@ -0,0 +1,13 @@ +_base_ = ['./cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py'] + +model = dict( + architecture=dict( + cfg_path='mmdet::retinanet/retinanet_r50_fpn_1x_coco.py', + pretrained=False), + teacher=dict( + cfg_path='mmdet::retinanet/retinanet_r101_fpn_2x_coco.py', + pretrained=True)) + +# optimizer +optim_wrapper = dict( + optimizer=dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001)) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco_visualization.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco_visualization.py new file mode 100755 index 000000000..13947952a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco_visualization.py @@ -0,0 +1,21 @@ +_base_ = ['./cwd_fpn_retina_r101_retina_r50_1x_coco.py'] + +default_hooks = dict( + checkpoint=dict(type='CheckpointHook', interval=-1), + visualization=dict( + _scope_='mmrazor', + type='RazorVisualizationHook', + enabled=True, + recorders=dict( + # todo: Maybe it is hard for users to understand why to add a + # prefix `architecture.` + neck=dict( + _scope_='mmrazor', + type='ModuleOutputs', + source='architecture.neck')), + mappings=dict( + p3=dict(recorder='neck', data_idx=0), + p4=dict(recorder='neck', data_idx=1), + p5=dict(recorder='neck', data_idx=2), + p6=dict(recorder='neck', data_idx=3)), + out_dir='retina_vis')) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/metafile.yml new file mode 100755 index 000000000..f2375c366 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/metafile.yml @@ -0,0 +1,23 @@ + +Models: + - Name: cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco + In Collection: CWD + Metadata: + Location: cls head + Student: + Metrics: + box AP: 40.2 + Config: mmdet::gfl/gfl_r50_fpn_1x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r50_fpn_1x_coco/gfl_r50_fpn_1x_coco_20200629_121244-25944287.pth + Teacher: + Metrics: + box AP: 44.7 + Config: mmdet::gfl/gfl_r50_fpn_mstrain_2x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_mstrain_2x_coco/gfl_r101_fpn_mstrain_2x_coco_20200629_200126-dd12f847.pth + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.9 + Config: configs/distill/mmdet/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py + Weights: https://download.openmmlab.com/mmrazor/v1/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco_20211222-c134bb21.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/README.md new file mode 100755 index 000000000..cded5983d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/README.md @@ -0,0 +1,37 @@ +# IMPROVE OBJECT DETECTION WITH FEATURE-BASED KNOWLEDGE DISTILLATION: TOWARDS ACCURATE AND EFFICIENT DETECTORS (FBKD) + +> [IMPROVE OBJECT DETECTION WITH FEATURE-BASED KNOWLEDGE DISTILLATION: TOWARDS ACCURATE AND EFFICIENT DETECTORS](https://openreview.net/pdf?id=uKhGRvM8QNH) + + + +## Abstract + +Knowledge distillation, in which a student model is trained to mimic a teacher model, has been proved as an effective technique for model compression and model accuracy boosting. However, most knowledge distillation methods, designed for image classification, have failed on more challenging tasks, such as object detection. In this paper, we suggest that the failure of knowledge distillation on object detection is mainly caused by two reasons: (1) the imbalance between pixels of foreground and background and (2) lack of distillation on the relation between different pixels. Observing the above reasons, we propose attention-guided distillation and non-local distillation to address the two problems, respectively. Attention-guided distillation is proposed to find the crucial pixels of foreground objects with attention mechanism and then make the students take more effort to learn their features. Non-local distillation is proposed to enable students to learn not only the feature of an individual pixel but also the relation between different pixels captured by non-local modules. Experiments show that our methods achieve excellent AP improvements on both one-stage and two-stage, both anchor-based and anchor-free detectors. For example, Faster RCNN (ResNet101 backbone) with our distillation achieves 43.9 AP on COCO2017, which is 4.1 higher than the baseline. + +pipeline + +## Results and models + +### Detection + +| Location | Dataset | Teacher | Student | box AP | box AP(T) | box AP(S) | Config | Download | +| :------: | :-----: | :--------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :----: | :-------: | :-------: | :------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| neck | COCO | [faster-rcnn_resnet101](https://github.com/open-mmlab/mmdetection/blob/master/configs/faster_rcnn/faster_rcnn_r101_fpn_1x_coco.py) | [faster-rcnn_resnet50](https://github.com/open-mmlab/mmdetection/blob/master/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py) | 39.3 | 39.4 | 37.4 | [config](./fbkd_fpn_frcnn_resnet101_frcnn_resnet50_1x_coco.py) | [teacher](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_1x_coco/faster_rcnn_r101_fpn_1x_coco_20200130-f513f705.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/FBKD/fbkd_fpn_frcnn_resnet101_frcnn_resnet50_1x_coco_20220830_121522-8d7e11df.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/FBKD/fbkd_fpn_frcnn_resnet101_frcnn_resnet50_1x_coco_20220830_121522-8d7e11df.json) | + +## Citation + +```latex +@inproceedings{DBLP:conf/iclr/ZhangM21, + author = {Linfeng Zhang and Kaisheng Ma}, + title = {Improve Object Detection with Feature-based Knowledge Distillation: + Towards Accurate and Efficient Detectors}, + booktitle = {9th International Conference on Learning Representations, {ICLR} 2021, + Virtual Event, Austria, May 3-7, 2021}, + publisher = {OpenReview.net}, + year = {2021}, + url = {https://openreview.net/forum?id=uKhGRvM8QNH}, + timestamp = {Wed, 23 Jun 2021 17:36:39 +0200}, + biburl = {https://dblp.org/rec/conf/iclr/ZhangM21.bib}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/fbkd_fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/fbkd_fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco.py new file mode 100755 index 000000000..3203e3fea --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/fbkd_fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco.py @@ -0,0 +1,126 @@ +_base_ = [ + 'mmdet::_base_/datasets/coco_detection.py', + 'mmdet::_base_/schedules/schedule_1x.py', + 'mmdet::_base_/default_runtime.py' +] + +teacher_ckpt = 'https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_1x_coco/faster_rcnn_r101_fpn_1x_coco_20200130-f513f705.pth' # noqa: E501 +model = dict( + _scope_='mmrazor', + type='SingleTeacherDistill', + architecture=dict( + cfg_path='mmdet::faster_rcnn/faster-rcnn_r50_fpn_1x_coco.py', + pretrained=True), + teacher=dict( + cfg_path='mmdet::faster_rcnn/faster-rcnn_r101_fpn_1x_coco.py', + pretrained=False), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + neck_s0=dict(type='ModuleOutputs', source='neck.fpn_convs.0.conv'), + neck_s1=dict(type='ModuleOutputs', source='neck.fpn_convs.1.conv'), + neck_s2=dict(type='ModuleOutputs', source='neck.fpn_convs.2.conv'), + neck_s3=dict(type='ModuleOutputs', + source='neck.fpn_convs.3.conv')), + teacher_recorders=dict( + neck_s0=dict(type='ModuleOutputs', source='neck.fpn_convs.0.conv'), + neck_s1=dict(type='ModuleOutputs', source='neck.fpn_convs.1.conv'), + neck_s2=dict(type='ModuleOutputs', source='neck.fpn_convs.2.conv'), + neck_s3=dict(type='ModuleOutputs', + source='neck.fpn_convs.3.conv')), + distill_losses=dict( + loss_s0=dict(type='FBKDLoss'), + loss_s1=dict(type='FBKDLoss'), + loss_s2=dict(type='FBKDLoss'), + loss_s3=dict(type='FBKDLoss')), + connectors=dict( + loss_s0_sfeat=dict( + type='FBKDStudentConnector', + in_channels=256, + reduction=4, + mode='dot_product', + sub_sample=True, + maxpool_stride=8), + loss_s0_tfeat=dict( + type='FBKDTeacherConnector', + in_channels=256, + reduction=4, + mode='dot_product', + sub_sample=True, + maxpool_stride=8), + loss_s1_sfeat=dict( + type='FBKDStudentConnector', + in_channels=256, + reduction=4, + mode='dot_product', + sub_sample=True, + maxpool_stride=4), + loss_s1_tfeat=dict( + type='FBKDTeacherConnector', + in_channels=256, + reduction=4, + mode='dot_product', + sub_sample=True, + maxpool_stride=4), + loss_s2_sfeat=dict( + type='FBKDStudentConnector', + in_channels=256, + mode='dot_product', + sub_sample=True), + loss_s2_tfeat=dict( + type='FBKDTeacherConnector', + in_channels=256, + mode='dot_product', + sub_sample=True), + loss_s3_sfeat=dict( + type='FBKDStudentConnector', + in_channels=256, + mode='dot_product', + sub_sample=True), + loss_s3_tfeat=dict( + type='FBKDTeacherConnector', + in_channels=256, + mode='dot_product', + sub_sample=True)), + loss_forward_mappings=dict( + loss_s0=dict( + s_input=dict( + from_student=True, + recorder='neck_s0', + connector='loss_s0_sfeat'), + t_input=dict( + from_student=False, + recorder='neck_s0', + connector='loss_s0_tfeat')), + loss_s1=dict( + s_input=dict( + from_student=True, + recorder='neck_s1', + connector='loss_s1_sfeat'), + t_input=dict( + from_student=False, + recorder='neck_s1', + connector='loss_s1_tfeat')), + loss_s2=dict( + s_input=dict( + from_student=True, + recorder='neck_s2', + connector='loss_s2_sfeat'), + t_input=dict( + from_student=False, + recorder='neck_s2', + connector='loss_s2_tfeat')), + loss_s3=dict( + s_input=dict( + from_student=True, + recorder='neck_s3', + connector='loss_s3_sfeat'), + t_input=dict( + from_student=False, + recorder='neck_s3', + connector='loss_s3_tfeat'))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/metafile.yml new file mode 100755 index 000000000..aa8c1eaea --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/metafile.yml @@ -0,0 +1,41 @@ +Collections: + - Name: FBKD + Metadata: + Training Data: + - COCO + Paper: + URL: https://openreview.net/pdf?id=uKhGRvM8QNH + Title: IMPROVE OBJECT DETECTION WITH FEATURE-BASED KNOWLEDGE DISTILLATION- TOWARDS ACCURATE AND EFFICIENT DETECTORS + README: configs/distill/mmdet/fbkd/README.md + Converted From: + Code: + URL: https://github.com/ArchipLab-LinfengZhang/Object-Detection-Knowledge-Distillation-ICLR2021 +Models: + - Name: fbkd_fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco + In Collection: FBKD + Metadata: + inference time (ms/im): + - value: 0.32 + hardware: NVIDIA A100-SXM4-80GB + backend: PyTorch + batch size: 2 + mode: FP32 + resolution: (1333, 800) + Location: fpn + Student: + Metrics: + box AP: 37.4 + Config: mmdet::faster_rcnn/faster-rcnn_r50_fpn_1x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth + Teacher: + Metrics: + box AP: 39.4 + Config: mmdet::faster_rcnn/faster-rcnn_r101_fpn_1x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_1x_coco/faster_rcnn_r101_fpn_1x_coco_20200130-f513f705.pth + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 39.3 + Config: configs/distill/mmdet/fbkd/fbkd_fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco.py + Weights: https://download.openmmlab.com/mmrazor/v1/FBKD/fbkd_fpn_frcnn_resnet101_frcnn_resnet50_1x_coco_20220830_121522-8d7e11df.pth diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/README.md new file mode 100755 index 000000000..19c52ac4b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/README.md @@ -0,0 +1,30 @@ +# MGD + +> [Masked Generative Distillation](https://arxiv.org/abs/2205.01529) + + + +## Abstract + +Knowledge distillation has been applied to various tasks successfully. The current distillation algorithm usually improves students' performance by imitating the output of the teacher. This paper shows that teachers can also improve students' representation power by guiding students' feature recovery. From this point of view, we propose Masked Generative Distillation (MGD), which is simple: we mask random pixels of the student's feature and force it to generate the teacher's full feature through a simple block. MGD is a truly general feature-based distillation method, which can be utilized on various tasks, including image classification, object detection, semantic segmentation and instance segmentation. We experiment on different models with extensive datasets and the results show that all the students achieve excellent improvements. Notably, we boost ResNet-18 from 69.90% to 71.69% ImageNet top-1 accuracy, RetinaNet with ResNet-50 backbone from 37.4 to 41.0 Boundingbox mAP, SOLO based on ResNet-50 from 33.1 to 36.2 Mask mAP and DeepLabV3 based on ResNet-18 from 73.20 to 76.02 mIoU. + +![pipeline](https://github.com/yzd-v/MGD/raw/master/architecture.png) + +## Results and models + +### Detection + +| Location | Dataset | Teacher | Student | Lr schd | mAP | mAP(T) | mAP(S) | Config | Download | +| :------: | :-----: | :----------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------: | :-----: | :--: | :----: | :----: | :-------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| FPN | COCO | [RetinaNet-X101](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/retinanet/retinanet_x101-64x4d_fpn_1x_coco.py) | [RetinaNet-R50](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/retinanet/retinanet_r50_fpn_2x_coco.py) | 2x | 41.0 | 41.0 | 37.4 | [config](mgd_fpn_retina_x101_retina_r50_2x_coco.py) | [teacher](https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_x101_64x4d_fpn_1x_coco/retinanet_x101_64x4d_fpn_1x_coco_20200130-366f5af1.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/mgd/mgd_fpn_retina_x101_retina_r50_2x_coco_20221209_191847-87141529.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/mgd/mgd_fpn_retina_x101_retina_r50_2x_coco_20221209_191847-87141529.log) | + +## Citation + +```latex +@article{yang2022masked, + title={Masked Generative Distillation}, + author={Yang, Zhendong and Li, Zhe and Shao, Mingqi and Shi, Dachuan and Yuan, Zehuan and Yuan, Chun}, + journal={arXiv preprint arXiv:2205.01529}, + year={2022} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/mgd_fpn_retina_x101_retina_r50_2x_coco.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/mgd_fpn_retina_x101_retina_r50_2x_coco.py new file mode 100755 index 000000000..9a416cd8b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/mgd_fpn_retina_x101_retina_r50_2x_coco.py @@ -0,0 +1,118 @@ +_base_ = ['mmdet::retinanet/retinanet_r50_fpn_2x_coco.py'] + +teacher_ckpt = 'https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_x101_64x4d_fpn_1x_coco/retinanet_x101_64x4d_fpn_1x_coco_20200130-366f5af1.pth' # noqa: E501 + +student = _base_.model +student.neck.init_cfg = dict( + type='Pretrained', prefix='neck.', checkpoint=teacher_ckpt) +student.bbox_head.init_cfg = dict( + type='Pretrained', prefix='bbox_head.', checkpoint=teacher_ckpt) + +model = dict( + _scope_='mmrazor', + _delete_=True, + type='FpnTeacherDistill', + architecture=student, + teacher=dict( + cfg_path='mmdet::retinanet/retinanet_x101-64x4d_fpn_1x_coco.py', + pretrained=False), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fpn0=dict(type='ModuleOutputs', source='neck.fpn_convs.0.conv'), + fpn1=dict(type='ModuleOutputs', source='neck.fpn_convs.1.conv'), + fpn2=dict(type='ModuleOutputs', source='neck.fpn_convs.2.conv'), + fpn3=dict(type='ModuleOutputs', source='neck.fpn_convs.3.conv'), + fpn4=dict(type='ModuleOutputs', source='neck.fpn_convs.4.conv')), + teacher_recorders=dict( + fpn0=dict(type='ModuleOutputs', source='neck.fpn_convs.0.conv'), + fpn1=dict(type='ModuleOutputs', source='neck.fpn_convs.1.conv'), + fpn2=dict(type='ModuleOutputs', source='neck.fpn_convs.2.conv'), + fpn3=dict(type='ModuleOutputs', source='neck.fpn_convs.3.conv'), + fpn4=dict(type='ModuleOutputs', source='neck.fpn_convs.4.conv')), + connectors=dict( + s_fpn0_connector=dict( + type='MGDConnector', + student_channels=256, + teacher_channels=256, + lambda_mgd=0.65), + s_fpn1_connector=dict( + type='MGDConnector', + student_channels=256, + teacher_channels=256, + lambda_mgd=0.65), + s_fpn2_connector=dict( + type='MGDConnector', + student_channels=256, + teacher_channels=256, + lambda_mgd=0.65), + s_fpn3_connector=dict( + type='MGDConnector', + student_channels=256, + teacher_channels=256, + lambda_mgd=0.65), + s_fpn4_connector=dict( + type='MGDConnector', + student_channels=256, + teacher_channels=256, + lambda_mgd=0.65)), + distill_losses=dict( + loss_mgd_fpn0=dict(type='MGDLoss', alpha_mgd=0.00002), + loss_mgd_fpn1=dict(type='MGDLoss', alpha_mgd=0.00002), + loss_mgd_fpn2=dict(type='MGDLoss', alpha_mgd=0.00002), + loss_mgd_fpn3=dict(type='MGDLoss', alpha_mgd=0.00002), + loss_mgd_fpn4=dict(type='MGDLoss', alpha_mgd=0.00002)), + loss_forward_mappings=dict( + loss_mgd_fpn0=dict( + preds_S=dict( + from_student=True, + recorder='fpn0', + connector='s_fpn0_connector'), + preds_T=dict(from_student=False, recorder='fpn0')), + loss_mgd_fpn1=dict( + preds_S=dict( + from_student=True, + recorder='fpn1', + connector='s_fpn1_connector'), + preds_T=dict(from_student=False, recorder='fpn1')), + loss_mgd_fpn2=dict( + preds_S=dict( + from_student=True, + recorder='fpn2', + connector='s_fpn2_connector'), + preds_T=dict(from_student=False, recorder='fpn2')), + loss_mgd_fpn3=dict( + preds_S=dict( + from_student=True, + recorder='fpn3', + connector='s_fpn3_connector'), + preds_T=dict(from_student=False, recorder='fpn3')), + loss_mgd_fpn4=dict( + preds_S=dict( + from_student=True, + recorder='fpn4', + connector='s_fpn4_connector'), + preds_T=dict(from_student=False, recorder='fpn4'))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') + +optimizer_config = dict( + _delete_=True, grad_clip=dict(max_norm=35, norm_type=2)) + +param_scheduler = [ + dict( + type='LinearLR', start_factor=0.001, by_epoch=False, begin=0, end=500), + dict( + type='MultiStepLR', + begin=0, + end=24, + by_epoch=True, + milestones=[16, 22], + gamma=0.1) +] + +optim_wrapper = dict( + optimizer=dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0001)) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/README.md new file mode 100755 index 000000000..a25dc5ae8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/README.md @@ -0,0 +1,34 @@ +# PKD + +> [PKD: General Distillation Framework for Object Detectors via Pearson Correlation Coefficient](https://arxiv.org/abs/2207.02039) + + + +## Abstract + +Knowledge distillation(KD) is a widely-used technique to train compact models in object detection. However, there is still a lack of study on how to distill between heterogeneous detectors. In this paper, we empirically find that better FPN features from a heterogeneous teacher detector can help the student although their detection heads and label assignments are different. However, directly aligning the feature maps to distill detectors suffers from two problems. First, the difference in feature magnitude between the teacher and the student could enforce overly strict constraints on the student. Second, the FPN stages and channels with large feature magnitude from the teacher model could dominate the gradient of distillation loss, which will overwhelm the effects of other features in KD and introduce much noise. To address the above issues, we propose to imitate features with Pearson Correlation Coefficient to focus on the relational information from the teacher and relax constraints on the magnitude of the features. Our method consistently outperforms the existing detection KD methods and works for both homogeneous and heterogeneous student-teacher pairs. Furthermore, it converges faster. With a powerful MaskRCNN-Swin detector as the teacher, ResNet-50 based RetinaNet and FCOS achieve 41.5% and 43.9% mAP on COCO2017, which are 4.1% and 4.8% higher than the baseline, respectively. + +![pipeline](https://user-images.githubusercontent.com/41630003/197719796-76fa5f33-1d54-4927-8a08-86f5c6e33879.png) + +## Results and models + +### Detection + +| Location | Dataset | Teacher | Student | Lr schd | mAP | mAP(T) | mAP(S) | Config | Download | +| :------: | :-----: | :--------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------: | :-----: | :--: | :----: | :----: | :-----------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| FPN | COCO | [FCOS-X101](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/fcos/fcos_x101-64x4d_fpn_gn-head_ms-640-800-2x_coco.py) | [RetinaNet-R50](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/retinanet/retinanet_r50_fpn_1x_coco.py) | 1x | 40.3 | 42.6 | 36.5 | [config](pkd_fpn_fcos_x101_retina_r50_1x_coco.py) | [teacher](https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco-ede514a8.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_fcos_retina/pkd_fpn_fcos_x101_retina_r50_1x_coco_20220925_181547-9cac5059.pth?versionId=CAEQThiBgMCLyNC0oBgiIDBjY2FkY2JlNGFiYzRmM2RiZGUyYzM1NjQxYzQxODA4) \| [log](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_fcos_retina/pkd_fpn_fcos_x101_retina_r50_1x_coco_20220925_181547-9cac5059.json?versionId=CAEQThiBgMDA0dS0oBgiIDM4ZjZlZmVkMzc4MjQxMGJiN2FlMDFlOTA2NGIzZGQ4) | +| FPN | COCO | [Faster-Rcnn-R101](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/faster_rcnn/faster-rcnn_r101_fpn_2x_coco.py) | [Faster-rcnn-R50](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/faster_rcnn/faster-rcnn_r50_fpn_2x_coco.py) | 2x | 40.3 | 39.8 | 38.4 | [config](pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py) | [teacher](https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_2x_coco/faster_rcnn_r101_fpn_2x_coco_bbox_mAP-0.398_20200504_210455-1d2dac9c.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_frcnn/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco_20221014_103040-3efbd439.pth?versionId=CAEQThiBgMDQr9C0oBgiIDMyZWE1Y2ZlMDA2ZDQ2ZGNhZmQ3NzMxODk3YzgzYWFl) \| [log](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_frcnn/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco_20221014_103040-3efbd439.json?versionId=CAEQThiBgICYsNC0oBgiIDdhNWY5ZjZlYjUyNzRjMGU4NGFhYzk4NzQwZDAxY2Rj) | +| FPN | COCO | [Mask-Rcnn-Swin](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/swin/mask-rcnn_swin-s-p4-w7_fpn_amp-ms-crop-3x_coco.py) | [RetinaNet-R50](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/retinanet/retinanet_r50_fpn_2x_coco.py) | 2x | 41.5 | 48.2 | 37.4 | [config](pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py) | [teacher](https://download.openmmlab.com/mmdetection/v2.0/swin/mask_rcnn_swin-t-p4-w7_fpn_1x_coco/mask_rcnn_swin-t-p4-w7_fpn_1x_coco_20210902_120937-9d6b7cfa.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_swin_retina/pkd_fpn_mask_rcnn_swin_retina_r50_2x_coco_20220925_142555-edec7433.pth?versionId=CAEQThiBgIDWqNC0oBgiIDViOGE0ZDU4ODgxNzQ5YmE5OGU3MzRkMjFiZGRjZmRm) \| [log](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_swin_retina/pkd_fpn_mask_rcnn_swin_retina_r50_2x_coco_20220925_142555-edec7433.json?versionId=CAEQThiBgIDVqdC0oBgiIDU3YzFjOWRmNWY3NTRmYjFhMDdmNzU2ODE3MzdlZThk) | +| FPN | COCO | [Reppoints-X101-dcn](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/reppoints/reppoints-moment_x101-dconv-c3-c5_fpn-gn_head-gn_2x_coco.py) | [Reppoints-R50](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/reppoints/reppoints-moment_r50_fpn-gn_head-gn_2x_coco.py) | 2x | 42.3 | 44.2 | 38.6 | [config](pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py) | [teacher](https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco_20200329-f87da1ea.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_reppoints/pkd_fpn_reppoints_x101_dcn_reppoints_r50_2x_coco_20220926_145818-f8932e12.pth?versionId=CAEQThiBgIC8rNC0oBgiIGU2N2IxM2NkMjNlMjQyN2E4YmVlNmViNGI2MDY3OTE5) \| [log](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_reppoints/pkd_fpn_reppoints_x101_dcn_reppoints_r50_2x_coco_20220926_145818-f8932e12.json?versionId=CAEQThiBgICordC0oBgiIDJhMjBjOGZiN2UxNjQxYmI5MzE3NWVhZDgxZDE2NmJm) | +| FPN | COCO | [RetinaNet-X101](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/retinanet/retinanet_x101-64x4d_fpn_1x_coco.py) | [RetinaNet-R50](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/retinanet/retinanet_r50_fpn_2x_coco.py) | 2x | 40.8 | 41.0 | 37.4 | [config](pkd_fpn_retina_x101_retina_r50_2x_coco.py) | [teacher](https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_x101_64x4d_fpn_1x_coco/retinanet_x101_64x4d_fpn_1x_coco_20200130-366f5af1.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_retinax_retina/pkd_fpn_retina_x101_retina_r50_2x_coco_20221014_232526-4c0f8d96.pth?versionId=CAEQThiBgIDQqdC0oBgiIGFmZjNmZmE4NDFiMDQ4MzhiMzdjOGI2NzI4MTQxMjFi) \| [log](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_retinax_retina/pkd_fpn_retina_x101_retina_r50_2x_coco_20221014_232526-4c0f8d96.json?versionId=CAEQThiBgMC2qdC0oBgiIGRkMTIzODYwMzliMDQ3M2JiYjNlYjA5N2I4Y2QzMGFl) | + +## Citation + +```latex +@article{cao2022pkd, + title={PKD: General Distillation Framework for Object Detectors via Pearson Correlation Coefficient}, + author={Cao, Weihan and Zhang, Yifan and Gao, Jianfei and Cheng, Anda and Cheng, Ke and Cheng, Jian}, + journal={arXiv preprint arXiv:2207.02039}, + year={2022} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/metafile.yml new file mode 100755 index 000000000..6ea2347b5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/metafile.yml @@ -0,0 +1,110 @@ +Models: + - Name: pkd_fpn_fcos_x101_retina_r50_1x_coco + In Collection: PKD + Metadata: + Location: FPN + Student: + Metrics: + box AP: 36.5 + Config: mmdet::retinanet/retinanet_r50_fpn_1x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_1x_coco/retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth + Teacher: + Metrics: + box AP: 42.6 + Config: mmdet::fcos/fcos_x101-64x4d_fpn_gn-head_ms-640-800-2x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco-ede514a8.pth + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.3 + Config: configs/distill/mmdet/pkd/pkd_fpn_fcos_x101_retina_r50_1x_coco.py + Weights: https://download.openmmlab.com/mmrazor/v1/pkd/pkd_fcos_retina/pkd_fpn_fcos_x101_retina_r50_1x_coco_20220925_181547-9cac5059.pth?versionId=CAEQThiBgMCLyNC0oBgiIDBjY2FkY2JlNGFiYzRmM2RiZGUyYzM1NjQxYzQxODA4 + + - Name: pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco + In Collection: PKD + Metadata: + Location: FPN + Student: + Metrics: + box AP: 38.4 + Config: mmdet::faster_rcnn/faster-rcnn_r50_fpn_2x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_2x_coco/faster_rcnn_r50_fpn_2x_coco_bbox_mAP-0.384_20200504_210434-a5d8aa15.pth + Teacher: + Metrics: + box AP: 39.8 + Config: mmdet::faster_rcnn/faster-rcnn_r101_fpn_2x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_2x_coco/faster_rcnn_r101_fpn_2x_coco_bbox_mAP-0.398_20200504_210455-1d2dac9c.pth + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.4 + Config: configs/distill/mmdet/pkd/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py + Weights: https://download.openmmlab.com/mmrazor/v1/pkd/pkd_frcnn/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco_20221014_103040-3efbd439.pth?versionId=CAEQThiBgMDQr9C0oBgiIDMyZWE1Y2ZlMDA2ZDQ2ZGNhZmQ3NzMxODk3YzgzYWFl + + - Name: pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco + In Collection: PKD + Metadata: + Location: FPN + Student: + Metrics: + box AP: 37.4 + Config: mmdet::retinanet/retinanet_r50_fpn_2x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_2x_coco/retinanet_r50_fpn_2x_coco_20200131-fdb43119.pth + Teacher: + Metrics: + box AP: 48.2 + Config: mmdet::swin/mask-rcnn_swin-s-p4-w7_fpn_amp-ms-crop-3x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/swin/mask_rcnn_swin-t-p4-w7_fpn_1x_coco/mask_rcnn_swin-t-p4-w7_fpn_1x_coco_20210902_120937-9d6b7cfa.pth + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 41.5 + Config: configs/distill/mmdet/pkd/pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py + Weights: https://download.openmmlab.com/mmrazor/v1/pkd/pkd_swin_retina/pkd_fpn_mask_rcnn_swin_retina_r50_2x_coco_20220925_142555-edec7433.pth?versionId=CAEQThiBgIDWqNC0oBgiIDViOGE0ZDU4ODgxNzQ5YmE5OGU3MzRkMjFiZGRjZmRm + + - Name: pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco + In Collection: PKD + Metadata: + Location: FPN + Student: + Metrics: + box AP: 38.6 + Config: mmdet::reppoints/reppoints-moment_r50_fpn-gn_head-gn_2x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_r50_fpn_gn-neck%2Bhead_2x_coco/reppoints_moment_r50_fpn_gn-neck%2Bhead_2x_coco_20200329-91babaa2.pth + Teacher: + Metrics: + box AP: 44.2 + Config: mmdet::reppoints/reppoints-moment_x101-dconv-c3-c5_fpn-gn_head-gn_2x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco_20200329-f87da1ea.pth + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 42.3 + Config: configs/distill/mmdet/pkd/pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py + Weights: https://download.openmmlab.com/mmrazor/v1/pkd/pkd_reppoints/pkd_fpn_reppoints_x101_dcn_reppoints_r50_2x_coco_20220926_145818-f8932e12.pth?versionId=CAEQThiBgIC8rNC0oBgiIGU2N2IxM2NkMjNlMjQyN2E4YmVlNmViNGI2MDY3OTE5 + + - Name: pkd_fpn_retina_x101_retina_r50_2x_coco + In Collection: PKD + Metadata: + Location: FPN + Student: + Metrics: + box AP: 37.4 + Config: mmdet::retinanet/retinanet_r50_fpn_2x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_2x_coco/retinanet_r50_fpn_2x_coco_20200131-fdb43119.pth + Teacher: + Metrics: + box AP: 41.0 + Config: mmdet::retinanet/retinanet_x101-64x4d_fpn_1x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_x101_64x4d_fpn_1x_coco/retinanet_x101_64x4d_fpn_1x_coco_20200130-366f5af1.pth + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 40.8 + Config: configs/distill/mmdet/pkd/pkd_fpn_retina_x101_retina_r50_2x_coco.py + Weights: https://download.openmmlab.com/mmrazor/v1/pkd/pkd_retinax_retina/pkd_fpn_retina_x101_retina_r50_2x_coco_20221014_232526-4c0f8d96.pth?versionId=CAEQThiBgIDQqdC0oBgiIGFmZjNmZmE4NDFiMDQ4MzhiMzdjOGI2NzI4MTQxMjFi diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py new file mode 100755 index 000000000..c9496792d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py @@ -0,0 +1,45 @@ +_base_ = [ + 'mmdet::_base_/datasets/coco_detection.py', + 'mmdet::_base_/schedules/schedule_2x.py', + 'mmdet::_base_/default_runtime.py' +] + +teacher_ckpt = 'https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r101_fpn_2x_coco/faster_rcnn_r101_fpn_2x_coco_bbox_mAP-0.398_20200504_210455-1d2dac9c.pth' # noqa: E501 + +model = dict( + _scope_='mmrazor', + type='FpnTeacherDistill', + architecture=dict( + cfg_path='mmdet::faster_rcnn/faster-rcnn_r50_fpn_2x_coco.py', + pretrained=False), + teacher=dict( + cfg_path='mmdet::faster_rcnn/faster-rcnn_r101_fpn_2x_coco.py', + pretrained=False), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict(fpn=dict(type='ModuleOutputs', source='neck')), + teacher_recorders=dict(fpn=dict(type='ModuleOutputs', source='neck')), + distill_losses=dict( + loss_pkd_fpn0=dict(type='PKDLoss', loss_weight=6), + loss_pkd_fpn1=dict(type='PKDLoss', loss_weight=6), + loss_pkd_fpn2=dict(type='PKDLoss', loss_weight=6), + loss_pkd_fpn3=dict(type='PKDLoss', loss_weight=6)), + loss_forward_mappings=dict( + loss_pkd_fpn0=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=0), + preds_T=dict(from_student=False, recorder='fpn', data_idx=0)), + loss_pkd_fpn1=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=1), + preds_T=dict(from_student=False, recorder='fpn', data_idx=1)), + loss_pkd_fpn2=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=2), + preds_T=dict(from_student=False, recorder='fpn', data_idx=2)), + loss_pkd_fpn3=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=3), + preds_T=dict(from_student=False, recorder='fpn', + data_idx=3))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_fcos_x101_retina_r50_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_fcos_x101_retina_r50_1x_coco.py new file mode 100755 index 000000000..3a8059acc --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_fcos_x101_retina_r50_1x_coco.py @@ -0,0 +1,27 @@ +_base_ = ['./pkd_fpn_retina_x101_retina_r50_2x_coco.py'] + +teacher_ckpt = 'https://download.openmmlab.com/mmdetection/v2.0/fcos/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco/fcos_x101_64x4d_fpn_gn-head_mstrain_640-800_2x_coco-ede514a8.pth' # noqa: E501 + +model = dict( + architecture=dict( + cfg_path='mmdet::retinanet/retinanet_r50_fpn_1x_coco.py'), + teacher=dict( + cfg_path= # noqa: E251 + 'mmdet::fcos/fcos_x101-64x4d_fpn_gn-head_ms-640-800-2x_coco.py'), + teacher_ckpt=teacher_ckpt) + +# training schedule for 1x +train_cfg = dict(type='EpochBasedTrainLoop', max_epochs=12, val_interval=1) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', start_factor=0.001, by_epoch=False, begin=0, end=500), + dict( + type='MultiStepLR', + begin=0, + end=12, + by_epoch=True, + milestones=[8, 11], + gamma=0.1) +] diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py new file mode 100755 index 000000000..3ba6727f5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py @@ -0,0 +1,53 @@ +_base_ = [ + 'mmdet::_base_/datasets/coco_instance.py', + 'mmdet::_base_/schedules/schedule_2x.py', + 'mmdet::_base_/default_runtime.py' +] + +teacher_ckpt = 'https://download.openmmlab.com/mmdetection/v2.0/swin/mask_rcnn_swin-s-p4-w7_fpn_fp16_ms-crop-3x_coco/mask_rcnn_swin-s-p4-w7_fpn_fp16_ms-crop-3x_coco_20210903_104808-b92c91f1.pth' # noqa: E501 + +model = dict( + _scope_='mmrazor', + type='FpnTeacherDistill', + architecture=dict( + cfg_path='mmdet::retinanet/retinanet_r50_fpn_2x_coco.py', + pretrained=False), + teacher=dict( + cfg_path= # noqa: E251 + 'mmdet::swin/mask-rcnn_swin-s-p4-w7_fpn_amp-ms-crop-3x_coco.py', + pretrained=False), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict(fpn=dict(type='ModuleOutputs', source='neck')), + teacher_recorders=dict(fpn=dict(type='ModuleOutputs', source='neck')), + distill_losses=dict( + loss_pkd_fpn0=dict(type='PKDLoss', loss_weight=6), + loss_pkd_fpn1=dict(type='PKDLoss', loss_weight=6), + loss_pkd_fpn2=dict(type='PKDLoss', loss_weight=6), + loss_pkd_fpn3=dict(type='PKDLoss', loss_weight=6)), + loss_forward_mappings=dict( + loss_pkd_fpn0=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=0), + preds_T=dict(from_student=False, recorder='fpn', data_idx=0)), + loss_pkd_fpn1=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=1), + preds_T=dict(from_student=False, recorder='fpn', data_idx=1)), + loss_pkd_fpn2=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=2), + preds_T=dict(from_student=False, recorder='fpn', data_idx=2)), + loss_pkd_fpn3=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=3), + preds_T=dict(from_student=False, recorder='fpn', + data_idx=3))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') + +# optimizer +optim_wrapper = dict(optimizer=dict(lr=0.01)) + +# dataset +val_evaluator = dict(metric=['bbox']) +test_evaluator = val_evaluator diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py new file mode 100755 index 000000000..ecf06bd37 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py @@ -0,0 +1,13 @@ +_base_ = ['./pkd_fpn_retina_x101_retina_r50_2x_coco.py'] + +teacher_ckpt = 'https://download.openmmlab.com/mmdetection/v2.0/reppoints/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco/reppoints_moment_x101_fpn_dconv_c3-c5_gn-neck%2Bhead_2x_coco_20200329-f87da1ea.pth' # noqa: E501 + +model = dict( + architecture=dict( + cfg_path= # noqa: E251 + 'mmdet::reppoints/reppoints-moment_r50_fpn-gn_head-gn_2x_coco.py'), + teacher=dict( + cfg_path= # noqa: E251 + 'mmdet::reppoints/reppoints-moment_x101-dconv-c3-c5_fpn-gn_head-gn_2x_coco.py' # noqa: E501 + ), + teacher_ckpt=teacher_ckpt) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_retina_x101_retina_r50_2x_coco.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_retina_x101_retina_r50_2x_coco.py new file mode 100755 index 000000000..ef2844e96 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_retina_x101_retina_r50_2x_coco.py @@ -0,0 +1,19 @@ +_base_ = ['./pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py'] + +teacher_ckpt = 'https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_x101_64x4d_fpn_1x_coco/retinanet_x101_64x4d_fpn_1x_coco_20200130-366f5af1.pth' # noqa: E501 + +model = dict( + architecture=dict( + cfg_path='mmdet::retinanet/retinanet_r50_fpn_2x_coco.py'), + teacher=dict( + cfg_path='mmdet::retinanet/retinanet_x101-64x4d_fpn_1x_coco.py'), + teacher_ckpt=teacher_ckpt, + distiller=dict( + distill_losses=dict( + loss_pkd_fpn0=dict(loss_weight=10), + loss_pkd_fpn1=dict(loss_weight=10), + loss_pkd_fpn2=dict(loss_weight=10), + loss_pkd_fpn3=dict(loss_weight=10)))) + +# optimizer +optim_wrapper = dict(optimizer=dict(lr=0.01)) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/README.md new file mode 100755 index 000000000..fdd191f69 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/README.md @@ -0,0 +1,30 @@ +# PKD + +> [PKD: General Distillation Framework for Object Detectors via Pearson Correlation Coefficient](https://arxiv.org/abs/2207.02039) + + + +## Abstract + +Knowledge distillation(KD) is a widely-used technique to train compact models in object detection. However, there is still a lack of study on how to distill between heterogeneous detectors. In this paper, we empirically find that better FPN features from a heterogeneous teacher detector can help the student although their detection heads and label assignments are different. However, directly aligning the feature maps to distill detectors suffers from two problems. First, the difference in feature magnitude between the teacher and the student could enforce overly strict constraints on the student. Second, the FPN stages and channels with large feature magnitude from the teacher model could dominate the gradient of distillation loss, which will overwhelm the effects of other features in KD and introduce much noise. To address the above issues, we propose to imitate features with Pearson Correlation Coefficient to focus on the relational information from the teacher and relax constraints on the magnitude of the features. Our method consistently outperforms the existing detection KD methods and works for both homogeneous and heterogeneous student-teacher pairs. Furthermore, it converges faster. With a powerful MaskRCNN-Swin detector as the teacher, ResNet-50 based RetinaNet and FCOS achieve 41.5% and 43.9% mAP on COCO2017, which are 4.1% and 4.8% higher than the baseline, respectively. + +![pipeline](https://user-images.githubusercontent.com/88702197/187424502-d8efb7a3-c40c-4e53-a36c-bd947de464a4.png) + +## Results and models + +### Detection + +| Location | Dataset | Teacher | Student | Lr schd | mAP | mAP(T) | mAP(S) | Config | Download | +| :------: | :--------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------: | :-----: | :--: | :----: | :----: | :------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| FPN | nus-mono3d | [FCOS3d-R101](https://github.com/open-mmlab/mmdetection3d/blob/dev-1.x/configs/fcos3d/fcos3d_r101-caffe-dcn_fpn_head-gn_8xb2-1x_nus-mono3d_finetune.py) | [FCOS3d-R50](<>) | 1x | 29.3 | 32.1 | 26.8 | [config](pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py) | [teacher](https://download.openmmlab.com/mmdetection3d/v0.1.0_models/fcos3d/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mono3d_finetune/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mono3d_finetune_20210717_095645-8d806dc2.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_fcos3d_w10/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d_20220928_234557-0b51b62e.pth?versionId=CAEQThiBgMC8sdC0oBgiIDAwOWE2OWUyNDU1NTQ1MjBhZTY1NmNjODZmMDZkZTM2) \| [log](https://download.openmmlab.com/mmrazor/v1/pkd/pkd_fcos3d_w10/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d_20220928_234557-0b51b62e.json?versionId=CAEQThiBgIDrvdC0oBgiIDNmNGNkNDZhM2RmNjQ1MmI4ZDM0OGNmYmFkYjk5ZjFi) | + +## Citation + +```latex +@article{cao2022pkd, + title={PKD: General Distillation Framework for Object Detectors via Pearson Correlation Coefficient}, + author={Cao, Weihan and Zhang, Yifan and Gao, Jianfei and Cheng, Anda and Cheng, Ke and Cheng, Jian}, + journal={arXiv preprint arXiv:2207.02039}, + year={2022} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/metafile.yml new file mode 100755 index 000000000..1f60cffd7 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/metafile.yml @@ -0,0 +1,22 @@ +Models: + - Name: pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d + In Collection: PKD + Metadata: + Location: FPN + Student: + Metrics: + box AP: 26.8 + Config: + Weights: + Teacher: + Metrics: + box AP: 32.1 + Config: mmdet3d::fcos3d/fcos3d_r101-caffe-dcn_fpn_head-gn_8xb2-1x_nus-mono3d_finetune.py + Weights: https://download.openmmlab.com/mmdetection3d/v0.1.0_models/fcos3d/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mono3d_finetune/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mono3d_finetune_20210717_095645-8d806dc2.pth + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 29.3 + Config: configs/distill/mmdet3d/pkd/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py + Weights: https://download.openmmlab.com/mmrazor/v1/pkd/pkd_fcos3d_w10/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d_20220928_234557-0b51b62e.json?versionId=CAEQThiBgIDrvdC0oBgiIDNmNGNkNDZhM2RmNjQ1MmI4ZDM0OGNmYmFkYjk5ZjFi diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py b/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py new file mode 100755 index 000000000..cbbedf7e0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py @@ -0,0 +1,49 @@ +_base_ = [ + 'mmdet3d::fcos3d/fcos3d_r101-caffe-dcn_fpn_head-gn_8xb2-1x_nus-mono3d.py', +] + +train_dataloader = dict(num_workers=4) + +student = _base_.model +student.backbone.depth = 50 # using original ResNet50 +student.backbone.dcn = None # no dcn in backbone +student.backbone.stage_with_dcn = (False, False, False, False) +student.backbone.init_cfg.checkpoint = 'open-mmlab://detectron2/resnet50_caffe' + +teacher_ckpt = 'https://download.openmmlab.com/mmdetection3d/v0.1.0_models/fcos3d/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mono3d_finetune/fcos3d_r101_caffe_fpn_gn-head_dcn_2x8_1x_nus-mono3d_finetune_20210717_095645-8d806dc2.pth' # noqa: E501 +model = dict( + _scope_='mmrazor', + _delete_=True, + type='FpnTeacherDistill', + architecture=student, + teacher=dict( + cfg_path= # noqa: E251 + 'mmdet3d::fcos3d/fcos3d_r101-caffe-dcn_fpn_head-gn_8xb2-1x_nus-mono3d_finetune.py', # noqa: E501 + pretrained=False), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict(fpn=dict(type='ModuleOutputs', source='neck')), + teacher_recorders=dict(fpn=dict(type='ModuleOutputs', source='neck')), + distill_losses=dict( + loss_pkd_fpn0=dict(type='PKDLoss', loss_weight=10), + loss_pkd_fpn1=dict(type='PKDLoss', loss_weight=10), + loss_pkd_fpn2=dict(type='PKDLoss', loss_weight=10), + loss_pkd_fpn3=dict(type='PKDLoss', loss_weight=10)), + loss_forward_mappings=dict( + loss_pkd_fpn0=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=0), + preds_T=dict(from_student=False, recorder='fpn', data_idx=0)), + loss_pkd_fpn1=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=1), + preds_T=dict(from_student=False, recorder='fpn', data_idx=1)), + loss_pkd_fpn2=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=2), + preds_T=dict(from_student=False, recorder='fpn', data_idx=2)), + loss_pkd_fpn3=dict( + preds_S=dict(from_student=True, recorder='fpn', data_idx=3), + preds_T=dict(from_student=False, recorder='fpn', + data_idx=3))))) + +find_unused_parameters = True +train_cfg = dict(val_interval=12) diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/README.md b/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/README.md new file mode 100755 index 000000000..4805c0696 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/README.md @@ -0,0 +1,37 @@ +# CWD + +> [Channel-wise Knowledge Distillation for Dense Prediction](https://arxiv.org/abs/2011.13256) + + + +## Abstract + +Knowledge distillation (KD) has been proven to be a simple and effective tool for training compact models. Almost all KD variants for dense prediction tasks align the student and teacher networks' feature maps in the spatial domain, typically by minimizing point-wise and/or pair-wise discrepancy. Observing that in semantic segmentation, some layers' feature activations of each channel tend to encode saliency of scene categories (analogue to class activation mapping), we propose to align features channel-wise between the student and teacher networks. To this end, we first transform the feature map of each channel into a probability map using softmax normalization, and then minimize the Kullback-Leibler (KL) divergence of the corresponding channels of the two networks. By doing so, our method focuses on mimicking the soft distributions of channels between networks. In particular, the KL divergence enables learning to pay more attention to the most salient regions of the channel-wise maps, presumably corresponding to the most useful signals for semantic segmentation. Experiments demonstrate that our channel-wise distillation outperforms almost all existing spatial distillation methods for semantic segmentation considerably, and requires less computational cost during training. We consistently achieve superior performance on three benchmarks with various network structures. + +![pipeline](https://user-images.githubusercontent.com/88702197/187424502-d8efb7a3-c40c-4e53-a36c-bd947de464a4.png) + +## Results and models + +### Segmentation + +| Location | Dataset | Teacher | Student | mIoU | mIoU(T) | mIou(S) | Config | Download | +| :------: | :--------: | :------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------: | :---: | :-----: | :-----: | :----------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| logits | cityscapes | [pspnet_r101](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes.py) | [pspnet_r18](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/pspnet/pspnet_r18-d8_512x1024_80k_cityscapes.py) | 75.54 | 79.76 | 74.87 | [config](<>) | [teacher](https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes/pspnet_r101-d8_512x1024_80k_cityscapes_20200606_112211-e1e1100f.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/cwd/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k_mIoU-75.54_20211222-3e643f6f.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/distill/cwd/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k_20211212_205711.log.json) | + +### Detection + +| Location | Dataset | Teacher | Student | mAP | mAP(T) | mAP(S) | Config | Download | +| :------: | :-----: | :--------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------: | :--: | :----: | :----: | :----------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| cls head | COCO | [gfl_r101_2x](https://github.com/open-mmlab/mmdetection/tree/master/configs/gfl/gfl_r101_fpn_mstrain_2x_coco.py) | [gfl_r50_1x](https://github.com/open-mmlab/mmdetection/tree/master/configs/gfl/gfl_r50_fpn_1x_coco.py) | 41.9 | 44.7 | 40.2 | [config](<>) | [teacher](https://download.openmmlab.com/mmdetection/v2.0/gfl/gfl_r101_fpn_mstrain_2x_coco/gfl_r101_fpn_mstrain_2x_coco_20200629_200126-dd12f847.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco_20211222-c134bb21.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/distill/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco_20211212_205444.log.json) | + +## Citation + +```latex +@inproceedings{shu2021channel, + title={Channel-Wise Knowledge Distillation for Dense Prediction}, + author={Shu, Changyong and Liu, Yifan and Gao, Jianfei and Yan, Zheng and Shen, Chunhua}, + booktitle={Proceedings of the IEEE/CVF International Conference on Computer Vision}, + pages={5311--5320}, + year={2021} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py b/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py new file mode 100755 index 000000000..e39045495 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py @@ -0,0 +1,31 @@ +_base_ = [ + 'mmseg::_base_/datasets/cityscapes.py', + 'mmseg::_base_/schedules/schedule_80k.py', + 'mmseg::_base_/default_runtime.py' +] + +teacher_ckpt = 'https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes/pspnet_r101-d8_512x1024_80k_cityscapes_20200606_112211-e1e1100f.pth' # noqa: E501 +teacher_cfg_path = 'mmseg::pspnet/pspnet_r101-d8_4xb2-80k_cityscapes-512x1024.py' # noqa: E501 +student_cfg_path = 'mmseg::pspnet/pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py' # noqa: E501 +model = dict( + _scope_='mmrazor', + type='SingleTeacherDistill', + architecture=dict(cfg_path=student_cfg_path, pretrained=False), + teacher=dict(cfg_path=teacher_cfg_path, pretrained=False), + teacher_ckpt=teacher_ckpt, + distiller=dict( + type='ConfigurableDistiller', + distill_losses=dict( + loss_cwd=dict(type='ChannelWiseDivergence', tau=1, loss_weight=5)), + student_recorders=dict( + logits=dict(type='ModuleOutputs', source='decode_head.conv_seg')), + teacher_recorders=dict( + logits=dict(type='ModuleOutputs', source='decode_head.conv_seg')), + loss_forward_mappings=dict( + loss_cwd=dict( + preds_S=dict(from_student=True, recorder='logits'), + preds_T=dict(from_student=False, recorder='logits'))))) + +find_unused_parameters = True + +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/metafile.yml b/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/metafile.yml new file mode 100755 index 000000000..2bb293275 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/metafile.yml @@ -0,0 +1,41 @@ +Collections: + - Name: CWD + Metadata: + Training Data: + - Cityscapes + - COCO + Paper: + URL: https://arxiv.org/abs/2011.13256 + Title: Channel-wise Knowledge Distillation for Dense Prediction + README: configs/distill/mmseg/cwd/README.md + Code: + URL: https://github.com/open-mmlab/mmrazor/blob/v0.1.0/mmrazor/models/losses/cwd.py#L10 + Version: v0.1.0 + Converted From: + Code: + - https://github.com/pppppM/mmsegmentation-distiller + - https://github.com/pppppM/mmdetection-distiller +Models: + - Name: cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024 + In Collection: CWD + Metadata: + Location: logits + Student: + Metrics: + mIoU: 74.87 + mIoU(ms+flip): 76.04 + Config: mmseg::pspnet/pspnet_r18-d8_512x1024_80k_cityscapes.py + Weights: https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r18-d8_512x1024_80k_cityscapes/pspnet_r18-d8_512x1024_80k_cityscapes_20201225_021458-09ffa746.pth + Teacher: + Metrics: + mIoU: 79.76 + mIoU(ms+flip): 81.01 + Config: mmseg::pspnet/pspnet_r101-d8_512x1024_80k_cityscapes.py + Weights: https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes/pspnet_r101-d8_512x1024_80k_cityscapes_20200606_112211-e1e1100f.pth + Results: + - Task: Semantic Segmentation + Dataset: Cityscapes + Metrics: + mIoU: 75.54 + Config: configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py + Weights: https://download.openmmlab.com/mmrazor/v1/cwd/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k_mIoU-75.54_20211222-3e643f6f.pth diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml new file mode 100755 index 000000000..e3672feaf --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml @@ -0,0 +1,134 @@ +backbone.base_embed_dims: + chosen: 64 +backbone.blocks.0.attn.mutable_attrs.num_heads: + chosen: 10 +backbone.blocks.0.middle_channels: + chosen: 3.5 +backbone.blocks.0.mutable_mlp_ratios: + chosen: 3.5 +backbone.blocks.0.mutable_q_embed_dims: + chosen: 10 +backbone.blocks.1.attn.mutable_attrs.num_heads: + chosen: 10 +backbone.blocks.1.middle_channels: + chosen: 3.5 +backbone.blocks.1.mutable_mlp_ratios: + chosen: 3.5 +backbone.blocks.1.mutable_q_embed_dims: + chosen: 64 +backbone.blocks.10.attn.mutable_attrs.num_heads: + chosen: 10 +backbone.blocks.10.middle_channels: + chosen: 4.0 +backbone.blocks.10.mutable_mlp_ratios: + chosen: 4.0 +backbone.blocks.10.mutable_q_embed_dims: + chosen: 64 +backbone.blocks.11.attn.mutable_attrs.num_heads: + chosen: 10 +backbone.blocks.11.middle_channels: + chosen: 576 +backbone.blocks.11.mutable_mlp_ratios: + chosen: 4.0 +backbone.blocks.11.mutable_q_embed_dims: + chosen: 10 +backbone.blocks.12.attn.mutable_attrs.num_heads: + chosen: 9 +backbone.blocks.12.middle_channels: + chosen: 4.0 +backbone.blocks.12.mutable_mlp_ratios: + chosen: 4.0 +backbone.blocks.12.mutable_q_embed_dims: + chosen: 9 +backbone.blocks.13.attn.mutable_attrs.num_heads: + chosen: 10 +backbone.blocks.13.middle_channels: + chosen: 4.0 +backbone.blocks.13.mutable_mlp_ratios: + chosen: 4.0 +backbone.blocks.13.mutable_q_embed_dims: + chosen: 10 +backbone.blocks.14.attn.mutable_attrs.num_heads: + chosen: 8 +backbone.blocks.14.middle_channels: + chosen: 576 +backbone.blocks.14.mutable_mlp_ratios: + chosen: 3.5 +backbone.blocks.14.mutable_q_embed_dims: + chosen: 8 +backbone.blocks.15.attn.mutable_attrs.num_heads: + chosen: 10 +backbone.blocks.15.middle_channels: + chosen: 3.0 +backbone.blocks.15.mutable_mlp_ratios: + chosen: 3.0 +backbone.blocks.15.mutable_q_embed_dims: + chosen: 10 +backbone.blocks.2.attn.mutable_attrs.num_heads: + chosen: 10 +backbone.blocks.2.middle_channels: + chosen: 576 +backbone.blocks.2.mutable_mlp_ratios: + chosen: 3.5 +backbone.blocks.2.mutable_q_embed_dims: + chosen: 10 +backbone.blocks.3.attn.mutable_attrs.num_heads: + chosen: 8 +backbone.blocks.3.middle_channels: + chosen: 4.0 +backbone.blocks.3.mutable_mlp_ratios: + chosen: 4.0 +backbone.blocks.3.mutable_q_embed_dims: + chosen: 8 +backbone.blocks.4.attn.mutable_attrs.num_heads: + chosen: 10 +backbone.blocks.4.middle_channels: + chosen: 576 +backbone.blocks.4.mutable_mlp_ratios: + chosen: 3.0 +backbone.blocks.4.mutable_q_embed_dims: + chosen: 10 +backbone.blocks.5.attn.mutable_attrs.num_heads: + chosen: 9 +backbone.blocks.5.middle_channels: + chosen: 3.0 +backbone.blocks.5.mutable_mlp_ratios: + chosen: 3.0 +backbone.blocks.5.mutable_q_embed_dims: + chosen: 9 +backbone.blocks.6.attn.mutable_attrs.num_heads: + chosen: 8 +backbone.blocks.6.middle_channels: + chosen: 576 +backbone.blocks.6.mutable_mlp_ratios: + chosen: 3.5 +backbone.blocks.6.mutable_q_embed_dims: + chosen: 8 +backbone.blocks.7.attn.mutable_attrs.num_heads: + chosen: 8 +backbone.blocks.7.middle_channels: + chosen: 3.5 +backbone.blocks.7.mutable_mlp_ratios: + chosen: 3.5 +backbone.blocks.7.mutable_q_embed_dims: + chosen: 8 +backbone.blocks.8.attn.mutable_attrs.num_heads: + chosen: 9 +backbone.blocks.8.middle_channels: + chosen: 576 +backbone.blocks.8.mutable_mlp_ratios: + chosen: 4.0 +backbone.blocks.8.mutable_q_embed_dims: + chosen: 9 +backbone.blocks.9.attn.mutable_attrs.num_heads: + chosen: 8 +backbone.blocks.9.middle_channels: + chosen: 576 +backbone.blocks.9.mutable_mlp_ratios: + chosen: 4.0 +backbone.blocks.9.mutable_q_embed_dims: + chosen: 8 +backbone.mutable_depth: + chosen: 14 +backbone.mutable_embed_dims: + chosen: 576 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/README.md b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/README.md new file mode 100755 index 000000000..161e83a56 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/README.md @@ -0,0 +1,75 @@ +# AutoFormer + +> [Searching Transformers for Visual Recognition](https://arxiv.org/abs/2107.00651) + + + +## Abstract + +Recently, pure transformer-based models have shown +great potentials for vision tasks such as image classification and detection. However, the design of transformer networks is challenging. It has been observed that the depth, +embedding dimension, and number of heads can largely affect the performance of vision transformers. Previous models configure these dimensions based upon manual crafting. In this work, we propose a new one-shot architecture +search framework, namely AutoFormer, dedicated to vision +transformer search. AutoFormer entangles the weights of +different blocks in the same layers during supernet training. Benefiting from the strategy, the trained supernet allows thousands of subnets to be very well-trained. Specifically, the performance of these subnets with weights inherited from the supernet is comparable to those retrained +from scratch. Besides, the searched models, which we refer to AutoFormers, surpass the recent state-of-the-arts such +as ViT and DeiT. In particular, AutoFormer-tiny/small/base +achieve 74.7%/81.7%/82.4% top-1 accuracy on ImageNet +with 5.7M/22.9M/53.7M parameters, respectively. Lastly, +we verify the transferability of AutoFormer by providing +the performance on downstream benchmarks and distillation experiments. + +![pipeline](/docs/en/imgs/model_zoo/autoformer/pipeline.png) + +## Get Started + +### Step 1: Supernet pre-training on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/mmcls/autoformer/autoformer_supernet_32xb256_in1k.py 4 \ + --work-dir $WORK_DIR +``` + +### Step 2: Search for subnet on the trained supernet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/mmcls/autoformer/autoformer_search_8xb128_in1k.py 4 \ + --work-dir $WORK_DIR --cfg-options load_from=$STEP1_CKPT +``` + +### Step 3: Subnet inference on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0 PORT=29500 ./tools/dist_test.sh \ + configs/nas/mmcls/autoformer/autoformer_subnet_8xb128_in1k.py \ + none 1 --work-dir $WORK_DIR \ + --cfg-options model.init_cfg.checkpoint=$STEP1_CKPT model.init_weight_from_supernet=True + +``` + +## Results and models + +| Dataset | Supernet | Subnet | Params(M) | Flops(G) | Top-1 (%) | Top-5 (%) | Config | Download | Remarks | +| :------: | :------: | :----------------------------------------------------------------: | :-------: | :------: | :-------: | :-------: | :---------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------: | +| ImageNet | vit | [mutable](./configs/nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml) | 54.319 | 10.57 | 82.47 | 95.99 | [config](./autoformer_supernet_32xb256_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/autoformer/autoformer_supernet_32xb256_in1k_20220919_110144-c658ce8f.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/autoformer/autoformer_supernet_32xb256_in1k_20220919_110144-c658ce8f.json) | MMRazor searched | + +**Note**: + +1. There are some small differences in our experiment in order to be consistent with mmrazor repo. For example, we set the max value of embed_channels 624 while the original repo set it 640. However, the original repo only search 528, 576, 624 embed_channels, so set 624 can also get the same result with orifinal paper. +2. The original paper get 82.4 top-1 acc with 53.7M Params while we get 82.48 top-1 acc with 52.47M Params. + +## Citation + +```latex +@article{xu2021autoformer, + title={Autoformer: Decomposition transformers with auto-correlation for long-term series forecasting}, + author={Xu, Jiehui and Wang, Jianmin and Long, Mingsheng and others}, + journal={Advances in Neural Information Processing Systems}, + volume={34}, + year={2021} +} +``` + +Footer diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_search_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_search_8xb128_in1k.py new file mode 100755 index 000000000..be1d4660d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_search_8xb128_in1k.py @@ -0,0 +1,17 @@ +_base_ = ['./autoformer_supernet_32xb256_in1k.py'] + +custom_hooks = None + +train_cfg = dict( + _delete_=True, + type='mmrazor.EvolutionSearchLoop', + dataloader=_base_.val_dataloader, + evaluator=_base_.val_evaluator, + max_epochs=20, + num_candidates=20, + top_k=10, + num_mutation=5, + num_crossover=5, + mutate_prob=0.2, + constraints_range=dict(params=(0, 55)), + score_key='accuracy/top1') diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_subnet_8xb256_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_subnet_8xb256_in1k.py new file mode 100755 index 000000000..f4d53ae76 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_subnet_8xb256_in1k.py @@ -0,0 +1,17 @@ +_base_ = 'autoformer_supernet_32xb256_in1k.py' + +model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.supernet, + # NOTE: You can replace the yaml with the mutable_cfg searched by yourself + fix_subnet='configs/nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml', + # You can also load the checkpoint of supernet instead of the specific + # subnet by modifying the `checkpoint`(path) in the following `init_cfg` + # with `init_weight_from_supernet = True`. + init_weight_from_supernet=False, + init_cfg=dict( + type='Pretrained', + checkpoint= # noqa: E251 + 'https://download.openmmlab.com/mmrazor/v1/autoformer/autoformer_supernet_32xb256_in1k_20220919_110144-c658ce8f.pth', # noqa: E501 + prefix='architecture.')) diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_supernet_32xb256_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_supernet_32xb256_in1k.py new file mode 100755 index 000000000..21555bfe7 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_supernet_32xb256_in1k.py @@ -0,0 +1,68 @@ +_base_ = [ + 'mmrazor::_base_/settings/imagenet_bs2048_AdamW.py', + 'mmcls::_base_/default_runtime.py', +] + +# data preprocessor +data_preprocessor = dict( + _scope_='mmcls', + type='ClsDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True, + num_classes=1000, + batch_augments=dict( + augments=[ + dict(type='Mixup', alpha=0.2), + dict(type='CutMix', alpha=1.0) + ], + probs=[0.5, 0.5])) + +arch_setting = dict( + mlp_ratios=[3.0, 3.5, 4.0], + num_heads=[8, 9, 10], + depth=[14, 15, 16], + embed_dims=[528, 576, 624]) + +supernet = dict( + _scope_='mmrazor', + type='SearchableImageClassifier', + data_preprocessor=data_preprocessor, + backbone=dict( + _scope_='mmrazor', + type='AutoformerBackbone', + arch_setting=arch_setting), + neck=None, + head=dict( + type='DynamicLinearClsHead', + num_classes=1000, + in_channels=624, + loss=dict( + type='mmcls.LabelSmoothLoss', + mode='original', + num_classes=1000, + label_smooth_val=0.1, + loss_weight=1.0), + topk=(1, 5)), + connect_head=dict(connect_with_backbone='backbone.last_mutable'), +) + +model = dict( + type='mmrazor.Autoformer', + architecture=supernet, + mutator=dict(type='mmrazor.NasMutator')) + +# runtime setting +custom_hooks = [dict(type='EMAHook', momentum=4e-5, priority='ABOVE_NORMAL')] + +# checkpoint saving +_base_.default_hooks.checkpoint = dict( + type='CheckpointHook', + interval=2, + by_epoch=True, + save_best='accuracy/top1', + max_keep_ckpts=3) + +find_unused_parameters = True diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/README.md b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/README.md new file mode 100755 index 000000000..37a651ddb --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/README.md @@ -0,0 +1,87 @@ +# AutoSlim + +> [AutoSlim: Towards One-Shot Architecture Search for Channel Numbers](https://arxiv.org/abs/1903.11728) + + + +## Abstract + +We study how to set channel numbers in a neural network to achieve better accuracy under constrained resources (e.g., FLOPs, latency, memory footprint or model size). A simple and one-shot solution, named AutoSlim, is presented. Instead of training many network samples and searching with reinforcement learning, we train a single slimmable network to approximate the network accuracy of different channel configurations. We then iteratively evaluate the trained slimmable model and greedily slim the layer with minimal accuracy drop. By this single pass, we can obtain the optimized channel configurations under different resource constraints. We present experiments with MobileNet v1, MobileNet v2, ResNet-50 and RL-searched MNasNet on ImageNet classification. We show significant improvements over their default channel configurations. We also achieve better accuracy than recent channel pruning methods and neural architecture search methods. +Notably, by setting optimized channel numbers, our AutoSlim-MobileNet-v2 at 305M FLOPs achieves 74.2% top-1 accuracy, 2.4% better than default MobileNet-v2 (301M FLOPs), and even 0.2% better than RL-searched MNasNet (317M FLOPs). Our AutoSlim-ResNet-50 at 570M FLOPs, without depthwise convolutions, achieves 1.3% better accuracy than MobileNet-v1 (569M FLOPs). + +![pipeline](https://user-images.githubusercontent.com/88702197/187425354-d90e4b36-e033-4dc0-b951-64a536e61b71.png) + +## Get Started + +### Supernet pre-training on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/autoslim/autoslim_mbv2_1.5x_supernet_8xb256_in1k.py 4 \ + --work-dir $WORK_DIR +``` + +### Search for subnet on the trained supernet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/autoslim/autoslim_mbv2_1.5x_search_8xb256_in1k.py 4 \ + --work-dir $WORK_DIR --cfg-options load_from=$STEP1_CKPT +``` + +### Subnet retraining on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/autoslim/autoslim_mbv2_subnet_8xb256_in1k.py 4 \ + --work-dir $WORK_DIR \ + --cfg-options algorithm.channel_cfg=configs/nas/autoslim/AUTOSLIM_MBV2_530M_OFFICIAL.yaml,configs/nas/autoslim/AUTOSLIM_MBV2_320M_OFFICIAL.yaml,configs/nas/autoslim/AUTOSLIM_MBV2_220M_OFFICIAL.yaml +``` + +### Split checkpoint + +```bash +python ./tools/model_converters/split_checkpoint.py \ + configs/nas/autoslim/autoslim_mbv2_subnet_8xb256_in1k.py \ + $RETRAINED_CKPT \ + --channel-cfgs configs/nas/autoslim/AUTOSLIM_MBV2_530M_OFFICIAL.yaml configs/nas/autoslim/AUTOSLIM_MBV2_320M_OFFICIAL.yaml configs/nas/autoslim/AUTOSLIM_MBV2_220M_OFFICIAL.yaml +``` + +### Subnet inference + +```bash +CUDA_VISIBLE_DEVICES=0 PORT=29500 ./tools/dist_test.sh \ + configs/nas/autoslim/autoslim_mbv2_subnet_8xb256_in1k.py \ + $SEARCHED_CKPT 1 --work-dir $WORK_DIR \ + --cfg-options algorithm.channel_cfg=configs/nas/autoslim/AUTOSLIM_MBV2_530M_OFFICIAL.yaml # or modify the config directly +``` + +## Results and models + +### Subnet retrain + +| Supernet | Params(M) | Flops(G) | Top-1 (%) | Top-5 (%) | Config | Download | Subnet | Remark | +| :----------------- | :-------: | -------: | :-------: | :-------: | :---------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------: | +| MobileNet v2(x1.5) | 6.5 | 0.53 | 74.23 | 91.74 | [config](./autoslim_mbv2_subnet_8xb256_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/autoslim/autoslim_mbv2_subnet_8xb256_in1k_flops-530M_acc-74.23_20220715-aa8754fe.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/pruning/autoslim/autoslim_mbv2_subnet_8xb256_in1k/autoslim_mbv2_subnet_8xb256_in1kautoslim_mbv2_subnet_8xb256_in1k_paper_channel_cfg.log.json) | [channel](https://download.openmmlab.com/mmrazor/v0.1/pruning/autoslim/autoslim_mbv2_subnet_8xb256_in1k/autoslim_mbv2_subnet_8xb256_in1k_flops-0.53M_acc-74.23_20211222-e5208bbd_channel_cfg.yaml) | official channel cfg | +| MobileNet v2(x1.5) | 5.77 | 0.32 | 72.73 | 90.83 | [config](./autoslim_mbv2_subnet_8xb256_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/autoslim/autoslim_mbv2_subnet_8xb256_in1k_flops-320M_acc-72.73_20220715-9aa8f8ae.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/pruning/autoslim/autoslim_mbv2_subnet_8xb256_in1k/autoslim_mbv2_subnet_8xb256_in1kautoslim_mbv2_subnet_8xb256_in1k_paper_channel_cfg.log.json) | [channel](https://download.openmmlab.com/mmrazor/v0.1/pruning/autoslim/autoslim_mbv2_subnet_8xb256_in1k/autoslim_mbv2_subnet_8xb256_in1k_flops-0.32M_acc-72.73_20211222-b5b0b33c_channel_cfg.yaml) | official channel cfg | +| MobileNet v2(x1.5) | 4.13 | 0.22 | 71.39 | 90.08 | [config](./autoslim_mbv2_subnet_8xb256_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/autoslim/autoslim_mbv2_subnet_8xb256_in1k_flops-220M_acc-71.4_20220715-9c288f3b.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/pruning/autoslim/autoslim_mbv2_subnet_8xb256_in1k/autoslim_mbv2_subnet_8xb256_in1kautoslim_mbv2_subnet_8xb256_in1k_paper_channel_cfg.log.json) | [channel](https://download.openmmlab.com/mmrazor/v0.1/pruning/autoslim/autoslim_mbv2_subnet_8xb256_in1k/autoslim_mbv2_subnet_8xb256_in1k_flops-0.22M_acc-71.39_20211222-43117c7b_channel_cfg.yaml) | official channel cfg | + +Note that we ran the official code and the Top-1 Acc of the models with official +channel cfg are 73.8%, 72.5% and 71.1%. And there are 3 differences between our +implementation and the official one. + +1. The implementation of Label Smooth is slightly different. +2. Lighting is not used in our data pipeline. (Lighting is a kind of data + augmentation which adjust images lighting using AlexNet-style PCA jitter.) +3. We do not recalibrating BN statistics after training. + +## Citation + +```latex +@article{yu2019autoslim, + title={Autoslim: Towards one-shot architecture search for channel numbers}, + author={Yu, Jiahui and Huang, Thomas}, + journal={arXiv preprint arXiv:1903.11728}, + year={2019} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_search_8xb256_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_search_8xb256_in1k.py new file mode 100755 index 000000000..e5b3ba21d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_search_8xb256_in1k.py @@ -0,0 +1,19 @@ +_base_ = ['./autoslim_mbv2_1.5x_supernet_8xb256_in1k.py'] + +model = dict(bn_training_mode=True) + +train_cfg = None +optim_wrapper = None +param_scheduler = None +train_dataloader = None + +val_cfg = None +val_dataloader = None +val_evaluator = None + +test_cfg = dict( + _delete_=True, + type='mmrazor.AutoSlimGreedySearchLoop', + dataloader=_base_.test_dataloader, + evaluator=_base_.test_evaluator, + target_flops=(500., 300., 200.)) diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py new file mode 100755 index 000000000..61d64a226 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py @@ -0,0 +1,46 @@ +_base_ = [ + 'mmrazor::_base_/settings/imagenet_bs2048_autoslim_pil.py', + 'mmcls::_base_/models/mobilenet_v2_1x.py', + 'mmcls::_base_/default_runtime.py', +] + +supernet = _base_.model +supernet.backbone.widen_factor = 1.5 +supernet.head.in_channels = 1920 + +# !dataset config +# ========================================================================== +# data preprocessor +data_preprocessor = dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True) + +# !autoslim algorithm config +# ========================================================================== + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='SlimmableNetwork', + architecture=supernet, + data_preprocessor=data_preprocessor, + mutator=dict( + type='SlimmableChannelMutator', + channel_unit_cfg=dict( + type='SlimmableChannelUnit', + units='tests/data/MBV2_slimmable_config.json'), + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer'))) + +model_wrapper_cfg = dict( + type='mmrazor.SlimmableNetworkDDP', + broadcast_buffers=False, + find_unused_parameters=True) + +val_cfg = dict(type='mmrazor.SlimmableValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py new file mode 100755 index 000000000..2ed71daf5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py @@ -0,0 +1,3 @@ +_base_ = 'autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py' + +model = dict(deploy_index=0) diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py new file mode 100755 index 000000000..e53aae1bc --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py @@ -0,0 +1,3 @@ +_base_ = 'autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py' + +model = dict(deploy_index=1) diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py new file mode 100755 index 000000000..218a9b036 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py @@ -0,0 +1,3 @@ +_base_ = 'autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py' + +model = dict(deploy_index=2) diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_supernet_8xb256_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_supernet_8xb256_in1k.py new file mode 100755 index 000000000..91cd9d2de --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_supernet_8xb256_in1k.py @@ -0,0 +1,68 @@ +_base_ = [ + '../../../_base_/settings/imagenet_bs2048_autoslim_pil.py', + 'mmcls::_base_/models/mobilenet_v2_1x.py', + 'mmcls::_base_/default_runtime.py', +] + +supernet = _base_.model +supernet.backbone.widen_factor = 1.5 +supernet.head.in_channels = 1920 + +# !dataset config +# ========================================================================== +# data preprocessor +data_preprocessor = dict( + type='ImgDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + bgr_to_rgb=True, +) + +# !autoslim algorithm config +num_random_samples = 2 +model = dict( + _delete_=True, + _scope_='mmrazor', + type='AutoSlim', + num_random_samples=num_random_samples, + architecture=supernet, + data_preprocessor=data_preprocessor, + distiller=dict( + type='ConfigurableDistiller', + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=1)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(recorder='fc', from_student=True), + preds_T=dict(recorder='fc', from_student=False)))), + mutator=dict( + type='OneShotChannelMutator', + channel_unit_cfg=dict( + type='OneShotMutableChannelUnit', + default_args=dict( + candidate_choices=list(i / 12 for i in range(2, 13)), + choice_mode='ratio', + divisor=8)), + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer'))) + +model_wrapper_cfg = dict( + type='mmrazor.AutoSlimDDP', + broadcast_buffers=False, + find_unused_parameters=False) + +# learning policy +max_epochs = 50 +param_scheduler = dict(end=max_epochs) + +# train, val, test setting +train_cfg = dict(max_epochs=max_epochs) +val_cfg = dict(type='mmrazor.SubnetValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/metafile.yml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/metafile.yml new file mode 100755 index 000000000..c46cd97b9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/metafile.yml @@ -0,0 +1,60 @@ +Collections: + - Name: AutoSlim + Metadata: + Training Data: + - ImageNet-1k + Paper: + URL: https://arxiv.org/abs/1903.11728 + Title: AutoSlim:Towards One-Shot Architecture Search for Channel Numbers + README: configs/nas/mmcls/autoslim/README.md + Code: + URL: https://github.com/open-mmlab/mmrazor/blob/v0.1.0/mmrazor/models/algorithms/autoslim.py + Version: v0.1.0 + Converted From: + Code: https://github.com/JiahuiYu/slimmable_networks +Models: + - Name: autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M + In Collection: AutoSlim + Metadata: + Flops(G): 0.53 + Params(M): 6.5 + Supernet: MobileNet v2(x1.5) + Channel: https://download.openmmlab.com/mmrazor/v1/autoslim/autoslim_mbv2_subnet_8xb256_in1k_flops-530M_acc-74.23_20220715-aa8754fe_subnet_cfg.yaml + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 74.23 + Top 5 Accuracy: 91.73 + Config: configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py + Weights: https://download.openmmlab.com/mmrazor/v1/autoslim/autoslim_mbv2_subnet_8xb256_in1k_flops-530M_acc-74.23_20220715-aa8754fe.pth + - Name: autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M + In Collection: AutoSlim + Metadata: + Flops(G): 0.32 + Params(M): 5.77 + Supernet: MobileNet v2(x1.5) + Channel: https://download.openmmlab.com/mmrazor/v1/autoslim/autoslim_mbv2_subnet_8xb256_in1k_flops-320M_acc-72.73_20220715-9aa8f8ae_subnet_cfg.yaml + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 72.73 + Top 5 Accuracy: 90.84 + Config: configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py + Weights: https://download.openmmlab.com/mmrazor/v1/autoslim/autoslim_mbv2_subnet_8xb256_in1k_flops-320M_acc-72.73_20220715-9aa8f8ae.pth + - Name: autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M + In Collection: AutoSlim + Metadata: + Flops(G): 0.22 + Params(M): 4.13 + Supernet: MobileNet v2(x1.5) + Channel: https://download.openmmlab.com/mmrazor/v1/autoslim/autoslim_mbv2_subnet_8xb256_in1k_flops-220M_acc-71.4_20220715-9c288f3b_subnet_cfg.yaml + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 71.4 + Top 5 Accuracy: 90.08 + Config: configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py + Weights: https://download.openmmlab.com/mmrazor/v1/autoslim/autoslim_mbv2_subnet_8xb256_in1k_flops-220M_acc-71.4_20220715-9c288f3b.pth diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml new file mode 100755 index 000000000..e926d4b03 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml @@ -0,0 +1,64 @@ +backbone.first_channels: + chosen: 16 +backbone.last_channels: + chosen: 1792 +backbone.layers.1.kernel_size: + chosen: 3 +backbone.layers.1.expand_ratio: + chosen: 1 +backbone.layers.1.depth: + chosen: 1 +backbone.layers.1.out_channels: + chosen: 16 +backbone.layers.2.kernel_size: + chosen: 3 +backbone.layers.2.expand_ratio: + chosen: 4 +backbone.layers.2.depth: + chosen: 3 +backbone.layers.2.out_channels: + chosen: 24 +backbone.layers.3.kernel_size: + chosen: 3 +backbone.layers.3.expand_ratio: + chosen: 4 +backbone.layers.3.depth: + chosen: 3 +backbone.layers.3.out_channels: + chosen: 32 +backbone.layers.4.kernel_size: + chosen: 3 +backbone.layers.4.expand_ratio: + chosen: 4 +backbone.layers.4.depth: + chosen: 3 +backbone.layers.4.out_channels: + chosen: 64 +backbone.layers.5.kernel_size: + chosen: 3 +backbone.layers.5.expand_ratio: + chosen: 4 +backbone.layers.5.depth: + chosen: 3 +backbone.layers.5.out_channels: + chosen: 112 +backbone.layers.6.kernel_size: + chosen: 3 +backbone.layers.6.expand_ratio: + chosen: 6 +backbone.layers.6.depth: + chosen: 3 +backbone.layers.6.out_channels: + chosen: 192 +backbone.layers.7.kernel_size: + chosen: 3 +backbone.layers.7.expand_ratio: + chosen: 6 +backbone.layers.7.depth: + chosen: 1 +backbone.layers.7.out_channels: + chosen: 216 +input_shape: + chosen: + - 192 + - 192 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A1.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A1.yaml new file mode 100755 index 000000000..b4b78c7a2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A1.yaml @@ -0,0 +1,64 @@ +backbone.first_channels: + chosen: 16 +backbone.last_channels: + chosen: 1984 +backbone.layers.1.kernel_size: + chosen: 3 +backbone.layers.1.expand_ratio: + chosen: 1 +backbone.layers.1.depth: + chosen: 1 +backbone.layers.1.out_channels: + chosen: 16 +backbone.layers.2.kernel_size: + chosen: 3 +backbone.layers.2.expand_ratio: + chosen: 4 +backbone.layers.2.depth: + chosen: 3 +backbone.layers.2.out_channels: + chosen: 24 +backbone.layers.3.kernel_size: + chosen: 3 +backbone.layers.3.expand_ratio: + chosen: 4 +backbone.layers.3.depth: + chosen: 3 +backbone.layers.3.out_channels: + chosen: 32 +backbone.layers.4.kernel_size: + chosen: 5 +backbone.layers.4.expand_ratio: + chosen: 4 +backbone.layers.4.depth: + chosen: 3 +backbone.layers.4.out_channels: + chosen: 64 +backbone.layers.5.kernel_size: + chosen: 3 +backbone.layers.5.expand_ratio: + chosen: 4 +backbone.layers.5.depth: + chosen: 3 +backbone.layers.5.out_channels: + chosen: 112 +backbone.layers.6.kernel_size: + chosen: 5 +backbone.layers.6.expand_ratio: + chosen: 6 +backbone.layers.6.depth: + chosen: 3 +backbone.layers.6.out_channels: + chosen: 192 +backbone.layers.7.kernel_size: + chosen: 3 +backbone.layers.7.expand_ratio: + chosen: 6 +backbone.layers.7.depth: + chosen: 1 +backbone.layers.7.out_channels: + chosen: 216 +input_shape: + chosen: + - 224 + - 224 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A2.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A2.yaml new file mode 100755 index 000000000..704b79051 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A2.yaml @@ -0,0 +1,64 @@ +backbone.first_channels: + chosen: 16 +backbone.last_channels: + chosen: 1984 +backbone.layers.1.kernel_size: + chosen: 3 +backbone.layers.1.expand_ratio: + chosen: 1 +backbone.layers.1.depth: + chosen: 1 +backbone.layers.1.out_channels: + chosen: 16 +backbone.layers.2.kernel_size: + chosen: 3 +backbone.layers.2.expand_ratio: + chosen: 4 +backbone.layers.2.depth: + chosen: 3 +backbone.layers.2.out_channels: + chosen: 24 +backbone.layers.3.kernel_size: + chosen: 3 +backbone.layers.3.expand_ratio: + chosen: 5 +backbone.layers.3.depth: + chosen: 3 +backbone.layers.3.out_channels: + chosen: 32 +backbone.layers.4.kernel_size: + chosen: 3 +backbone.layers.4.expand_ratio: + chosen: 4 +backbone.layers.4.depth: + chosen: 3 +backbone.layers.4.out_channels: + chosen: 64 +backbone.layers.5.kernel_size: + chosen: 3 +backbone.layers.5.expand_ratio: + chosen: 4 +backbone.layers.5.depth: + chosen: 3 +backbone.layers.5.out_channels: + chosen: 112 +backbone.layers.6.kernel_size: + chosen: 5 +backbone.layers.6.expand_ratio: + chosen: 6 +backbone.layers.6.depth: + chosen: 4 +backbone.layers.6.out_channels: + chosen: 200 +backbone.layers.7.kernel_size: + chosen: 3 +backbone.layers.7.expand_ratio: + chosen: 6 +backbone.layers.7.depth: + chosen: 1 +backbone.layers.7.out_channels: + chosen: 224 +input_shape: + chosen: + - 224 + - 224 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A3.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A3.yaml new file mode 100755 index 000000000..45f4d8411 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A3.yaml @@ -0,0 +1,64 @@ +backbone.first_channels: + chosen: 16 +backbone.last_channels: + chosen: 1984 +backbone.layers.1.kernel_size: + chosen: 3 +backbone.layers.1.expand_ratio: + chosen: 1 +backbone.layers.1.depth: + chosen: 2 +backbone.layers.1.out_channels: + chosen: 16 +backbone.layers.2.kernel_size: + chosen: 3 +backbone.layers.2.expand_ratio: + chosen: 4 +backbone.layers.2.depth: + chosen: 3 +backbone.layers.2.out_channels: + chosen: 24 +backbone.layers.3.kernel_size: + chosen: 3 +backbone.layers.3.expand_ratio: + chosen: 4 +backbone.layers.3.depth: + chosen: 3 +backbone.layers.3.out_channels: + chosen: 32 +backbone.layers.4.kernel_size: + chosen: 3 +backbone.layers.4.expand_ratio: + chosen: 4 +backbone.layers.4.depth: + chosen: 4 +backbone.layers.4.out_channels: + chosen: 64 +backbone.layers.5.kernel_size: + chosen: 5 +backbone.layers.5.expand_ratio: + chosen: 4 +backbone.layers.5.depth: + chosen: 3 +backbone.layers.5.out_channels: + chosen: 112 +backbone.layers.6.kernel_size: + chosen: 3 +backbone.layers.6.expand_ratio: + chosen: 6 +backbone.layers.6.depth: + chosen: 5 +backbone.layers.6.out_channels: + chosen: 208 +backbone.layers.7.kernel_size: + chosen: 3 +backbone.layers.7.expand_ratio: + chosen: 6 +backbone.layers.7.depth: + chosen: 1 +backbone.layers.7.out_channels: + chosen: 224 +input_shape: + chosen: + - 224 + - 224 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A4.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A4.yaml new file mode 100755 index 000000000..e15485bc3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A4.yaml @@ -0,0 +1,64 @@ +backbone.first_channels: + chosen: 16 +backbone.last_channels: + chosen: 1984 +backbone.layers.1.kernel_size: + chosen: 3 +backbone.layers.1.expand_ratio: + chosen: 1 +backbone.layers.1.depth: + chosen: 1 +backbone.layers.1.out_channels: + chosen: 16 +backbone.layers.2.kernel_size: + chosen: 3 +backbone.layers.2.expand_ratio: + chosen: 4 +backbone.layers.2.depth: + chosen: 3 +backbone.layers.2.out_channels: + chosen: 24 +backbone.layers.3.kernel_size: + chosen: 3 +backbone.layers.3.expand_ratio: + chosen: 4 +backbone.layers.3.depth: + chosen: 3 +backbone.layers.3.out_channels: + chosen: 32 +backbone.layers.4.kernel_size: + chosen: 5 +backbone.layers.4.expand_ratio: + chosen: 5 +backbone.layers.4.depth: + chosen: 4 +backbone.layers.4.out_channels: + chosen: 64 +backbone.layers.5.kernel_size: + chosen: 3 +backbone.layers.5.expand_ratio: + chosen: 4 +backbone.layers.5.depth: + chosen: 3 +backbone.layers.5.out_channels: + chosen: 112 +backbone.layers.6.kernel_size: + chosen: 5 +backbone.layers.6.expand_ratio: + chosen: 6 +backbone.layers.6.depth: + chosen: 5 +backbone.layers.6.out_channels: + chosen: 192 +backbone.layers.7.kernel_size: + chosen: 3 +backbone.layers.7.expand_ratio: + chosen: 6 +backbone.layers.7.depth: + chosen: 1 +backbone.layers.7.out_channels: + chosen: 216 +input_shape: + chosen: + - 256 + - 256 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A5.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A5.yaml new file mode 100755 index 000000000..c0b789079 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A5.yaml @@ -0,0 +1,64 @@ +backbone.first_channels: + chosen: 16 +backbone.last_channels: + chosen: 1792 +backbone.layers.1.kernel_size: + chosen: 3 +backbone.layers.1.expand_ratio: + chosen: 1 +backbone.layers.1.depth: + chosen: 1 +backbone.layers.1.out_channels: + chosen: 16 +backbone.layers.2.kernel_size: + chosen: 3 +backbone.layers.2.expand_ratio: + chosen: 4 +backbone.layers.2.depth: + chosen: 3 +backbone.layers.2.out_channels: + chosen: 24 +backbone.layers.3.kernel_size: + chosen: 3 +backbone.layers.3.expand_ratio: + chosen: 5 +backbone.layers.3.depth: + chosen: 3 +backbone.layers.3.out_channels: + chosen: 32 +backbone.layers.4.kernel_size: + chosen: 5 +backbone.layers.4.expand_ratio: + chosen: 4 +backbone.layers.4.depth: + chosen: 3 +backbone.layers.4.out_channels: + chosen: 64 +backbone.layers.5.kernel_size: + chosen: 3 +backbone.layers.5.expand_ratio: + chosen: 4 +backbone.layers.5.depth: + chosen: 4 +backbone.layers.5.out_channels: + chosen: 112 +backbone.layers.6.kernel_size: + chosen: 3 +backbone.layers.6.expand_ratio: + chosen: 6 +backbone.layers.6.depth: + chosen: 6 +backbone.layers.6.out_channels: + chosen: 192 +backbone.layers.7.kernel_size: + chosen: 3 +backbone.layers.7.expand_ratio: + chosen: 6 +backbone.layers.7.depth: + chosen: 1 +backbone.layers.7.out_channels: + chosen: 224 +input_shape: + chosen: + - 256 + - 256 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A6.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A6.yaml new file mode 100755 index 000000000..91f4d6a35 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A6.yaml @@ -0,0 +1,64 @@ +backbone.first_channels: + chosen: 16 +backbone.last_channels: + chosen: 1984 +backbone.layers.1.kernel_size: + chosen: 3 +backbone.layers.1.depth: + chosen: 1 +backbone.layers.1.expand_ratio: + chosen: 1 +backbone.layers.1.out_channels: + chosen: 24 +backbone.layers.2.kernel_size: + chosen: 3 +backbone.layers.2.depth: + chosen: 3 +backbone.layers.2.expand_ratio: + chosen: 4 +backbone.layers.2.out_channels: + chosen: 32 +backbone.layers.3.kernel_size: + chosen: 3 +backbone.layers.3.depth: + chosen: 3 +backbone.layers.3.expand_ratio: + chosen: 6 +backbone.layers.3.out_channels: + chosen: 40 +backbone.layers.4.kernel_size: + chosen: 3 +backbone.layers.4.depth: + chosen: 4 +backbone.layers.4.expand_ratio: + chosen: 5 +backbone.layers.4.out_channels: + chosen: 72 +backbone.layers.5.kernel_size: + chosen: 3 +backbone.layers.5.depth: + chosen: 4 +backbone.layers.5.expand_ratio: + chosen: 4 +backbone.layers.5.out_channels: + chosen: 128 +backbone.layers.6.kernel_size: + chosen: 5 +backbone.layers.6.depth: + chosen: 6 +backbone.layers.6.expand_ratio: + chosen: 6 +backbone.layers.6.out_channels: + chosen: 216 +backbone.layers.7.kernel_size: + chosen: 3 +backbone.layers.7.depth: + chosen: 1 +backbone.layers.7.expand_ratio: + chosen: 6 +backbone.layers.7.out_channels: + chosen: 224 +input_shape: + chosen: + - 288 + - 288 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/README.md b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/README.md new file mode 100755 index 000000000..d6b117f11 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/README.md @@ -0,0 +1,69 @@ +# BigNAS + +> [BigNAS: Scaling Up Neural Architecture Search with Big Single-Stage Models](https://arxiv.org/abs/2003.11142) + + + +## Abstract + +Neural architecture search (NAS) has shown promising results discovering models that are both accurate and fast. For NAS, training a one-shot model has become a popular strategy to rank the relative quality of different architectures (child models) using a single set of shared weights. However, while one-shot model weights can effectively rank different network architectures, the absolute accuracies from these shared weights are typically far below those obtained from stand-alone training. To compensate, existing methods assume that the weights must be retrained, finetuned, or otherwise post-processed after the search is completed. These steps significantly increase the compute requirements and complexity of the architecture search and model deployment. In this work, we propose BigNAS, an approach that challenges the conventional wisdom that post-processing of the weights is necessary to get good prediction accuracies. Without extra retraining or post-processing steps, we are able to train a single set of shared weights on ImageNet and use these weights to obtain child models whose sizes range from 200 to 1000 MFLOPs. Our discovered model family, BigNASModels, achieve top1 accuracies ranging from 76.5% to 80.9%, surpassing state-of-the-art models in this range including EfficientNets and Once-for-All networks without extra retraining or post-processing. We present ablative study and analysis to further understand the proposed BigNASModels. + +## Get Started + +### Step 1: Supernet pre-training on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/mmcls/bignas/attentive_mobilenet_supernet_32xb64_in1k.py 4 \ + --work-dir $WORK_DIR +``` + +### Step 2: Search for subnet on the trained supernet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/mmcls/bignas/attentive_mobilenet_search_8xb128_in1k.py 4 \ + --work-dir $WORK_DIR --cfg-options load_from=$STEP1_CKPT +``` + +### Step 3: Subnet inference on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0 PORT=29500 ./tools/dist_test.sh \ + configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py \ + none 1 --work-dir $WORK_DIR \ + --cfg-options model.init_cfg.checkpoint=$STEP2_CKPT model.init_weight_from_supernet=False +``` + +## Results and models + +| Dataset | Supernet | Subnet | Params(M) | Flops(G) | Top-1 | Config | Download | Remarks | +| :------: | :------------------: | :-------------------------------------------------------------------------------------------------------------------------------: | :--------------------: | :------------------: | :---------------------: | :-------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------: | +| ImageNet | AttentiveMobileNetV3 | [search space](https://github.com/open-mmlab/mmrazor/blob/dev-1.x/configs/_base_/nas_backbones/attentive_mobilenetv3_supernet.py) | 8.854(min) / 23.3(max) | 212(min) / 1944(max) | 77.19(min) / 81.42(max) | [config](https://github.com/open-mmlab/mmrazor/blob/dev-1.x/configs/nas/mmcls/bignas/attentive_mobilenet_supernet_32xb64_in1k.py) | [model\*](https://download.openmmlab.com/mmrazor/v1/bignas/attentive_mobilenet_supernet_32xb64_in1k_flops-2G_acc-81.72_20221229_200440-954772a3.pth) | [log](https://download.openmmlab.com/mmrazor/v1/bignas/attentive_mobilenet_supernet_32xb64_in1k_20221227_175800-bcf94eaa.json) (`sandwich rule`) | +| ImageNet | AttentiveMobileNetV3 | [AttentiveNAS-A0\*](https://download.openmmlab.com/mmrazor/v1/bignas/ATTENTIVE_SUBNET_A0.yaml) | 8.854 | 212 | 77.19 | [config](https://github.com/open-mmlab/mmrazor/blob/dev-1.x/configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/bignas/attentive_mobilenet_subnet_8xb256_in1k_flops-0.21G_acc-77.19_20221229_200440-282a1f70.pth) | Converted from the repo | +| ImageNet | AttentiveMobileNetV3 | [AttentiveNAS-A6\*](https://download.openmmlab.com/mmrazor/v1/bignas/ATTENTIVE_SUBNET_A6.yaml) | 15.594 | 927 | 80.81 | [config](https://github.com/open-mmlab/mmrazor/blob/dev-1.x/configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/bignas/attentive_mobilenet_subnet_8xb256_in1k_flops-0.93G_acc-80.81_20221229_200440-73d92cc6.pth) | Converted from the repo | + +*Models with * are converted from the [official repo](https://github.com/facebookresearch/AttentiveNAS). The config files of these models +are only for inference. We support training the supernet by `sandwich rule`, which is different from `rejection sampling` in [official repo](https://github.com/facebookresearch/AttentiveNAS), and welcome you to contribute your reproduction results.* + +**Note**: In the official `AttentiveNAS` code, the `AutoAugmentation` in Calib-BN subnet recommended to use large batchsize to evaluation like `256`, which leads to higher performance. Compared with the original configuration file, this configuration has been modified as follows: + +- modified the settings related to `batchsize` in `train_pipeline` and `test_pipeline`, e.g. setting `train_dataloader.batch_size=256`〠`val_dataloader.batch_size=256`ã€`test_cfg.calibrate_sample_num=16384` and `collate_fn=dict(type='default_collate')` in train_dataloader. +- setting `dict(type='mmrazor.AutoAugment', policies='original')` instead of `dict(type='mmrazor.AutoAugmentV2', policies=policies)` in train_pipeline. + +1. Used search_space in AttentiveNAS, which is different from BigNAS paper. +2. The Top-1 Acc is unstable and may fluctuate by about 0.1, convert [the official weight](https://download.openmmlab.com/mmrazor/v1/bignas/attentive_mobilenet_supernet_32xb64_in1k_flops-2G_acc-81.72_20221229_200440-954772a3.pth) according to the [converter script](../../../../tools/model_converters/convert_attentivenas_nas_ckpt.py). A Calib-BN model will be released later. +3. We have observed that the searchable model has been officially released. We will also provide the completed version of supernet training configuration in the future. + +## Citation + +```latex +@inproceedings{yu2020bignas, + title={Bignas: Scaling up neural architecture search with big single-stage models}, + author={Yu, Jiahui and Jin, Pengchong and Liu, Hanxiao and Bender, Gabriel and Kindermans, Pieter-Jan and Tan, Mingxing and Huang, Thomas and Song, Xiaodan and Pang, Ruoming and Le, Quoc}, + booktitle={European Conference on Computer Vision}, + pages={702--717}, + year={2020}, + organization={Springer} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_search_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_search_8xb128_in1k.py new file mode 100755 index 000000000..8ee2f9578 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_search_8xb128_in1k.py @@ -0,0 +1,16 @@ +_base_ = ['./attentive_mobilenet_supernet_32xb64_in1k.py'] + +train_cfg = dict( + _delete_=True, + type='mmrazor.EvolutionSearchLoop', + dataloader=_base_.val_dataloader, + evaluator=_base_.val_evaluator, + max_epochs=20, + num_candidates=50, + top_k=10, + num_mutation=25, + num_crossover=25, + mutate_prob=0.1, + calibrate_sample_num=4096, + constraints_range=dict(flops=(0., 700.)), + score_key='accuracy/top1') diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py new file mode 100755 index 000000000..6ce2cfec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py @@ -0,0 +1,24 @@ +_base_ = 'attentive_mobilenet_supernet_32xb64_in1k.py' + +model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.supernet, + # NOTE: You can replace the yaml with the mutable_cfg searched by yourself + fix_subnet='configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml', + # You can load the checkpoint of supernet instead of the specific + # subnet by modifying the `checkpoint`(path) in the following `init_cfg` + # with `init_weight_from_supernet = True`. + init_weight_from_supernet=True, + init_cfg=dict( + type='Pretrained', + checkpoint= # noqa: E251 + 'https://download.openmmlab.com/mmrazor/v1/bignas/attentive_mobilenet_supernet_32xb64_in1k_flops-2G_acc-81.72_20221229_200440-954772a3.pth', # noqa: E501 + prefix='architecture.')) + +model_wrapper_cfg = None +find_unused_parameters = True + +test_cfg = dict(evaluate_fixed_subnet=True) + +default_hooks = dict(checkpoint=None) diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_supernet_32xb64_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_supernet_32xb64_in1k.py new file mode 100755 index 000000000..2683b7e5b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_supernet_32xb64_in1k.py @@ -0,0 +1,59 @@ +_base_ = [ + 'mmcls::_base_/default_runtime.py', + 'mmrazor::_base_/settings/imagenet_bs2048_bignas.py', + 'mmrazor::_base_/nas_backbones/attentive_mobilenetv3_supernet.py', +] + +supernet = dict( + _scope_='mmrazor', + type='SearchableImageClassifier', + data_preprocessor=_base_.data_preprocessor, + backbone=_base_.nas_backbone, + neck=dict(type='SqueezeMeanPoolingWithDropout', drop_ratio=0.2), + head=dict( + type='DynamicLinearClsHead', + num_classes=1000, + in_channels=1984, + loss=dict( + type='mmcls.LabelSmoothLoss', + num_classes=1000, + label_smooth_val=0.1, + mode='original', + loss_weight=1.0), + topk=(1, 5)), + input_resizer_cfg=_base_.input_resizer_cfg, + connect_head=dict(connect_with_backbone='backbone.last_mutable_channels'), +) + +model = dict( + _scope_='mmrazor', + type='BigNAS', + drop_path_rate=0.2, + num_random_samples=2, + backbone_dropout_stages=[6, 7], + architecture=supernet, + distiller=dict( + type='ConfigurableDistiller', + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=1)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(recorder='fc', from_student=True), + preds_T=dict(recorder='fc', from_student=False)))), + mutator=dict(type='mmrazor.NasMutator')) + +model_wrapper_cfg = dict( + type='mmrazor.BigNASDDP', + broadcast_buffers=False, + find_unused_parameters=True) + +optim_wrapper_cfg = dict( + type='OptimWrapper', clip_grad=dict(type='value', clip_value=0.2)) + +default_hooks = dict( + checkpoint=dict( + type='CheckpointHook', interval=1, max_keep_ckpts=1, save_best='auto')) diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml new file mode 100755 index 000000000..9a3610daf --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml @@ -0,0 +1,80 @@ +normal_n2: + chosen: + - normal_n2_p0 + - normal_n2_p1 +normal_n2_p0: + chosen: + - sep_conv_3x3 +normal_n2_p1: + chosen: + - sep_conv_3x3 +normal_n3: + chosen: + - normal_n3_p0 + - normal_n3_p1 +normal_n3_p0: + chosen: + - skip_connect +normal_n3_p1: + chosen: + - sep_conv_5x5 +normal_n4: + chosen: + - normal_n4_p0 + - normal_n4_p1 +normal_n4_p0: + chosen: + - sep_conv_3x3 +normal_n4_p1: + chosen: + - skip_connect +normal_n5: + chosen: + - normal_n5_p0 + - normal_n5_p1 +normal_n5_p0: + chosen: + - skip_connect +normal_n5_p1: + chosen: + - skip_connect +reduce_n2: + chosen: + - reduce_n2_p0 + - reduce_n2_p1 +reduce_n2_p0: + chosen: + - max_pool_3x3 +reduce_n2_p1: + chosen: + - sep_conv_3x3 +reduce_n3: + chosen: + - reduce_n3_p0 + - reduce_n3_p2 +reduce_n3_p0: + chosen: + - max_pool_3x3 +reduce_n3_p2: + chosen: + - dil_conv_5x5 +reduce_n4: + chosen: + - reduce_n4_p0 + - reduce_n4_p2 +reduce_n4_p0: + chosen: + - max_pool_3x3 +reduce_n4_p2: + chosen: + - skip_connect +reduce_n5: + chosen: + - reduce_n5_p0 + - reduce_n5_p2 +reduce_n5_p0: + chosen: + - max_pool_3x3 +reduce_n5_p2: + chosen: + - skip_connect diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml new file mode 100755 index 000000000..347874e64 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml @@ -0,0 +1,116 @@ +normal_n2: + chosen: + - normal_n2_p1 + - normal_n2_p0 +normal_n2_p0: + chosen: + - sep_conv_3x3 +normal_n2_p1: + chosen: + - sep_conv_3x3 +normal_n3: + chosen: + - normal_n3_p0 + - normal_n3_p1 +normal_n3_p0: + chosen: + - sep_conv_3x3 +normal_n3_p1: + chosen: + - sep_conv_3x3 +normal_n3_p2: + chosen: + - sep_conv_3x3 +normal_n4: + chosen: + - normal_n4_p0 + - normal_n4_p1 +normal_n4_p0: + chosen: + - skip_connect +normal_n4_p1: + chosen: + - sep_conv_3x3 +normal_n4_p2: + chosen: + - skip_connect +normal_n4_p3: + chosen: + - sep_conv_3x3 +normal_n5: + chosen: + - normal_n5_p2 + - normal_n5_p0 +normal_n5_p0: + chosen: + - skip_connect +normal_n5_p1: + chosen: + - skip_connect +normal_n5_p2: + chosen: + - dil_conv_3x3 +normal_n5_p3: + chosen: + - skip_connect +normal_n5_p4: + chosen: + - skip_connect +reduce_n2: + chosen: + - reduce_n2_p0 + - reduce_n2_p1 +reduce_n2_p0: + chosen: + - max_pool_3x3 +reduce_n2_p1: + chosen: + - max_pool_3x3 +reduce_n3: + chosen: + - reduce_n3_p1 + - reduce_n3_p2 +reduce_n3_p0: + chosen: + - max_pool_3x3 +reduce_n3_p1: + chosen: + - max_pool_3x3 +reduce_n3_p2: + chosen: + - skip_connect +reduce_n4: + chosen: + - reduce_n4_p2 + - reduce_n4_p0 +reduce_n4_p0: + chosen: + - max_pool_3x3 +reduce_n4_p1: + chosen: + - max_pool_3x3 +reduce_n4_p2: + chosen: + - skip_connect +reduce_n4_p3: + chosen: + - skip_connect +reduce_n5: + chosen: + - reduce_n5_p1 + - reduce_n5_p2 +reduce_n5_p0: + chosen: + - max_pool_3x3 +reduce_n5_p1: + chosen: + - max_pool_3x3 +reduce_n5_p2: + chosen: + - skip_connect +reduce_n5_p3: + chosen: + - skip_connect +reduce_n5_p4: + chosen: + - skip_connect diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/README.md b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/README.md new file mode 100755 index 000000000..5d3da3d8e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/README.md @@ -0,0 +1,65 @@ +# DARTS + +> [DARTS: Differentiable Architecture Search](https://arxiv.org/abs/1806.09055) + + + +## Abstract + +This paper addresses the scalability challenge of architecture search by formulating the task in a differentiable manner. Unlike conventional approaches of applying evolution or reinforcement learning over a discrete and non-differentiable search space, our method is based on the continuous relaxation of the architecture representation, allowing efficient search of the architecture using gradient descent. Extensive experiments on CIFAR-10, ImageNet, Penn Treebank and WikiText-2 show that our algorithm excels in discovering high-performance convolutional architectures for image classification and recurrent architectures for language modeling, while being orders of magnitude faster than state-of-the-art non-differentiable techniques. Our implementation has been made publicly available to facilitate further research on efficient architecture search algorithms. + +![pipeline](https://user-images.githubusercontent.com/88702197/187425171-2dfe7fbf-7c2c-4c22-9219-2234aa83e47d.png) + +## Get Started + +### Step 1: Supernet training on Cifar-10 + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/mmcls/darts/darts_supernet_unroll_1xb96_cifar10.py 4 \ + --work-dir $WORK_DIR +``` + +## Step 2: Subnet retraining on Cifar-10 + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py 4 \ + --work-dir $WORK_DIR \ + --cfg-options model.init_cfg.checkpoint=$STEP2_CKPT +``` + +## Step 3: Subnet inference on Cifar-10 + +```bash +CUDA_VISIBLE_DEVICES=0 PORT=29500 ./tools/dist_test.sh \ + configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py \ + none 1 --work-dir $WORK_DIR \ + --cfg-options model.init_cfg.checkpoint=$STEP2_CKPT +``` + +## Results and models + +### Supernet + +| Dataset | Unroll | Config | Download | +| :-----: | :----: | :------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| Cifar10 | True | [config](./darts_supernet_unroll_1xb64_cifar10.py) | [model](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v0.1/nas/darts/darts_supernet_unroll_1xb64_cifar10/darts_supernet_unroll_1xb64_cifar10_20211222-a923a040.pth?versionId=CAEQHxiBgID6mLuL7xciIDhjYzA2NGViNzY5ZDQxODk5MTY3ZjBiMGUyMGNlYzlk) \| [log](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v0.1/nas/darts/darts_supernet_unroll_1xb64_cifar10/darts_supernet_unroll_1xb64_cifar10_20211220_133123.log.json?versionId=CAEQHxiBgIDmmLuL7xciIGQwN2RlZWUwNmZkYjQwMzU4MGRiMTA3NGY4NTU5N2Nm) | + +### Subnet + +| Dataset | Params(M) | Flops(G) | Top-1 Acc | Top-5 Acc | Subnet | Config | Download | Remarks | +| :-----: | :-------: | :------: | :-------: | :-------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------: | +| Cifar10 | 3.42 | 0.48 | 97.32 | 99.94 | [mutable](https://download.openmmlab.com/mmrazor/v1/darts/darts_subnetnet_1xb96_cifar10_acc-97.32_20211222-e5727921_mutable_cfg.yaml) | [config](./darts_subnet_1xb96_cifar10_2.0_mmrazor.py) | [model](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/darts/darts_subnetnet_1xb96_cifar10_acc-97.32_20211222-e5727921_latest.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/nas/darts/darts_subnetnet_1xb96_cifar10/darts_subnetnet_1xb96_cifar10_20211222-e5727921.log.json) | MMRazor searched | +| Cifar10 | 3.83 | 0.55 | 97.27 | 99.98 | [mutable](https://download.openmmlab.com/mmrazor/v0.1/nas/darts/darts_subnetnet_1xb96_cifar10/darts_subnetnet_1xb96_cifar10_acc-97.27_20211222-17e42600_mutable_cfg.yaml) | [config](./darts_subnet_1xb96_cifar10_2.0.py) | [model](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/darts/darts_subnetnet_1xb96_cifar10_acc-97.27_20211222-17e42600_latest.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/nas/darts/darts_subnetnet_1xb96_cifar10/darts_subnetnet_1xb96_cifar10_20211222-17e42600.log.json) | official | + +## Citation + +```latex +@inproceedings{liu2018darts, + title={DARTS: Differentiable Architecture Search}, + author={Liu, Hanxiao and Simonyan, Karen and Yang, Yiming}, + booktitle={International Conference on Learning Representations}, + year={2018} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py new file mode 100755 index 000000000..c05a3b435 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py @@ -0,0 +1,44 @@ +_base_ = [ + 'mmrazor::_base_/settings/cifar10_darts_subnet.py', + 'mmrazor::_base_/nas_backbones/darts_supernet.py', + 'mmcls::_base_/default_runtime.py', +] + +subnet_backbone = _base_.nas_backbone +subnet_backbone.base_channels = 36 +subnet_backbone.num_layers = 20 +subnet_backbone.auxliary = True +subnet_backbone.aux_channels = 128 +subnet_backbone.aux_out_channels = 768 +subnet_backbone.out_indices = (19, ) +subnet_backbone.norm_cfg = norm_cfg = dict(type='BN', affine=True) + +# model +supernet = dict( + type='ImageClassifier', + data_preprocessor=_base_.preprocess_cfg, + backbone=subnet_backbone, + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='mmrazor.DartsSubnetClsHead', + num_classes=10, + in_channels=576, + aux_in_channels=768, + loss=dict(type='CrossEntropyLoss', loss_weight=1.0), + aux_loss=dict(type='CrossEntropyLoss', loss_weight=0.4), + topk=(1, 5), + cal_acc=True)) + +model = dict( + type='mmrazor.sub_model', + cfg=supernet, + # NOTE: You can replace the yaml with the mutable_cfg searched by yourself + fix_subnet='configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml', + init_cfg=dict( + type='Pretrained', + checkpoint= # noqa: E251 + 'https://download.openmmlab.com/mmrazor/v1/darts/darts_subnetnet_1xb96_cifar10_acc-97.27_20211222-17e42600_latest.pth', # noqa: E501 + prefix='architecture.')) + +model_wrapper_cfg = None +find_unused_parameters = True diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0_mmrazor.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0_mmrazor.py new file mode 100755 index 000000000..2085c2130 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0_mmrazor.py @@ -0,0 +1,39 @@ +_base_ = [ + 'mmrazor::_base_/settings/cifar10_darts_subnet.py', + 'mmrazor::_base_/nas_backbones/darts_supernet.py', + 'mmcls::_base_/default_runtime.py', +] + +subnet_backbone = _base_.nas_backbone +subnet_backbone.base_channels = 36 +subnet_backbone.num_layers = 20 +subnet_backbone.auxliary = True +subnet_backbone.aux_channels = 128 +subnet_backbone.aux_out_channels = 768 +subnet_backbone.out_indices = (19, ) +subnet_backbone.norm_cfg = norm_cfg = dict(type='BN', affine=True) + +# model +supernet = dict( + type='ImageClassifier', + data_preprocessor=_base_.preprocess_cfg, + backbone=subnet_backbone, + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='mmrazor.DartsSubnetClsHead', + num_classes=10, + in_channels=576, + aux_in_channels=768, + loss=dict(type='CrossEntropyLoss', loss_weight=1.0), + aux_loss=dict(type='CrossEntropyLoss', loss_weight=0.4), + topk=(1, 5), + cal_acc=True)) + +model = dict( + type='mmrazor.sub_model', + cfg=supernet, + # NOTE: You can replace the yaml with the mutable_cfg searched by yourself + fix_subnet='configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml') + +_base_.model_wrapper_cfg = None +find_unused_parameters = True diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_supernet_unroll_1xb96_cifar10.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_supernet_unroll_1xb96_cifar10.py new file mode 100755 index 000000000..bcbd2dfe0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_supernet_unroll_1xb96_cifar10.py @@ -0,0 +1,33 @@ +_base_ = [ + 'mmrazor::_base_/settings/cifar10_darts_supernet.py', + 'mmrazor::_base_/nas_backbones/darts_supernet.py', + 'mmcls::_base_/default_runtime.py', +] + +custom_hooks = [ + dict(type='mmrazor.DumpSubnetHook', interval=10, by_epoch=True) +] + +# model +model = dict( + type='mmrazor.Darts', + architecture=dict( + type='ImageClassifier', + backbone=_base_.nas_backbone, + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=10, + in_channels=256, + loss=dict(type='CrossEntropyLoss', loss_weight=1.0), + topk=(1, 5), + cal_acc=True)), + mutator=dict(type='mmrazor.NasMutator'), + unroll=True) + +model_wrapper_cfg = dict( + type='mmrazor.DartsDDP', + broadcast_buffers=False, + find_unused_parameters=False) + +find_unused_parameter = False diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/metafile.yml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/metafile.yml new file mode 100755 index 000000000..b262a6960 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/metafile.yml @@ -0,0 +1,28 @@ +Collections: + - Name: Darts + Metadata: + Training Data: + - CIFAR-10 + Paper: + URL: https://arxiv.org/abs/1806.09055 + Title: DARTS:Differentiable Architecture Search + README: configs/nas/mmcls/darts/README.md + Code: + URL: https://github.com/open-mmlab/mmrazor/blob/v0.1.0/mmrazor/models/algorithms/darts.py + Version: v0.1.0 + Converted From: + Code: https://github.com/quark0/darts +Models: + - Name: darts_subnet_1xb96_cifar10_2.0 + In Collection: Darts + Metadata: + Params(M): 3.42 + Mutable: https://download.openmmlab.com/mmrazor/v1/darts/darts_subnetnet_1xb96_cifar10_acc-97.32_20211222-e5727921_mutable_cfg.yaml + Results: + - Task: Image Classification + Dataset: CIFAR-10 + Metrics: + Top 1 Accuracy: 97.32 + Top 5 Accuracy: 99.94 + Config: configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py + Weights: https://download.openmmlab.com/mmrazor/v1/darts/darts_subnetnet_1xb96_cifar10_acc-97.32_20211222-e5727921_latest.pth diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml new file mode 100755 index 000000000..0c35c01b5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml @@ -0,0 +1,40 @@ +backbone.layers.0.0: + chosen: shuffle_3x3 +backbone.layers.0.1: + chosen: shuffle_7x7 +backbone.layers.0.2: + chosen: shuffle_3x3 +backbone.layers.0.3: + chosen: shuffle_5x5 +backbone.layers.1.0: + chosen: shuffle_3x3 +backbone.layers.1.1: + chosen: shuffle_3x3 +backbone.layers.1.2: + chosen: shuffle_3x3 +backbone.layers.1.3: + chosen: shuffle_7x7 +backbone.layers.2.0: + chosen: shuffle_xception +backbone.layers.2.1: + chosen: shuffle_3x3 +backbone.layers.2.2: + chosen: shuffle_3x3 +backbone.layers.2.3: + chosen: shuffle_5x5 +backbone.layers.2.4: + chosen: shuffle_3x3 +backbone.layers.2.5: + chosen: shuffle_5x5 +backbone.layers.2.6: + chosen: shuffle_7x7 +backbone.layers.2.7: + chosen: shuffle_7x7 +backbone.layers.3.0: + chosen: shuffle_xception +backbone.layers.3.1: + chosen: shuffle_3x3 +backbone.layers.3.2: + chosen: shuffle_7x7 +backbone.layers.3.3: + chosen: shuffle_3x3 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/README.md b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/README.md new file mode 100755 index 000000000..222e731de --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/README.md @@ -0,0 +1,61 @@ +# DSNAS + +> [DSNAS: Direct Neural Architecture Search without Parameter Retraining](https://arxiv.org/abs/2002.09128.pdf) + + + +## Abstract + +Most existing NAS methods require two-stage parameter optimization. +However, performance of the same architecture in the two stages correlates poorly. +Based on this observation, DSNAS proposes a task-specific end-to-end differentiable NAS framework that simultaneously optimizes architecture and parameters with a low-biased Monte Carlo estimate. Child networks derived from DSNAS can be deployed directly without parameter retraining. + +![pipeline](/docs/en/imgs/model_zoo/dsnas/pipeline.jpg) + +## Get Started + +### Supernet training on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/mmcls/dsnas/dsnas_supernet_8xb128_in1k.py 4 \ + --work-dir $WORK_DIR +``` + +## Subnet inference on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0 PORT=29500 ./tools/dist_test.sh \ + configs/nas/mmcls/dsnas/dsnas_subnet_8xb128_in1k.py \ + $STEP1_CKPT 1 --work-dir $WORK_DIR +``` + +## Results and models + +### Supernet + +| Dataset | Params(M) | FLOPs (G) | Top-1 Acc (%) | Top-5 Acc (%) | Config | Download | Remarks | +| :------: | :-------: | :-------: | :-----------: | :-----------: | :---------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------: | +| ImageNet | 3.33 | 0.299 | 73.56 | 91.24 | [config](./dsnas_supernet_8xb128_in1k.py) | [model](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/dsnas/dsnas_supernet_8xb128_in1k_20220926_171954-29b87e3a.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/dsnas/dsnas_supernet_8xb128_in1k_20220926_171954-29b87e3a.log) | MMRazor searched | + +**Note**: + +1. There **might be(not all the case)** some small differences in our experiment in order to be consistent with other repos in OpenMMLab. For example, + normalize images in data preprocessing; resize by cv2 rather than PIL in training; dropout is not used in network. **Please refer to corresponding config for details.** +2. We convert the official searched checkpoint DSNASsearch240.pth into mmrazor-style and evaluate with pytorch1.8_cuda11.0, Top-1 is 74.1 and Top-5 is 91.51. +3. The implementation of ShuffleNetV2 in official DSNAS is different from OpenMMLab's and we follow the structure design in OpenMMLab. Note that with the + origin ShuffleNetV2 design in official DSNAS, the Top-1 is 73.92 and Top-5 is 91.59. +4. The finetune stage in our implementation refers to the 'search-from-search' stage mentioned in official DSNAS. +5. We obtain params and FLOPs using `mmrazor.ResourceEstimator`, which may be different from the origin repo. + +## Citation + +```latex +@inproceedings{hu2020dsnas, + title={Dsnas: Direct neural architecture search without parameter retraining}, + author={Hu, Shoukang and Xie, Sirui and Zheng, Hehui and Liu, Chunxiao and Shi, Jianping and Liu, Xunying and Lin, Dahua}, + booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, + pages={12084--12092}, + year={2020} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_subnet_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_subnet_8xb128_in1k.py new file mode 100755 index 000000000..beafd5638 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_subnet_8xb128_in1k.py @@ -0,0 +1,12 @@ +_base_ = ['./dsnas_supernet_8xb128_in1k.py'] + +model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.supernet, + # NOTE: You can replace the yaml with the mutable_cfg searched by yourself + fix_subnet= # noqa: E251 + 'configs/nas/mmcls/dsnas/DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml' +) # noqa: E501 + +find_unused_parameters = False diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_supernet_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_supernet_8xb128_in1k.py new file mode 100755 index 000000000..869dede5b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_supernet_8xb128_in1k.py @@ -0,0 +1,43 @@ +_base_ = [ + 'mmrazor::_base_/settings/imagenet_bs1024_dsnas.py', + 'mmrazor::_base_/nas_backbones/dsnas_shufflenet_supernet.py', + 'mmcls::_base_/default_runtime.py', +] + +custom_hooks = [ + dict(type='mmrazor.DumpSubnetHook', interval=10, by_epoch=True) +] + +supernet = dict( + _scope_='mmcls', + type='ImageClassifier', + data_preprocessor=_base_.data_preprocessor, + backbone=_base_.nas_backbone, + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=1000, + in_channels=1024, + loss=dict( + type='LabelSmoothLoss', + num_classes=1000, + label_smooth_val=0.1, + mode='original', + loss_weight=1.0), + topk=(1, 5))) + +# model +model = dict( + type='mmrazor.DSNAS', + architecture=supernet, + mutator=dict(type='mmrazor.NasMutator'), + pretrain_epochs=15, + finetune_epochs=_base_.search_epochs, +) + +model_wrapper_cfg = dict( + type='mmrazor.DSNASDDP', + broadcast_buffers=False, + find_unused_parameters=True) + +randomness = dict(seed=48, diff_rank_seed=True) diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT22.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT22.yaml new file mode 100755 index 000000000..144342caa --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT22.yaml @@ -0,0 +1,140 @@ +backbone.first_channels: + chosen: 16 +backbone.last_channels: + chosen: 1280 +backbone.layers.1.0.expand_ratio: + chosen: 1 +backbone.layers.1.0.kernel_size: + chosen: 3 +backbone.layers.1.depth: + chosen: 1 +backbone.layers.1.out_channels: + chosen: 16 +backbone.layers.2.0.expand_ratio: + chosen: 3 +backbone.layers.2.0.kernel_size: + chosen: 3 +backbone.layers.2.1.expand_ratio: + chosen: 3 +backbone.layers.2.1.kernel_size: + chosen: 3 +backbone.layers.2.2.expand_ratio: + chosen: 3 +backbone.layers.2.2.kernel_size: + chosen: 3 +backbone.layers.2.3.expand_ratio: + chosen: 3 +backbone.layers.2.3.kernel_size: + chosen: 3 +backbone.layers.2.depth: + chosen: 2 +backbone.layers.2.out_channels: + chosen: 24 +backbone.layers.3.0.expand_ratio: + chosen: 3 +backbone.layers.3.0.expand_ratio_se: + chosen: 4 +backbone.layers.3.0.kernel_size: + chosen: 5 +backbone.layers.3.1.expand_ratio: + chosen: 3 +backbone.layers.3.1.expand_ratio_se: + chosen: 3 +backbone.layers.3.1.kernel_size: + chosen: 5 +backbone.layers.3.2.expand_ratio: + chosen: 3 +backbone.layers.3.2.expand_ratio_se: + chosen: 3 +backbone.layers.3.2.kernel_size: + chosen: 3 +backbone.layers.3.3.expand_ratio: + chosen: 3 +backbone.layers.3.3.expand_ratio_se: + chosen: 3 +backbone.layers.3.3.kernel_size: + chosen: 3 +backbone.layers.3.depth: + chosen: 2 +backbone.layers.3.out_channels: + chosen: 40 +backbone.layers.4.0.expand_ratio: + chosen: 4 +backbone.layers.4.0.kernel_size: + chosen: 7 +backbone.layers.4.1.expand_ratio: + chosen: 3 +backbone.layers.4.1.kernel_size: + chosen: 3 +backbone.layers.4.2.expand_ratio: + chosen: 3 +backbone.layers.4.2.kernel_size: + chosen: 3 +backbone.layers.4.3.expand_ratio: + chosen: 3 +backbone.layers.4.3.kernel_size: + chosen: 3 +backbone.layers.4.depth: + chosen: 2 +backbone.layers.4.out_channels: + chosen: 80 +backbone.layers.5.0.expand_ratio: + chosen: 3 +backbone.layers.5.0.expand_ratio_se: + chosen: 3 +backbone.layers.5.0.kernel_size: + chosen: 5 +backbone.layers.5.1.expand_ratio: + chosen: 4 +backbone.layers.5.1.expand_ratio_se: + chosen: 4 +backbone.layers.5.1.kernel_size: + chosen: 3 +backbone.layers.5.2.expand_ratio: + chosen: 3 +backbone.layers.5.2.expand_ratio_se: + chosen: 3 +backbone.layers.5.2.kernel_size: + chosen: 3 +backbone.layers.5.3.expand_ratio: + chosen: 3 +backbone.layers.5.3.expand_ratio_se: + chosen: 3 +backbone.layers.5.3.kernel_size: + chosen: 3 +backbone.layers.5.depth: + chosen: 2 +backbone.layers.5.out_channels: + chosen: 112 +backbone.layers.6.0.expand_ratio: + chosen: 6 +backbone.layers.6.0.expand_ratio_se: + chosen: 6 +backbone.layers.6.0.kernel_size: + chosen: 3 +backbone.layers.6.1.expand_ratio: + chosen: 6 +backbone.layers.6.1.expand_ratio_se: + chosen: 6 +backbone.layers.6.1.kernel_size: + chosen: 7 +backbone.layers.6.2.expand_ratio: + chosen: 3 +backbone.layers.6.2.expand_ratio_se: + chosen: 6 +backbone.layers.6.2.kernel_size: + chosen: 3 +backbone.layers.6.3.expand_ratio: + chosen: 6 +backbone.layers.6.3.expand_ratio_se: + chosen: 6 +backbone.layers.6.3.kernel_size: + chosen: 3 +backbone.layers.6.depth: + chosen: 2 +backbone.layers.6.out_channels: + chosen: 160 +input_shape: + chosen: + - 140 + - 140 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT31.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT31.yaml new file mode 100755 index 000000000..b8f752d9f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT31.yaml @@ -0,0 +1,148 @@ +backbone.first_channels: + chosen: 16 +backbone.last_channels: + chosen: 1280 +backbone.layers.1.0.expand_ratio: + chosen: 1 +backbone.layers.1.0.kernel_size: + chosen: 3 +backbone.layers.1.depth: + chosen: 1 +backbone.layers.1.out_channels: + chosen: 16 +backbone.layers.2.0.expand_ratio: + chosen: 3 +backbone.layers.2.0.kernel_size: + chosen: 5 +backbone.layers.2.1.expand_ratio: + chosen: 3 +backbone.layers.2.1.kernel_size: + chosen: 3 +backbone.layers.2.2.expand_ratio: + chosen: 3 +backbone.layers.2.2.kernel_size: + chosen: 3 +backbone.layers.2.3.expand_ratio: + chosen: 3 +backbone.layers.2.3.kernel_size: + chosen: 3 +backbone.layers.2.depth: + chosen: 2 +backbone.layers.2.out_channels: + chosen: 24 +backbone.layers.3.0.expand_ratio: + chosen: 4 +backbone.layers.3.0.expand_ratio_se: + chosen: 4 +backbone.layers.3.0.kernel_size: + chosen: 5 +backbone.layers.3.1.expand_ratio: + chosen: 3 +backbone.layers.3.1.expand_ratio_se: + chosen: 3 +backbone.layers.3.1.kernel_size: + chosen: 5 +backbone.layers.3.2.expand_ratio: + chosen: 3 +backbone.layers.3.2.expand_ratio_se: + chosen: 3 +backbone.layers.3.2.kernel_size: + chosen: 3 +backbone.layers.3.3.expand_ratio: + chosen: 3 +backbone.layers.3.3.expand_ratio_se: + chosen: 3 +backbone.layers.3.3.kernel_size: + chosen: 3 +backbone.layers.3.depth: + chosen: 2 +backbone.layers.3.out_channels: + chosen: 40 +backbone.layers.4.0.expand_ratio: + chosen: 4 +backbone.layers.4.0.expand_ratio_se: + chosen: 4 +backbone.layers.4.0.kernel_size: + chosen: 3 +backbone.layers.4.1.expand_ratio: + chosen: 4 +backbone.layers.4.1.expand_ratio_se: + chosen: 4 +backbone.layers.4.1.kernel_size: + chosen: 3 +backbone.layers.4.2.expand_ratio: + chosen: 4 +backbone.layers.4.2.expand_ratio_se: + chosen: 4 +backbone.layers.4.2.kernel_size: + chosen: 5 +backbone.layers.4.3.expand_ratio: + chosen: 4 +backbone.layers.4.3.expand_ratio_se: + chosen: 4 +backbone.layers.4.3.kernel_size: + chosen: 3 +backbone.layers.4.depth: + chosen: 3 +backbone.layers.4.out_channels: + chosen: 80 +backbone.layers.5.0.expand_ratio: + chosen: 4 +backbone.layers.5.0.expand_ratio_se: + chosen: 4 +backbone.layers.5.0.kernel_size: + chosen: 3 +backbone.layers.5.1.expand_ratio: + chosen: 3 +backbone.layers.5.1.expand_ratio_se: + chosen: 3 +backbone.layers.5.1.kernel_size: + chosen: 5 +backbone.layers.5.2.expand_ratio: + chosen: 4 +backbone.layers.5.2.expand_ratio_se: + chosen: 4 +backbone.layers.5.2.kernel_size: + chosen: 7 +backbone.layers.5.3.expand_ratio: + chosen: 3 +backbone.layers.5.3.expand_ratio_se: + chosen: 3 +backbone.layers.5.3.kernel_size: + chosen: 3 +backbone.layers.5.depth: + chosen: 3 +backbone.layers.5.out_channels: + chosen: 112 +backbone.layers.6.0.expand_ratio: + chosen: 6 +backbone.layers.6.0.expand_ratio_se: + chosen: 6 +backbone.layers.6.0.kernel_size: + chosen: 3 +backbone.layers.6.1.expand_ratio: + chosen: 3 +backbone.layers.6.1.expand_ratio_se: + chosen: 3 +backbone.layers.6.1.kernel_size: + chosen: 3 +backbone.layers.6.2.expand_ratio: + chosen: 3 +backbone.layers.6.2.expand_ratio_se: + chosen: 3 +backbone.layers.6.2.kernel_size: + chosen: 5 +backbone.layers.6.3.expand_ratio: + chosen: 3 +backbone.layers.6.3.expand_ratio_se: + chosen: 3 +backbone.layers.6.3.kernel_size: + chosen: 5 +backbone.layers.6.depth: + chosen: 4 +backbone.layers.6.out_channels: + chosen: 160 +input_shape: + chosen: + - 152 + - 152 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/README.md b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/README.md new file mode 100755 index 000000000..92270f708 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/README.md @@ -0,0 +1,50 @@ +# Once-For-All + +> [ONCE-FOR-ALL: TRAIN ONE NETWORK AND SPE- CIALIZE IT FOR EFFICIENT DEPLOYMENT](https://arxiv.org/abs/1908.09791) + + + +## Abstract + +We address the challenging problem of efficient inference across many devices and resource constraints, especially on edge devices. Conventional approaches either manually design or use neural architecture search (NAS) to find a specialized neural network and train it from scratch for each case, which is computationally prohibitive (causing CO2 emission as much as 5 cars’ lifetime Strubell et al. (2019)) thus unscalable. In this work, we propose to train a once-for-all (OFA) network that supports diverse architectural settings by decoupling training and search, to reduce the cost. We can quickly get a specialized sub-network by selecting from the OFA network without additional training. To efficiently train OFA networks, we also propose a novel progressive shrinking algorithm, a generalized pruning method that reduces the model size across many more dimensions than pruning (depth, width, kernel size, and resolution). It can obtain a surprisingly large number of sub- networks (> 1019) that can fit different hardware platforms and latency constraints while maintaining the same level of accuracy as training independently. On diverse edge devices, OFA consistently outperforms state-of-the-art (SOTA) NAS methods (up to 4.0% ImageNet top1 accuracy improvement over MobileNetV3, or same accuracy but 1.5× faster than MobileNetV3, 2.6× faster than EfficientNet w.r.t measured latency) while reducing many orders of magnitude GPU hours and CO2 emission. In particular, OFA achieves a new SOTA 80.0% ImageNet top-1 accuracy under the mobile setting (\<600M MACs). OFA is the winning solution for the 3rd Low Power Computer Vision Challenge (LPCVC), DSP classification track and the 4th LPCVC, both classification track and detection track. + +## Get Started + +We product inference models which are published by official Once-For-All repo and converted by MMRazor. + +### Subnet test on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0 PORT=29500 ./tools/dist_test.sh \ + configs/nas/mmcls/onceforall/ofa_mobilenet_subnet_8xb256_in1k.py \ + none 1 --work-dir $WORK_DIR \ + --cfg-options model.init_cfg.checkpoint=$OFA_CKPT model.init_weight_from_supernet=False +``` + +## Results and models + +| Dataset | Supernet | Subnet | Params(M) | Flops(G) | Top-1 | Config | Download | Remarks | +| :------: | :------------------: | :-------------------------------------------------------------------------------------------------------------------------: | :-------: | :------: | :---: | :-----------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------: | +| ImageNet | AttentiveMobileNetV3 | [search space](https://github.com/open-mmlab/mmrazor/blob/dev-1.x/configs/_base_/nas_backbones/ofa_mobilenetv3_supernet.py) | 7.6 | 747.8 | 77.5 | [config](https://github.com/open-mmlab/mmrazor/blob/dev-1.x/configs/nas/mmcls/onceforall/ofa_mobilenet_supernet_32xb64_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/ofa/ofa_mobilenet_supernet_d234_e346_k357_w1_0.py_20221214_0940-d0ebc66f.pth) | Converted from the repo | +| ImageNet | AttentiveMobileNetV3 | note8_lat@22ms_top1@70.4_finetune@25 | 4.3 | 70.9 | 70.3 | [config](https://download.openmmlab.com/mmrazor/v1/ofa/rtmdet/OFA_SUBNET_NOTE8_LAT22.yaml) | [model](https://download.openmmlab.com/mmrazor/v1/ofa/ofa_mobilenet_subnet_8xb256_in1k_note8_lat%4022ms_top1%4070.4_finetune%4025.py_20221214_0938-fb7fb84f.pth) | Converted from the repo | +| ImageNet | AttentiveMobileNetV3 | note8_lat@31ms_top1@72.8_finetune@25 | 4.6 | 105.4 | 72.6 | [config](https://download.openmmlab.com/mmrazor/v1/ofa/rtmdet/OFA_SUBNET_NOTE8_LAT31.yaml) | [model](https://download.openmmlab.com/mmrazor/v1/ofa/ofa_mobilenet_subnet_8xb256_in1k_note8_lat%4031ms_top1%4072.8_finetune%4025.py_20221214_0939-981a8b2a.pth) | Converted from the repo | + +**Note**: + +1. OFA provides a more fine-grained search mode, which searches expand ratios & kernel size for each block in every layer of the defined supernet, therefore the subnet configs (format as .yaml) is more complex than those of BigNAS/AttentiveNAS. +2. We product the [ofa script](../../../../tools/model_converters/convert_ofa_ckpt.py) to convert the official weight into MMRazor-style. The layer depth of a specific subnet is required when converting keys. +3. The models above are converted from the [once-for-all official repo](https://github.com/mit-han-lab/once-for-all). The config files of these models + are only for inference. We don't ensure training accuracy of these config files and you are welcomed to contribute your reproduction results. + +## Citation + +```latex +@inproceedings{ + cai2020once, + title={Once for All: Train One Network and Specialize it for Efficient Deployment}, + author={Han Cai and Chuang Gan and Tianzhe Wang and Zhekai Zhang and Song Han}, + booktitle={International Conference on Learning Representations}, + year={2020}, + url={https://arxiv.org/pdf/1908.09791.pdf} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_search_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_search_8xb128_in1k.py new file mode 100755 index 000000000..75d52ad58 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_search_8xb128_in1k.py @@ -0,0 +1,16 @@ +_base_ = ['./ofa_mobilenet_supernet_32xb64_in1k.py'] + +train_cfg = dict( + _delete_=True, + type='mmrazor.EvolutionSearchLoop', + dataloader=_base_.val_dataloader, + evaluator=_base_.val_evaluator, + max_epochs=1, + num_candidates=2, + top_k=1, + num_mutation=1, + num_crossover=1, + mutate_prob=0.1, + calibrate_sample_num=4096, + constraints_range=dict(flops=(0., 700.)), + score_key='accuracy/top1') diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_subnet_8xb256_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_subnet_8xb256_in1k.py new file mode 100755 index 000000000..9b033b3e3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_subnet_8xb256_in1k.py @@ -0,0 +1,22 @@ +_base_ = 'ofa_mobilenet_supernet_32xb64_in1k.py' + +model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.supernet, + # NOTE: You can replace the yaml with the mutable_cfg searched by yourself + fix_subnet='configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT31.yaml', + # You can also load the checkpoint of supernet instead of the specific + # subnet by modifying the `checkpoint`(path) in the following `init_cfg` + # with `init_weight_from_supernet = True`. + init_weight_from_supernet=False, + init_cfg=dict( + type='Pretrained', + checkpoint= # noqa: E251 + 'https://download.openmmlab.com/mmrazor/v1/ofa/ofa_mobilenet_subnet_8xb256_in1k_note8_lat%4031ms_top1%4072.8_finetune%4025.py_20221214_0939-981a8b2a.pth', # noqa: E501 + prefix='architecture.')) + +model_wrapper_cfg = None +find_unused_parameters = True + +test_cfg = dict(evaluate_fixed_subnet=True) diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_supernet_32xb64_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_supernet_32xb64_in1k.py new file mode 100755 index 000000000..341f4bda9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_supernet_32xb64_in1k.py @@ -0,0 +1,51 @@ +_base_ = [ + 'mmcls::_base_/default_runtime.py', + 'mmrazor::_base_/settings/imagenet_bs2048_ofa.py', + 'mmrazor::_base_/nas_backbones/ofa_mobilenetv3_supernet.py', +] + +supernet = dict( + _scope_='mmrazor', + type='SearchableImageClassifier', + data_preprocessor=_base_.data_preprocessor, + backbone=_base_.nas_backbone, + neck=dict(type='mmcls.GlobalAveragePooling'), + head=dict( + type='DynamicLinearClsHead', + num_classes=1000, + in_channels=1280, + loss=dict( + type='mmcls.LabelSmoothLoss', + num_classes=1000, + label_smooth_val=0.1, + mode='original', + loss_weight=1.0), + topk=(1, 5)), + input_resizer_cfg=_base_.input_resizer_cfg, + connect_head=dict(connect_with_backbone='backbone.last_mutable_channels'), +) + +model = dict( + _scope_='mmrazor', + type='BigNAS', + drop_path_rate=0.2, + backbone_dropout_stages=[6, 7], + architecture=supernet, + distiller=dict( + type='ConfigurableDistiller', + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=1)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(recorder='fc', from_student=True), + preds_T=dict(recorder='fc', from_student=False)))), + mutators=dict(type='mmrazor.NasMutator')) + +model_wrapper_cfg = dict( + type='mmrazor.BigNASDDP', + broadcast_buffers=False, + find_unused_parameters=True) diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/README.md b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/README.md new file mode 100755 index 000000000..19e55b795 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/README.md @@ -0,0 +1,76 @@ +# SPOS + +> [Single Path One-Shot Neural Architecture Search with Uniform Sampling](https://arxiv.org/abs/1904.00420) + + + +## Abstract + +We revisit the one-shot Neural Architecture Search (NAS) paradigm and analyze its advantages over existing NAS approaches. Existing one-shot method, however, is hard to train and not yet effective on large scale datasets like ImageNet. This work propose a Single Path One-Shot model to address the challenge in the training. Our central idea is to construct a simplified supernet, where all architectures are single paths so that weight co-adaption problem is alleviated. Training is performed by uniform path sampling. All architectures (and their weights) are trained fully and equally. +Comprehensive experiments verify that our approach is flexible and effective. It is easy to train and fast to search. It effortlessly supports complex search spaces (e.g., building blocks, channel, mixed-precision quantization) and different search constraints (e.g., FLOPs, latency). It is thus convenient to use for various needs. It achieves start-of-the-art performance on the large dataset ImageNet. + +![pipeline](https://user-images.githubusercontent.com/88702197/187424862-c2f3fde1-4a48-4eda-9ff7-c65971b683ba.jpg) + +## Get Started + +### Step 1: Supernet pre-training on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/spos/spos_supernet_shufflenetv2_8xb128_in1k.py 4 \ + --work-dir $WORK_DIR \ +``` + +### Step 2: Search for subnet on the trained supernet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/spos/spos_evolution_search_shufflenetv2_8xb2048_in1k.py 4 \ + --work-dir $WORK_DIR --cfg-options load_from=$STEP1_CKPT +``` + +### Step 3: Subnet retraining on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/spos/spos_subnet_shufflenetv2_8xb128_in1k.py 4 \ + --work-dir $WORK_DIR \ + --cfg-options model.init_cfg.checkpoint=$STEP2_CKPT + +``` + +## Step 4: Subnet inference on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0 PORT=29500 ./tools/dist_test.sh \ + configs/nas/spos/spos_subnet_shufflenetv2_8xb128_in1k.py \ + none 1 --work-dir $WORK_DIR \ + --cfg-options model.init_cfg.checkpoint=$STEP3_CKPT +``` + +## Results and models + +| Dataset | Supernet | Subnet | Params(M) | Flops(G) | Top-1 (%) | Top-5 (%) | Config | Download | Remarks | +| :------: | :--------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------: | :-------: | :------: | :-------: | :-------: | :-------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :-----------------------------------------------------------: | +| ImageNet | ShuffleNetV2 | [mutable](https://download.openmmlab.com/mmrazor/v1/spos/spos_shufflenetv2_subnet_8xb128_in1k_flops_0.33M_acc_73.87_20220715-aa94d5ef_subnet_cfg_v3.yaml) | 3.35 | 0.33 | 73.87 | 91.6 | [config](https://github.com/open-mmlab/mmrazor/blob/dev-1.x/configs/nas/mmcls/spos/spos_subnet_shufflenetv2_8xb128_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/spos/spos_shufflenetv2_subnet_8xb128_in1k_flops_0.33M_acc_73.87_20211222-1f0a0b4d_v3.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/nas/spos/spos_shufflenetv2_subnet_8xb128_in1k/spos_shufflenetv2_subnet_8xb128_in1k_flops_0.33M_acc_73.87_20211222-1f0a0b4d.log.json) | MMRazor searched | +| ImageNet | MobileNet-ProxylessGPU | [mutable](https://download.openmmlab.com/mmrazor/v0.1/nas/spos/spos_mobilenet_subnet/spos_angelnas_flops_0.49G_acc_75.98_20220307-54f4698f_mutable_cfg.yaml) | 5.94 | 0.49\* | 75.98 | 92.77 | [config](https://github.com/open-mmlab/mmrazor/blob/dev-1.x/configs/nas/mmcls/spos/spos_mobilenet_subnet_8xb128_in1k.py) | | [AngleNAS](https://github.com/megvii-model/AngleNAS) searched | + +**Note**: + +1. There **might be(not all the case)** some small differences in our experiment in order to be consistent with other repos in OpenMMLab. For example, + normalize images in data preprocessing; resize by cv2 rather than PIL in training; dropout is not used in network. **Please refer to corresponding config for details.** +2. For *ShuffleNetV2*, we retrain the subnet reported in paper with their official code, Top-1 is 73.6 and Top-5 is 91.6. +3. For *AngleNAS searched MobileNet-ProxylessGPU*, we obtain params and FLOPs using [this script](/tools/misc/get_flops.py), which may be different from [AngleNAS](https://github.com/megvii-model/AngleNAS#searched-models-with-abs). + +## Citation + +```latex +@inproceedings{guo2020single, + title={Single path one-shot neural architecture search with uniform sampling}, + author={Guo, Zichao and Zhang, Xiangyu and Mu, Haoyuan and Heng, Wen and Liu, Zechun and Wei, Yichen and Sun, Jian}, + booktitle={European Conference on Computer Vision}, + pages={544--560}, + year={2020}, + organization={Springer} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/SPOS_SUBNET.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/SPOS_SUBNET.yaml new file mode 100755 index 000000000..ba809da1d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/SPOS_SUBNET.yaml @@ -0,0 +1,40 @@ +backbone.layers.0.0: + chosen: shuffle_7x7 +backbone.layers.0.1: + chosen: shuffle_3x3 +backbone.layers.0.2: + chosen: shuffle_7x7 +backbone.layers.0.3: + chosen: shuffle_3x3 +backbone.layers.1.0: + chosen: shuffle_xception +backbone.layers.1.1: + chosen: shuffle_5x5 +backbone.layers.1.2: + chosen: shuffle_5x5 +backbone.layers.1.3: + chosen: shuffle_3x3 +backbone.layers.2.0: + chosen: shuffle_3x3 +backbone.layers.2.1: + chosen: shuffle_5x5 +backbone.layers.2.2: + chosen: shuffle_3x3 +backbone.layers.2.3: + chosen: shuffle_5x5 +backbone.layers.2.4: + chosen: shuffle_3x3 +backbone.layers.2.5: + chosen: shuffle_xception +backbone.layers.2.6: + chosen: shuffle_5x5 +backbone.layers.2.7: + chosen: shuffle_7x7 +backbone.layers.3.0: + chosen: shuffle_7x7 +backbone.layers.3.1: + chosen: shuffle_3x3 +backbone.layers.3.2: + chosen: shuffle_5x5 +backbone.layers.3.3: + chosen: shuffle_xception diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/faster-rcnn_nas_backbone_fpn_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/faster-rcnn_nas_backbone_fpn_1x_coco.py new file mode 100755 index 000000000..d1ed4a937 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/faster-rcnn_nas_backbone_fpn_1x_coco.py @@ -0,0 +1,21 @@ +# Suppose you are in mmdet and want to use the searched subnet +# as backbone for faster-rcnn, then you can just use this config. + +_base_ = [ + '../_base_/models/faster-rcnn_r50_fpn.py', + '../_base_/datasets/coco_detection.py', + '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py', + 'mmrazor::_base_/nas_backbones/spos_shufflenet_supernet.py' +] + +_base_.nas_backbone.out_indices = (0, 1, 2, 3) +_base_.nas_backbone.with_last_layer = False +nas_backbone = dict( + # use mmrazor's build_func + type='mmrazor.sub_model', + cfg=_base_.nas_backbone, + fix_subnet='/path/to/your/mmrazor/configs/nas/mmcls/spos/SPOS_SUBNET.yaml', + extra_prefix='backbone.') + +_base_.model.backbone = nas_backbone +_base_.model.neck.in_channels = [64, 160, 320, 640] diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/metafile.yml b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/metafile.yml new file mode 100755 index 000000000..0a8dc5960 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/metafile.yml @@ -0,0 +1,28 @@ +Collections: + - Name: SPOS + Metadata: + Training Data: + - ImageNet-1k + Paper: + URL: https://arxiv.org/abs/1904.00420 + Title: Single Path One-Shot Neural Architecture Search with Uniform Sampling + README: configs/nas/mmcls/spos/README.md + Code: + URL: https://github.com/open-mmlab/mmrazor/blob/v0.1.0/mmrazor/models/algorithms/spos.py + Version: v0.1.0 + Converted From: + Code: https://github.com/megvii-model/SinglePathOneShot +Models: + - Name: spos_shufflenet_subnet_8xb128_in1k + In Collection: SPOS + Metadata: + FLOPs: 330 MB + Subnet: https://download.openmmlab.com/mmrazor/v1/spos/spos_shufflenetv2_subnet_8xb128_in1k_flops_0.33M_acc_73.87_20211222-1f0a0b4d_subnet_cfg_v3.yaml + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 73.87 + Top 5 Accuracy: 91.60 + Config: configs/nas/mmcls/spos/spos_shufflenet_subnet_8xb128_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/spos/spos_shufflenetv2_subnet_8xb128_in1k_flops_0.33M_acc_73.87_20211222-1f0a0b4d_v3.pth diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_search_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_search_8xb128_in1k.py new file mode 100755 index 000000000..87553ec39 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_search_8xb128_in1k.py @@ -0,0 +1,17 @@ +_base_ = ['./spos_mobilenet_supernet_8xb128_in1k.py'] + +model = dict(norm_training=True) + +train_cfg = dict( + _delete_=True, + type='mmrazor.EvolutionSearchLoop', + dataloader=_base_.val_dataloader, + evaluator=_base_.val_evaluator, + max_epochs=20, + num_candidates=50, + top_k=10, + num_mutation=25, + num_crossover=25, + mutate_prob=0.1, + constraints_range=dict(flops=(0., 465.)), + score_key='accuracy/top1') diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_subnet_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_subnet_8xb128_in1k.py new file mode 100755 index 000000000..a45d17c1b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_subnet_8xb128_in1k.py @@ -0,0 +1,17 @@ +_base_ = ['./spos_mobilenet_supernet_8xb128_in1k.py'] + +model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.supernet, + # NOTE: You can replace the yaml with the mutable_cfg searched by yourself + fix_subnet='configs/nas/spos/AngleNAS_SHUFFLENETV2_IN1k_2.0.yaml', + init_cfg=dict( + type='Pretrained', + checkpoint= # noqa: E251 + 'https://download.openmmlab.com/mmrazor/v1/spos/spos_mobilenetv2_subnet_8xb128_in1k_flops_0.33M_acc_73.87_20211222-1f0a0b4d_v3.pth', # noqa: E501 + prefix='architecture.')) + +model_wrapper_cfg = None + +find_unused_parameters = False diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_supernet_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_supernet_8xb128_in1k.py new file mode 100755 index 000000000..eb38013af --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_supernet_8xb128_in1k.py @@ -0,0 +1,31 @@ +_base_ = [ + 'mmrazor::_base_/settings/imagenet_bs1024_spos.py', + 'mmrazor::_base_/nas_backbones/spos_mobilenet_supernet.py', + 'mmcls::_base_/default_runtime.py', +] + +# model +supernet = dict( + _scope_='mmcls', + type='ImageClassifier', + # data_preprocessor=_base_.preprocess_cfg, + backbone=_base_.nas_backbone, + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=1000, + in_channels=1728, + loss=dict( + type='LabelSmoothLoss', + num_classes=1000, + label_smooth_val=0.1, + mode='original', + loss_weight=1.0), + topk=(1, 5))) + +model = dict( + type='mmrazor.SPOS', + architecture=supernet, + mutator=dict(type='mmrazor.NasMutator')) + +find_unused_parameters = True diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_8xb128_in1k.py new file mode 100755 index 000000000..f5a5e88f4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_8xb128_in1k.py @@ -0,0 +1,17 @@ +_base_ = ['./spos_shufflenet_supernet_8xb128_in1k.py'] + +model = dict(norm_training=True) + +train_cfg = dict( + _delete_=True, + type='mmrazor.EvolutionSearchLoop', + dataloader=_base_.val_dataloader, + evaluator=_base_.val_evaluator, + max_epochs=20, + num_candidates=50, + top_k=10, + num_mutation=25, + num_crossover=25, + mutate_prob=0.1, + constraints_range=dict(flops=(0, 330)), + score_key='accuracy/top1') diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_predictor_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_predictor_8xb128_in1k.py new file mode 100755 index 000000000..fb08d3494 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_predictor_8xb128_in1k.py @@ -0,0 +1,21 @@ +_base_ = ['./spos_shufflenet_supernet_8xb128_in1k.py'] + +model = dict(norm_training=True) + +train_cfg = dict( + _delete_=True, + type='mmrazor.EvolutionSearchLoop', + dataloader=_base_.val_dataloader, + evaluator=_base_.val_evaluator, + max_epochs=20, + num_candidates=50, + top_k=10, + num_mutation=25, + num_crossover=25, + mutate_prob=0.1, + constraints_range=dict(flops=(0., 360.)), + predictor_cfg=dict( + type='mmrazor.MetricPredictor', + train_samples=20, + handler_cfg=dict(type='mmrazor.GaussProcessHandler')), +) diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_subnet_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_subnet_8xb128_in1k.py new file mode 100755 index 000000000..7f671def4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_subnet_8xb128_in1k.py @@ -0,0 +1,17 @@ +_base_ = ['./spos_shufflenet_supernet_8xb128_in1k.py'] + +_base_.model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.supernet, + # NOTE: You can replace the yaml with the mutable_cfg searched by yourself + fix_subnet='configs/nas/mmcls/spos/SPOS_SUBNET.yaml', + init_cfg=dict( + type='Pretrained', + checkpoint= # noqa: E251 + 'https://download.openmmlab.com/mmrazor/v1/spos/spos_shufflenetv2_subnet_8xb128_in1k_flops_0.33M_acc_73.87_20211222-1f0a0b4d_v3.pth', # noqa: E501 + prefix='architecture.')) + +model_wrapper_cfg = None + +find_unused_parameters = False diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_supernet_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_supernet_8xb128_in1k.py new file mode 100755 index 000000000..869bcac4c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_supernet_8xb128_in1k.py @@ -0,0 +1,31 @@ +_base_ = [ + 'mmrazor::_base_/settings/imagenet_bs1024_spos.py', + 'mmrazor::_base_/nas_backbones/spos_shufflenet_supernet.py', + 'mmcls::_base_/default_runtime.py', +] + +# model +supernet = dict( + _scope_='mmcls', + type='ImageClassifier', + data_preprocessor=_base_.preprocess_cfg, + backbone=_base_.nas_backbone, + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=1000, + in_channels=1024, + loss=dict( + type='LabelSmoothLoss', + num_classes=1000, + label_smooth_val=0.1, + mode='original', + loss_weight=1.0), + topk=(1, 5))) + +model = dict( + type='mmrazor.SPOS', + architecture=supernet, + mutator=dict(type='mmrazor.NasMutator')) + +find_unused_parameters = True diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/DETNAS_SUBNET.yaml b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/DETNAS_SUBNET.yaml new file mode 100755 index 000000000..c7bcab916 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/DETNAS_SUBNET.yaml @@ -0,0 +1,40 @@ +backbone.layers.0.0: + chosen: shuffle_5x5 +backbone.layers.0.1: + chosen: shuffle_3x3 +backbone.layers.0.2: + chosen: shuffle_3x3 +backbone.layers.0.3: + chosen: shuffle_3x3 +backbone.layers.1.0: + chosen: shuffle_xception +backbone.layers.1.1: + chosen: shuffle_3x3 +backbone.layers.1.2: + chosen: shuffle_xception +backbone.layers.1.3: + chosen: shuffle_7x7 +backbone.layers.2.0: + chosen: shuffle_7x7 +backbone.layers.2.1: + chosen: shuffle_7x7 +backbone.layers.2.2: + chosen: shuffle_xception +backbone.layers.2.3: + chosen: shuffle_xception +backbone.layers.2.4: + chosen: shuffle_3x3 +backbone.layers.2.5: + chosen: shuffle_7x7 +backbone.layers.2.6: + chosen: shuffle_5x5 +backbone.layers.2.7: + chosen: shuffle_xception +backbone.layers.3.0: + chosen: shuffle_7x7 +backbone.layers.3.1: + chosen: shuffle_7x7 +backbone.layers.3.2: + chosen: shuffle_7x7 +backbone.layers.3.3: + chosen: shuffle_5x5 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/README.md b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/README.md new file mode 100755 index 000000000..2b4096a63 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/README.md @@ -0,0 +1,87 @@ +# DetNAS + +> [DetNAS: Backbone Search for Object Detection](https://arxiv.org/abs/1903.10979) + + + +## Abstract + +Object detectors are usually equipped with backbone networks designed for image classification. It might be sub-optimal because of the gap between the tasks of image classification and object detection. In this work, we present DetNAS to use Neural Architecture Search (NAS) for the design of better backbones for object detection. It is non-trivial because detection training typically needs ImageNet pre-training while NAS systems require accuracies on the target detection task as supervisory signals. Based on the technique of one-shot supernet, which contains all possible networks in the search space, we propose a framework for backbone search on object detection. We train the supernet under the typical detector training schedule: ImageNet pre-training and detection fine-tuning. Then, the architecture search is performed on the trained supernet, using the detection task as the guidance. This framework makes NAS on backbones very efficient. In experiments, we show the effectiveness of DetNAS on various detectors, for instance, one-stage RetinaNet and the two-stage FPN. We empirically find that networks searched on object detection shows consistent superiority compared to those searched on ImageNet classification. The resulting architecture achieves superior performance than hand-crafted networks on COCO with much less FLOPs complexity. + +![pipeline](https://user-images.githubusercontent.com/88702197/187425296-64baa22a-9422-46cd-bd95-47e3e5707f75.jpg) + +## Get Started + +### Step 1: Supernet pre-training on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/detnas/detnas_supernet_shufflenetv2_8xb128_in1k.py 4 \ + --work-dir $WORK_DIR +``` + +### Step 2: Supernet fine-tuning on COCO + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/detnas/detnas_supernet_frcnn_shufflenetv2_fpn_1x_coco.py 4 \ + --work-dir $WORK_DIR --cfg-options load_from=$STEP1_CKPT +``` + +### Step 3: Search for subnet on the trained supernet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/detnas/detnas_evolution_search_frcnn_shufflenetv2_fpn_coco.py 4 \ + --work-dir $WORK_DIR --cfg-options load_from=$STEP2_CKPT +``` + +### Step 4: Subnet retraining on ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/detnas/detnas_subnet_shufflenetv2_8xb128_in1k.py 4 \ + --work-dir $WORK_DIR --cfg-options algorithm.mutable_cfg=$STEP3_SUBNET_YAML # or modify the config directly +``` + +### Step 5: Subnet fine-tuning on COCO + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/nas/detnas/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco.py 4 \ + --work-dir $WORK_DIR \ + --cfg-options --cfg-options model.init_cfg.checkpoint=$STEP4_CKPT +``` + +### Step 6: Subnet inference on COCO + +```bash +CUDA_VISIBLE_DEVICES=0 PORT=29500 ./tools/dist_test.sh \ + configs/nas/detnas/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco.py \ + none 1 --work-dir $WORK_DIR \ + --cfg-options model.init_cfg.checkpoint=$STEP5_CKPT +``` + +## Results and models + +| Dataset | Supernet | Subnet | Params(M) | Flops(G) | mAP | Config | Download | Remarks | +| :-----: | :----------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------: | :------------: | :--: | :---------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------: | +| COCO | FRCNN-ShuffleNetV2 | [mutable](https://download.openmmlab.com/mmrazor/v0.1/nas/detnas/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco_bbox_backbone_flops-0.34M_mAP-37.5_20211222-67fea61f_mutable_cfg.yaml) | 3.35(backbone) | 0.34(backbone) | 37.5 | [config](./detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco.py) | [pretrain](https://download.openmmlab.com/mmrazor/v0.1/nas/detnas/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco/detnas_subnet_shufflenetv2_8xb128_in1k_acc-74.08_20211223-92e9b66a.pth) \|[model](https://download.openmmlab.com/mmrazor/v0.1/nas/detnas/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco_bbox_backbone_flops-0.34M_mAP-37.5_20211222-67fea61f.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/nas/detnas/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco_bbox_backbone_flops-0.34M_mAP-37.5_20211222-67fea61f.log.json) | MMRazor searched | + +**Note**: + +1. The experiment settings of DetNAS are similar with SPOS's, and our training dataset is COCO2017 rather than COCO2014. +2. We also retrained official subnet with same experiment settings, the final result is 36.9 + +## Citation + +```latex +@article{chen2019detnas, + title={Detnas: Backbone search for object detection}, + author={Chen, Yukang and Yang, Tong and Zhang, Xiangyu and Meng, Gaofeng and Xiao, Xinyu and Sun, Jian}, + journal={Advances in Neural Information Processing Systems}, + volume={32}, + pages={6642--6652}, + year={2019} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_search_coco_1x.py b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_search_coco_1x.py new file mode 100755 index 000000000..689618362 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_search_coco_1x.py @@ -0,0 +1,17 @@ +_base_ = ['./detnas_frcnn_shufflenet_supernet_coco_1x.py'] + +model = dict(norm_training=True) + +train_cfg = dict( + _delete_=True, + type='mmrazor.EvolutionSearchLoop', + dataloader=_base_.val_dataloader, + evaluator=_base_.val_evaluator, + max_epochs=20, + num_candidates=50, + top_k=10, + num_mutation=20, + num_crossover=20, + mutate_prob=0.1, + constraints_range=dict(flops=(0, 330)), + score_key='coco/bbox_mAP') diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_subnet_coco_1x.py b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_subnet_coco_1x.py new file mode 100755 index 000000000..e10daec7d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_subnet_coco_1x.py @@ -0,0 +1,15 @@ +_base_ = ['./detnas_frcnn_shufflenet_supernet_coco_1x.py'] + +model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.supernet, + # NOTE: You can replace the yaml with the mutable_cfg searched by yourself + fix_subnet='configs/nas/mmdet/detnas/DETNAS_SUBNET.yaml', + init_cfg=dict( + type='Pretrained', + checkpoint= # noqa: E251 + 'https://download.openmmlab.com/mmrazor/v1/detnas/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco_bbox_backbone_flops-0.34M_mAP-37.5_20220715-61d2e900_v1.pth', # noqa: E501 + prefix='architecture.')) + +find_unused_parameters = False diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_supernet_coco_1x.py b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_supernet_coco_1x.py new file mode 100755 index 000000000..b2b2711f6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_supernet_coco_1x.py @@ -0,0 +1,30 @@ +_base_ = [ + 'mmdet::_base_/models/faster-rcnn_r50_fpn.py', + 'mmdet::_base_/datasets/coco_detection.py', + 'mmdet::_base_/schedules/schedule_1x.py', + 'mmdet::_base_/default_runtime.py', + 'mmrazor::_base_/nas_backbones/spos_shufflenet_supernet.py' +] + +norm_cfg = dict(type='SyncBN', requires_grad=True) + +supernet = _base_.model + +supernet.backbone = _base_.nas_backbone +supernet.backbone.norm_cfg = norm_cfg +supernet.backbone.out_indices = (0, 1, 2, 3) +supernet.backbone.with_last_layer = False + +supernet.neck.norm_cfg = norm_cfg +supernet.neck.in_channels = [64, 160, 320, 640] + +supernet.roi_head.bbox_head.norm_cfg = norm_cfg +supernet.roi_head.bbox_head.type = 'Shared4Conv1FCBBoxHead' + +model = dict( + _delete_=True, + type='mmrazor.SPOS', + architecture=supernet, + mutator=dict(type='mmrazor.NasMutator')) + +find_unused_parameters = True diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_retina_shufflenet_supernet_coco_1x.py b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_retina_shufflenet_supernet_coco_1x.py new file mode 100755 index 000000000..21c37f51e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_retina_shufflenet_supernet_coco_1x.py @@ -0,0 +1,27 @@ +_base_ = [ + 'mmdet::_base_/models/retinanet_r50_fpn.py', + 'mmdet::_base_/datasets/coco_detection.py', + 'mmdet::_base_/schedules/schedule_1x.py', + 'mmdet::_base_/default_runtime.py', + 'mmrazor::_base_/nas_backbones/spos_shufflenet_supernet.py' +] + +norm_cfg = dict(type='SyncBN', requires_grad=True) + +supernet = _base_.model + +supernet.backbone = _base_.nas_backbone +supernet.backbone.norm_cfg = norm_cfg +supernet.backbone.out_indices = (0, 1, 2, 3) +supernet.backbone.with_last_layer = False + +supernet.neck.norm_cfg = norm_cfg +supernet.neck.in_channels = [64, 160, 320, 640] + +model = dict( + _delete_=True, + type='mmrazor.SPOS', + architecture=supernet, + mutator=dict(type='mmrazor.NasMutator')) + +find_unused_parameters = True diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_subnet_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_subnet_8xb128_in1k.py new file mode 100755 index 000000000..4129f1863 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_subnet_8xb128_in1k.py @@ -0,0 +1,12 @@ +_base_ = './detnas_shufflenet_supernet_8xb128_in1k.py' + +model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.supernet, + # NOTE: You can replace the yaml with the mutable_cfg searched by yourself + fix_subnet= # noqa: E251 + 'https://download.openmmlab.com/mmrazor/v1/detnas/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco_bbox_backbone_flops-0.34M_mAP-37.5_20220715-61d2e900_subnet_cfg_v1.yaml' # noqa: E501 +) + +find_unused_parameters = False diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_supernet_8xb128_in1k.py b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_supernet_8xb128_in1k.py new file mode 100755 index 000000000..0e514e83f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_supernet_8xb128_in1k.py @@ -0,0 +1 @@ +_base_ = 'mmrazor::nas/mmcls/spos/shufflenet/spos_shufflenet_supernet_8xb128_in1k.py' # noqa: E501 diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/metafile.yml b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/metafile.yml new file mode 100755 index 000000000..6a9a7d880 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/metafile.yml @@ -0,0 +1,30 @@ +Collections: + - Name: DetNAS + Metadata: + Training Data: + - ImageNet-1k + - COCO + Paper: + URL: https://arxiv.org/abs/1903.10979 + Title: DetNAS:Backbone Search for Object Detection + README: configs/nas/mmdet/detnas/README.md + Code: + URL: https://github.com/open-mmlab/mmrazor/blob/v0.1.0/mmrazor/models/algorithms/detnas.py + Version: v0.1.0 + Converted From: + Code: https://github.com/megvii-model/DetNAS +Models: + - Name: detnas_frcnn_shufflenet_subnet_coco_1x + In Collection: DetNAS + Metadata: + FLOPs(Backbone): 340 MB + Params(Backbone): 3.35 MB + Supernet: FRCNN-ShuffleNetV2 + Mutable: https://download.openmmlab.com/mmrazor/v1/detnas/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco_bbox_backbone_flops-0.34M_mAP-37.5_20220715-61d2e900_subnet_cfg_v1.yaml + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 37.5 + Config: configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_subnet_coco_1x.py + Weights: https://download.openmmlab.com/mmrazor/v1/detnas/detnas_subnet_frcnn_shufflenetv2_fpn_1x_coco_bbox_backbone_flops-0.34M_mAP-37.5_20220715-61d2e900_v1.pth diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/README.md b/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/README.md new file mode 100755 index 000000000..e294bee85 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/README.md @@ -0,0 +1,246 @@ +# Group_fisher pruning + +> [Group Fisher Pruning for Practical Network Compression.](https://arxiv.org/pdf/2108.00708.pdf) + +## Abstract + +Network compression has been widely studied since it is able to reduce the memory and computation cost during inference. However, previous methods seldom deal with complicated structures like residual connections, group/depthwise convolution and feature pyramid network, where channels of multiple layers are coupled and need to be pruned simultaneously. In this paper, we present a general channel pruning approach that can be applied to various complicated structures. Particularly, we propose a layer grouping algorithm to find coupled channels automatically. Then we derive a unified metric based on Fisher information to evaluate the importance of a single channel and coupled channels. Moreover, we find that inference speedup on GPUs is more correlated with the reduction of memory rather than FLOPs, and thus we employ the memory reduction of each channel to normalize the importance. Our method can be used to prune any structures including those with coupled channels. We conduct extensive experiments on various backbones, including the classic ResNet and ResNeXt, mobilefriendly MobileNetV2, and the NAS-based RegNet, both on image classification and object detection which is under-explored. Experimental results validate that our method can effectively prune sophisticated networks, boosting inference speed without sacrificing accuracy. + +![pipeline](https://github.com/jshilong/FisherPruning/blob/main/resources/structures.png?raw=true) + +## Results and models + +### Classification on ImageNet + +| Model | Top-1 | Gap | Flop(G) | Remain(%) | Parameters(M) | Remain(%) | Config | Download | Onnx_cpu(FPS) | +| ----------------------------- | ----- | ----- | ------- | --------- | ------------- | --------- | ---------------------------------------- | ----------------------------------------------------------- | ------------- | +| ResNet50 | 76.55 | - | 4.11 | - | 25.6 | - | [mmcls][cls_r50_c] | [model][cls_r50_m] | 55.360 | +| ResNet50_pruned_act | 75.22 | -1.33 | 2.06 | 50.1% | 16.3 | 63.7% | [prune][r_a_pc] \| [finetune][r_a_fc] | [pruned][r_a_p] \| [finetuned][r_a_f] \| [log][r_a_l] | 80.671 | +| ResNet50_pruned_act + dist kd | 76.50 | -0.05 | 2.06 | 50.1% | 16.3 | 63.7% | [prune][r_a_pc] \| [finetune][r_a_fc_kd] | [pruned][r_a_p] \| [finetuned][r_a_f_kd] \| [log][r_a_l_kd] | 80.671 | +| ResNet50_pruned_flops | 75.61 | -0.94 | 2.06 | 50.1% | 16.3 | 63.7% | [prune][r_f_pc] \| [finetune][r_f_fc] | [pruned][r_f_p] \| [finetuned][r_f_f] \| [log][r_f_l] | 78.674 | +| MobileNetV2 | 71.86 | - | 0.313 | - | 3.51 | - | [mmcls][cls_m_c] | [model][cls_m_m] | 419.673 | +| MobileNetV2_pruned_act | 70.82 | -1.04 | 0.207 | 66.1% | 3.18 | 90.6% | [prune][m_a_pc] \| [finetune][m_a_fc] | [pruned][m_a_p] \| [finetuned][m_a_f] \| [log][m_a_l] | 576.118 | +| MobileNetV2_pruned_flops | 70.87 | -0.99 | 0.207 | 66.1% | 2.82 | 88.7% | [prune][m_f_pc] \| [finetune][m_f_fc] | [pruned][m_f_p] \| [finetuned][m_f_f] \| [log][m_f_l] | 540.105 | + +**Note** + +- Because the pruning papers use different pretraining and finetuning settings, It is hard to compare them fairly. As a result, we prefer to apply algorithms on the openmmlab settings. +- This may make the experiment results are different from that in the original papers. + +### Detection on COCO + +| Model(Detector-Backbone) | AP | Gap | Flop(G) | Remain(%) | Parameters(M) | Remain(%) | Config | Download | Onnx_cpu(FPS) | +| ------------------------------ | ---- | ---- | ------- | --------- | ------------- | --------- | --------------------------------------- | -------------------------------------------------------- | ------------- | +| RetinaNet-R50-FPN | 36.5 | - | 250 | - | 63.8 | - | [mmdet][det_rt_c] | [model][det_rt_m] | 1.095 | +| RetinaNet-R50-FPN_pruned_act | 36.5 | 0.0 | 126 | 50.4% | 34.6 | 54.2% | [prune][rt_a_pc] \| [finetune][rt_a_fc] | [pruned][rt_a_p] \| [finetuned][rt_a_f] \| [log][rt_a_l] | 1.608 | +| RetinaNet-R50-FPN_pruned_flops | 36.6 | +0.1 | 126 | 50.4% | 34.9 | 54.7% | [prune][rt_f_pc] \| [finetune][rt_f_fc] | [pruned][rt_f_p] \| [finetuned][rt_f_f] \| [log][rt_f_l] | 1.609 | + +### Pose on COCO + +| Model | AP | Gap | Flop(G) | Remain(%) | Parameters(M) | Remain(%) | Config | Download | Onnx_cpu(FPS) | +| -------------------- | ----- | ------ | ------- | --------- | ------------- | --------- | --------------------------------------- | ----------------------------------------------------------- | ------------- | +| rtmpose-s | 0.716 | - | 0.68 | - | 5.47 | - | [mmpose][pose_s_c] | [model][pose_s_m] | 196 | +| rtmpose-s_pruned_act | 0.691 | -0.025 | 0.34 | 50.0% | 3.42 | 62.5% | [prune][rp_a_pc] \| [finetune][rp_a_fc] | [pruned][rp_sc_p] \| [finetuned][rp_sc_f] \| [log][rp_sc_l] | 268 | +| rtmpose-t | 0.682 | - | 0.35 | - | 3.34 | - | [mmpose][pose_t_c] | [model][pose_t_m] | 279 | + +| Model | AP | Gap | Flop(G) | Remain(%) | Parameters(M) | Remain(%) | Config | Download | Onnx_cpu(FPS) | +| ----------------------------- | ----- | ------ | ------- | --------- | ------------- | --------- | --------------------------------------- | ----------------------------------------------------------- | ------------- | +| rtmpose-s-aic-coco | 0.722 | - | 0.68 | - | 5.47 | - | [mmpose][pose_s_c] | [model][pose_s_m] | 196 | +| rtmpose-s-aic-coco_pruned_act | 0.694 | -0.028 | 0.35 | 51.5% | 3.43 | 62.7% | [prune][rp_a_pc] \| [finetune][rp_a_fc] | [pruned][rp_sa_p] \| [finetuned][rp_sa_f] \| [log][rp_sa_l] | 272 | +| rtmpose-t-aic-coco | 0.685 | - | 0.35 | - | 3.34 | - | [mmpose][pose_t_c] | [model][pose_t_m] | 279 | + +- All FPS is test on the same machine with 11th Gen Intel(R) Core(TM) i7-11700 @ 2.50GHz. + +## Get Started + +We have three steps to apply GroupFisher to your model, including Prune, Finetune, Deploy. + +Note: please use torch>=1.12, as we need fxtracer to parse the models automatically. + +### Prune + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 PORT=29500 ./tools/dist_train.sh \ + {config_folder}/group_fisher_{normalization_type}_prune_{model_name}.py 8 \ + --work-dir $WORK_DIR +``` + +In the pruning config file. You have to fill some args as below. + +```python +""" +_base_ (str): The path to your pretrained model checkpoint. +pretrained_path (str): The path to your pretrained model checkpoint. + +interval (int): Interval between pruning two channels. You should ensure you + can reach your target pruning ratio when the training ends. +normalization_type (str): GroupFisher uses two methods to normlized the channel + importance, including ['flops','act']. The former uses flops, while the + latter uses the memory occupation of activation feature maps. +lr_ratio (float): Ratio to decrease lr rate. As pruning progress is unstable, + you need to decrease the original lr rate until the pruning training work + steadly without getting nan. + +target_flop_ratio (float): The target flop ratio to prune your model. +input_shape (Tuple): input shape to measure the flops. +""" +``` + +After the pruning process, you will get a checkpoint of the pruned model named flops\_{target_flop_ratio}.pth in your workdir. + +### Finetune + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 PORT=29500 ./tools/dist_train.sh \ + {config_folder}/group_fisher_{normalization_type}_finetune_{model_name}.py 8 \ + --work-dir $WORK_DIR +``` + +There are also some args for you to fill in the config file as below. + +```python +""" +_base_(str): The path to your pruning config file. +pruned_path (str): The path to the checkpoint of the pruned model. +finetune_lr (float): The lr rate to finetune. Usually, we directly use the lr + rate of the pretrain. +""" +``` + +After finetuning, except a checkpoint of the best model, there is also a fix_subnet.json, which records the pruned model structure. It will be used when deploying. + +### Test + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 PORT=29500 ./tools/dist_test.sh \ + {config_folder}/group_fisher_{normalization_type}_finetune_{model_name}.py {checkpoint_path} 8 +``` + +### Deploy + +First, we assume you are fimilar to mmdeploy. For a pruned model, you only need to use the pruning deploy config to instead the pretrain config to deploy the pruned version of your model. + +```bash +python {mmdeploy}/tools/deploy.py \ + {mmdeploy}/{mmdeploy_config}.py \ + {config_folder}/group_fisher_{normalization_type}_deploy_{model_name}.py \ + {path_to_finetuned_checkpoint}.pth \ + {mmdeploy}/tests/data/tiger.jpeg +``` + +The deploy config has some args as below: + +```python +""" +_base_ (str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" +``` + +The divisor is important for the actual inference speed, and we suggest you to test it in \[1,2,4,8,16,32\] to find the fastest divisor. + +## Implementation + +All the modules of GroupFisher is placesded in mmrazor/implementations/pruning/group_fisher/. + +| File | Module | Feature | +| -------------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| algorithm.py | GroupFisherAlgorithm | Dicide when to prune a channel according to the interval and the current iteration. | +| mutator.py | GroupFisherChannelMutator | Select the unit with the channel of the minimal importance and to prune it. | +| unit.py | GroupFisherChannelUnit | Compute fisher info | +| ops.py
    counters | GroupFisherConv2d
    GroupFisherLinear
    corresbonding counters | Collect model info to compute fisher info, including activation, grad and tensor shape. | + +There are also some modules to support GroupFisher. These modules may be refactored and moved to other folders as common modules for all pruning algorithms. + +| File | Module | Feature | +| ------------------------- | ---------------------------------------- | ------------------------------------------------------------------- | +| hook.py | PruningStructureHook
    ResourceInfoHook | Display pruning Structure iteratively. | +| prune_sub_model.py | GroupFisherSubModel | Convert a pruning algorithm(architecture) to a pruned static model. | +| prune_deploy_sub_model.py | GroupFisherDeploySubModel | Init a pruned static model for mmdeploy. | + +## Citation + +```latex +@InProceedings{Liu:2021, + TITLE = {Group Fisher Pruning for Practical Network Compression}, + AUTHOR = {Liu, Liyang + AND Zhang, Shilong + AND Kuang, Zhanghui + AND Zhou, Aojun + AND Xue, Jing-hao + AND Wang, Xinjiang + AND Chen, Yimin + AND Yang, Wenming + AND Liao, Qingmin + AND Zhang, Wayne}, + BOOKTITLE = {Proceedings of the 38th International Conference on Machine Learning}, + YEAR = {2021}, + SERIES = {Proceedings of Machine Learning Research}, + MONTH = {18--24 Jul}, + PUBLISHER = {PMLR}, +} +``` + + + +[cls_m_c]: https://github.com/open-mmlab/mmclassification/blob/dev-1.x/configs/mobilenet_v2/mobilenet-v2_8xb32_in1k.py +[cls_m_m]: https://download.openmmlab.com/mmclassification/v0/mobilenet_v2/mobilenet_v2_batch256_imagenet_20200708-3b2dc3af.pth +[cls_r50_c]: https://github.com/open-mmlab/mmclassification/blob/dev-1.x/configs/resnet/resnet50_8xb32_in1k.py +[cls_r50_m]: https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth +[det_rt_c]: https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/retinanet/retinanet_r50_fpn_1x_coco.py +[det_rt_m]: https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_1x_coco/retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth +[m_a_f]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/mobilenet/act/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.pth +[m_a_fc]: ../../mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py +[m_a_l]: https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/group_fisher/mobilenet/act/20230130_203443.json +[m_a_p]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/mobilenet/act/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.pth +[m_a_pc]: ../../mmcls/group_fisher/mobilenet/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py +[m_f_f]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/mobilenet/flop/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.pth +[m_f_fc]: ../../mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py +[m_f_l]: https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/group_fisher/mobilenet/flop/20230201_211550.json +[m_f_p]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/mobilenet/flop/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.pth +[m_f_pc]: ../../mmcls/group_fisher/mobilenet/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py +[pose_s_c]: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.pth +[pose_s_m]: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.pth +[pose_t_c]: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.pth +[pose_t_m]: https://download.openmmlab.com/mmclassification/v0/mobilenet_v2/mobilenet_v2_batch256_imagenet_20200708-3b2dc3af.pth +[rp_a_fc]: ../../mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.py +[rp_a_pc]: ../../mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.py +[rp_sa_f]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.pth +[rp_sa_l]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.json +[rp_sa_p]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.pth +[rp_sc_f]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.pth +[rp_sc_l]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.json +[rp_sc_p]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.pth +[rt_a_f]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/retinanet/act/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.pth +[rt_a_fc]: ../../mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py +[rt_a_l]: https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/group_fisher/retinanet/act/20230113_231904.json +[rt_a_p]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/retinanet/act/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.pth +[rt_a_pc]: ../../mmdet/group_fisher/retinanet/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py +[rt_f_f]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/retinanet/flops/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.pth +[rt_f_fc]: ../../mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py +[rt_f_l]: https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/group_fisher/retinanet/flops/20230129_101502.json +[rt_f_p]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/retinanet/flops/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.pth +[rt_f_pc]: ../../mmdet/group_fisher/retinanet/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py +[r_a_f]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/act/group_fisher_act_finetune_resnet50_8xb32_in1k.pth +[r_a_fc]: ../../mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py +[r_a_fc_kd]: ../../mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.py +[r_a_f_kd]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.pth +[r_a_l]: https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/group_fisher/resnet50/act/20230130_175426.json +[r_a_l_kd]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.json +[r_a_p]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/act/group_fisher_act_prune_resnet50_8xb32_in1k.pth +[r_a_pc]: ../../mmcls/group_fisher/resnet50/group_fisher_act_prune_resnet50_8xb32_in1k.py +[r_f_f]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/flops/group_fisher_flops_finetune_resnet50_8xb32_in1k.pth +[r_f_fc]: ../../mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py +[r_f_l]: https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/group_fisher/resnet50/flops/20230129_190931.json +[r_f_p]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/flops/group_fisher_flops_prune_resnet50_8xb32_in1k.pth +[r_f_pc]: ../../mmcls/group_fisher/resnet50/group_fisher_flops_prune_resnet50_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_deploy_template.py b/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_deploy_template.py new file mode 100755 index 000000000..996444837 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_deploy_template.py @@ -0,0 +1,24 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = '' +fix_subnet = {} +divisor = 8 +############################################################################## + +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_finetune_template.py b/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_finetune_template.py new file mode 100755 index 000000000..bee977d93 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_finetune_template.py @@ -0,0 +1,32 @@ +############################################################################# +"""# You have to fill these args. + +_base_(str): The path to your pruning config file. +pruned_path (str): The path to the checkpoint of the pruned model. +finetune_lr (float): The lr rate to finetune. Usually, we directly use the lr + rate of the pretrain. +""" + +_base_ = '' +pruned_path = '' +finetune_lr = 0.1 +############################################################################## + +algorithm = _base_.model +algorithm.init_cfg = dict(type='Pretrained', checkpoint=pruned_path) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherSubModel', + algorithm=algorithm, +) + +# restore lr +optim_wrapper = dict(optimizer=dict(lr=finetune_lr)) + +# remove pruning related hooks +custom_hooks = _base_.custom_hooks[:-2] + +# delete ddp +model_wrapper_cfg = None diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_prune_template.py b/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_prune_template.py new file mode 100755 index 000000000..74d485e1f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_prune_template.py @@ -0,0 +1,75 @@ +############################################################################# +"""You have to fill these args. + +_base_ (str): The path to your pretrained model checkpoint. +pretrained_path (str): The path to your pretrained model checkpoint. + +interval (int): Interval between pruning two channels. You should ensure you + can reach your target pruning ratio when the training ends. +normalization_type (str): GroupFisher uses two methods to normlized the channel + importance, including ['flops','act']. The former uses flops, while the + latter uses the memory occupation of activation feature maps. +lr_ratio (float): Ratio to decrease lr rate. As pruning progress is unstable, + you need to decrease the original lr rate until the pruning training work + steadly without getting nan. + +target_flop_ratio (float): The target flop ratio to prune your model. +input_shape (Tuple): input shape to measure the flops. +""" + +_base_ = '' +pretrained_path = '' + +interval = 10 +normalization_type = 'act' +lr_ratio = 0.1 + +target_flop_ratio = 0.5 +input_shape = (1, 3, 224, 224) +############################################################################## + +architecture = _base_.model + +if hasattr(_base_, 'data_preprocessor'): + architecture.update({'data_preprocessor': _base_.data_preprocessor}) + data_preprocessor = {} + +architecture.init_cfg = dict(type='Pretrained', checkpoint=pretrained_path) +architecture['_scope_'] = _base_.default_scope + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherAlgorithm', + architecture=architecture, + interval=interval, + mutator=dict( + type='GroupFisherChannelMutator', + parse_cfg=dict(type='ChannelAnalyzer', tracer_type='FxTracer'), + channel_unit_cfg=dict( + type='GroupFisherChannelUnit', + default_args=dict(normalization_type=normalization_type, ), + ), + ), +) + +model_wrapper_cfg = dict( + type='mmrazor.GroupFisherDDP', + broadcast_buffers=False, +) + +optim_wrapper = dict( + optimizer=dict(lr=_base_.optim_wrapper.optimizer.lr * lr_ratio)) + +custom_hooks = getattr(_base_, 'custom_hooks', []) + [ + dict(type='mmrazor.PruningStructureHook'), + dict( + type='mmrazor.ResourceInfoHook', + interval=interval, + demo_input=dict( + type='mmrazor.DefaultDemoInput', + input_shape=input_shape, + ), + save_ckpt_thr=[target_flop_ratio], + ), +] diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/README.md b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/README.md new file mode 100755 index 000000000..ba5692d61 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/README.md @@ -0,0 +1,82 @@ +# Training Compact CNNs for Image Classification using Dynamic-coded Filter Fusion + +## Abstract + +The mainstream approach for filter pruning is usually either to force a hard-coded importance estimation upon a computation-heavy pretrained model to select “important†filters, or to impose a hyperparameter-sensitive sparse constraint on the loss objective to regularize the network training. In this paper, we present a novel filter pruning method, dubbed dynamic-coded filter fusion (DCFF), to derive compact CNNs in a computationeconomical and regularization-free manner for efficient image classification. Each filter in our DCFF is firstly given an intersimilarity distribution with a temperature parameter as a filter proxy, on top of which, a fresh Kullback-Leibler divergence based dynamic-coded criterion is proposed to evaluate the filter importance. In contrast to simply keeping high-score filters in other methods, we propose the concept of filter fusion, i.e., the weighted averages using the assigned proxies, as our preserved filters. We obtain a one-hot inter-similarity distribution as the temperature parameter approaches infinity. Thus, the relative importance of each filter can vary along with the training of the compact CNN, leading to dynamically changeable fused filters without both the dependency on the pretrained model and the introduction of sparse constraints. Extensive experiments on classification benchmarks demonstrate the superiority of our DCFF over the compared counterparts. For example, our DCFF derives a compact VGGNet-16 with only 72.77M FLOPs and 1.06M parameters while reaching top-1 accuracy of 93.47% on CIFAR-10. A compact ResNet-50 is obtained with 63.8% FLOPs and 58.6% parameter reductions, retaining 75.60% top1 accuracy on ILSVRC-2012. + +![pipeline](https://user-images.githubusercontent.com/31244134/189286581-722853ba-c6d7-4a39-b902-37995b444c71.jpg) + +## Results and models + +### 1. Classification + +| Dataset | Backbone | Params(M) | FLOPs(M) | lr_type | Top-1 (%) | Top-5 (%) | CPrate | Config | Download | +| :------: | :----------: | :-------: | :------: | :-----: | :-------: | :-------: | :---------------------------------------------: | :--------------------------------------------------: | :--------------------------: | +| ImageNet | DCFFResNet50 | 15.16 | 2260 | step | 73.96 | 91.66 | \[0.0\]+\[0.35,0.4,0.1\]\*10+\[0.3,0.3,0.1\]\*6 | [config](../../mmcls/dcff/dcff_resnet_8xb32_in1k.py) | [model](<>) \| \[log\] (\<>) | + +### 2. Detection + +| Dataset | Method | Backbone | Style | Lr schd | Params(M) | FLOPs(M) | bbox AP | CPrate | Config | Download | +| :-----: | :---------: | :----------: | :-----: | :-----: | :-------: | :------: | :-----: | :---------------------------------------------: | :---------------------------------------------------------------: | :--------------------------: | +| COCO | Faster_RCNN | DCFFResNet50 | pytorch | step | 33.31 | 168320 | 35.8 | \[0.0\]+\[0.35,0.4,0.1\]\*10+\[0.3,0.3,0.1\]\*6 | [config](../../mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py) | [model](<>) \| \[log\] (\<>) | + +### 3. Segmentation + +| Dataset | Method | Backbone | crop size | Lr schd | Params(M) | FLOPs(M) | mIoU | CPrate | Config | Download | +| :--------: | :-------: | :-------------: | :-------: | :-----: | :-------: | :------: | :---: | :-----------------------------------------------------------------: | :-------------------------------------------------------------------: | :--------------------------: | +| Cityscapes | PointRend | DCFFResNetV1c50 | 512x1024 | 160k | 18.43 | 74410 | 76.75 | \[0.0, 0.0, 0.0\] + \[0.35, 0.4, 0.1\] * 10 + \[0.3, 0.3, 0.1\] * 6 | [config](../../mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py) | [model](<>) \| \[log\] (\<>) | + +### 4. Pose + +| Dataset | Method | Backbone | crop size | total epochs | Params(M) | FLOPs(M) | AP | CPrate | Config | Download | +| :-----: | :-------------: | :----------: | :-------: | :----------: | :-------: | :------: | :--: | :--------------------------------------------------------: | :---------------------------------------------------------------: | :--------------------------: | +| COCO | TopDown HeatMap | DCFFResNet50 | 256x192 | 300 | 26.95 | 4290 | 68.3 | \[0.0\] + \[0.2, 0.2, 0.1\] * 10 + \[0.15, 0.15, 0.1\] * 6 | [config](../../mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py) | [model](<>) \| \[log\] (\<>) | + +## Citation + +```latex +@article{lin2021training, + title={Training Compact CNNs for Image Classification using Dynamic-coded Filter Fusion}, + author={Lin, Mingbao and Ji, Rongrong and Chen, Bohong and Chao, Fei and Liu, Jianzhuang and Zeng, Wei and Tian, Yonghong and Tian, Qi}, + journal={arXiv preprint arXiv:2107.06916}, + year={2021} +} +``` + +## Get Started + +### Generate channel_config file + +Generate `resnet_cls.json` with `tools/pruning/get_channel_units.py`. + +```bash +python tools/pruning/get_channel_units.py + configs/pruning/mmcls/dcff/dcff_resnet50_8xb32_in1k.py \ + -c -i --output-path=configs/pruning/mmcls/dcff/resnet_cls.json +``` + +Then set layers' pruning rates `target_pruning_ratio` by `resnet_cls.json`. + +### Train DCFF + +#### Classification + +##### ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/pruning/mmcls/dcff/dcff_resnet50_8xb32_in1k.py 4 \ + --work-dir $WORK_DIR +``` + +### Test DCFF + +#### Classification + +##### ImageNet + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_test.sh \ + configs/pruning/mmcls/dcff/dcff_compact_resnet50_8xb32_in1k.py \ + $CKPT 1 --work-dir $WORK_DIR +``` diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_compact_resnet_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_compact_resnet_8xb32_in1k.py new file mode 100755 index 000000000..4a98b2584 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_compact_resnet_8xb32_in1k.py @@ -0,0 +1,13 @@ +_base_ = ['dcff_resnet_8xb32_in1k.py'] + +# model settings +_base_.model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=dict( + cfg_path='mmcls::resnet/resnet50_8xb32_in1k.py', pretrained=False), + fix_subnet='configs/pruning/mmcls/dcff/fix_subnet.json', + mode='mutator', + init_cfg=dict( + type='Pretrained', + checkpoint='configs/pruning/mmcls/dcff/fix_subnet_weight.pth')) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_resnet_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_resnet_8xb32_in1k.py new file mode 100755 index 000000000..f833cb562 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_resnet_8xb32_in1k.py @@ -0,0 +1,84 @@ +_base_ = [ + 'mmcls::_base_/datasets/imagenet_bs32.py', + 'mmcls::_base_/schedules/imagenet_bs256.py', + 'mmcls::_base_/default_runtime.py' +] + +stage_ratio_1 = 0.65 +stage_ratio_2 = 0.6 +stage_ratio_3 = 0.9 +stage_ratio_4 = 0.7 + +# the config template of target_pruning_ratio can be got by +# python ./tools/pruning/get_channel_units.py {config_file} --choice +target_pruning_ratio = { + 'backbone.layer1.0.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.0.conv2_(0, 64)_64': stage_ratio_2, + 'backbone.layer1.0.conv3_(0, 256)_256': stage_ratio_3, + 'backbone.layer1.1.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.1.conv2_(0, 64)_64': stage_ratio_2, + 'backbone.layer1.2.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.2.conv2_(0, 64)_64': stage_ratio_2, + # block 1 [0.65, 0.6] downsample=[0.9] + 'backbone.layer2.0.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.0.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.0.conv3_(0, 512)_512': stage_ratio_3, + 'backbone.layer2.1.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.1.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.2.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.2.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.3.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.3.conv2_(0, 128)_128': stage_ratio_2, + # block 2 [0.65, 0.6] downsample=[0.9] + 'backbone.layer3.0.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.0.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.0.conv3_(0, 1024)_1024': stage_ratio_3, + 'backbone.layer3.1.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.1.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.2.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.2.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.3.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.3.conv2_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.4.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.4.conv2_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.5.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.5.conv2_(0, 256)_256': stage_ratio_4, + # block 3 [0.65, 0.6]*2+[0.7, 0.7]*2 downsample=[0.9] + 'backbone.layer4.0.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv2_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv3_(0, 2048)_2048': stage_ratio_3, + 'backbone.layer4.1.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.1.conv2_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv2_(0, 512)_512': stage_ratio_4 + # block 4 [0.7, 0.7] downsample=[0.9] +} + +optim_wrapper = dict( + optimizer=dict(type='SGD', lr=0.1, momentum=0.9, weight_decay=0.0001)) +param_scheduler = dict( + type='MultiStepLR', by_epoch=True, milestones=[30, 60, 90], gamma=0.1) +train_cfg = dict(by_epoch=True, max_epochs=120, val_interval=1) + +data_preprocessor = {'type': 'mmcls.ClsDataPreprocessor'} + +# model settings +model = dict( + _scope_='mmrazor', + type='DCFF', + architecture=dict( + cfg_path='mmcls::resnet/resnet50_8xb32_in1k.py', pretrained=False), + mutator_cfg=dict( + type='DCFFChannelMutator', + channel_unit_cfg=dict( + type='DCFFChannelUnit', default_args=dict(choice_mode='ratio')), + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer')), + data_preprocessor=None, + target_pruning_ratio=target_pruning_ratio, + step_freq=1, + linear_schedule=False) + +val_cfg = dict(_delete_=True, type='mmrazor.ItePruneValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/fix_subnet.json b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/fix_subnet.json new file mode 100755 index 000000000..dfdcea758 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/fix_subnet.json @@ -0,0 +1,141 @@ +{ + "type":"DCFFChannelMutator", + "channel_unit_cfg":{ + "type":"DCFFChannelUnit", + "default_args":{ + "choice_mode":"ratio" + }, + "units":{ + "backbone.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":1.0 + }, + "backbone.layer1.0.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.640625 + }, + "backbone.layer1.1.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.640625 + }, + "backbone.layer2.0.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer2.0.conv2_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.59375 + }, + "backbone.layer2.1.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer3.0.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer3.0.conv2_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.59765625 + }, + "backbone.layer3.1.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer4.0.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + }, + "backbone.layer4.0.conv2_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + }, + "backbone.layer4.1.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + } + } + }, + "parse_cfg":{ + "type":"ChannelAnalyzer", + "demo_input":[ + 1, + 3, + 224, + 224 + ], + "tracer_type":"BackwardTracer" + } +} diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_MBV2_100M.json b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_MBV2_100M.json new file mode 100755 index 000000000..d4ee2409f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_MBV2_100M.json @@ -0,0 +1,271 @@ +{ + "type":"DMCPChannelMutator", + "channel_unit_cfg":{ + "type":"DMCPChannelUnit", + "default_args":{ + "choice_mode":"number" + }, + "units":{ + "backbone.conv1.conv_(0, 32)_32":{ + "init_args":{ + "num_channels":32, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":9 + }, + "backbone.layer1.0.conv.1.conv_(0, 16)_16":{ + "init_args":{ + "num_channels":16, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":10 + }, + "backbone.layer2.0.conv.0.conv_(0, 96)_96":{ + "init_args":{ + "num_channels":96, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":36 + }, + "backbone.layer2.0.conv.2.conv_(0, 24)_24":{ + "init_args":{ + "num_channels":24, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":16 + }, + "backbone.layer2.1.conv.0.conv_(0, 144)_144":{ + "init_args":{ + "num_channels":144, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":16 + }, + "backbone.layer3.0.conv.0.conv_(0, 144)_144":{ + "init_args":{ + "num_channels":144, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":48 + }, + "backbone.layer3.0.conv.2.conv_(0, 32)_32":{ + "init_args":{ + "num_channels":32, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":21 + }, + "backbone.layer3.1.conv.0.conv_(0, 192)_192":{ + "init_args":{ + "num_channels":192, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":41 + }, + "backbone.layer3.2.conv.0.conv_(0, 192)_192":{ + "init_args":{ + "num_channels":192, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":22 + }, + "backbone.layer4.0.conv.0.conv_(0, 192)_192":{ + "init_args":{ + "num_channels":192, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":60 + }, + "backbone.layer4.0.conv.2.conv_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":24 + }, + "backbone.layer4.1.conv.0.conv_(0, 384)_384":{ + "init_args":{ + "num_channels":384, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":44 + }, + "backbone.layer4.2.conv.0.conv_(0, 384)_384":{ + "init_args":{ + "num_channels":384, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":272 + }, + "backbone.layer4.3.conv.0.conv_(0, 384)_384":{ + "init_args":{ + "num_channels":384, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":272 + }, + "backbone.layer5.0.conv.0.conv_(0, 384)_384":{ + "init_args":{ + "num_channels":384, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":310 + }, + "backbone.layer5.0.conv.2.conv_(0, 96)_96":{ + "init_args":{ + "num_channels":96, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":36 + }, + "backbone.layer5.1.conv.0.conv_(0, 576)_576":{ + "init_args":{ + "num_channels":576, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":294 + }, + "backbone.layer5.2.conv.0.conv_(0, 576)_576":{ + "init_args":{ + "num_channels":576, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":351 + }, + "backbone.layer6.0.conv.0.conv_(0, 576)_576":{ + "init_args":{ + "num_channels":576, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":693 + }, + "backbone.layer6.0.conv.2.conv_(0, 160)_160":{ + "init_args":{ + "num_channels":160, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":80 + }, + "backbone.layer6.1.conv.0.conv_(0, 960)_960":{ + "init_args":{ + "num_channels":960, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":96 + }, + "backbone.layer6.2.conv.0.conv_(0, 960)_960":{ + "init_args":{ + "num_channels":960, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":864 + }, + "backbone.layer7.0.conv.0.conv_(0, 960)_960":{ + "init_args":{ + "num_channels":960, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":960 + }, + "backbone.layer7.0.conv.2.conv_(0, 320)_320":{ + "init_args":{ + "num_channels":320, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":192 + }, + "backbone.conv2.conv_(0, 1280)_1280":{ + "init_args":{ + "num_channels":1280, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":1280 + } + } + }, + "parse_cfg":{ + "type":"ChannelAnalyzer", + "demo_input":[ + 1, + 3, + 224, + 224 + ], + "tracer_type":"BackwardTracer" + } +} diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_R50_2G.json b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_R50_2G.json new file mode 100755 index 000000000..833707cde --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_R50_2G.json @@ -0,0 +1,391 @@ +{ + "type":"DMCPChannelMutator", + "channel_unit_cfg":{ + "type":"DMCPChannelUnit", + "default_args":{ + "choice_mode":"number" + }, + "units":{ + "backbone.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":52 + }, + "backbone.layer1.0.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":22 + }, + "backbone.layer1.0.conv2_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":22 + }, + "backbone.layer1.0.conv3_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":106 + }, + "backbone.layer1.1.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":16 + }, + "backbone.layer1.1.conv2_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":16 + }, + "backbone.layer1.2.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":40 + }, + "backbone.layer1.2.conv2_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":16 + }, + "backbone.layer2.0.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":68 + }, + "backbone.layer2.0.conv2_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":56 + }, + "backbone.layer2.0.conv3_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":155 + }, + "backbone.layer2.1.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":32 + }, + "backbone.layer2.1.conv2_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":68 + }, + "backbone.layer2.2.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":56 + }, + "backbone.layer2.2.conv2_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":56 + }, + "backbone.layer2.3.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":80 + }, + "backbone.layer2.3.conv2_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":92 + }, + "backbone.layer3.0.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":256 + }, + "backbone.layer3.0.conv2_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":256 + }, + "backbone.layer3.0.conv3_(0, 1024)_1024":{ + "init_args":{ + "num_channels":1024, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":1024 + }, + "backbone.layer3.1.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":106 + }, + "backbone.layer3.1.conv2_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":106 + }, + "backbone.layer3.2.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":131 + }, + "backbone.layer3.2.conv2_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":256 + }, + "backbone.layer3.3.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":131 + }, + "backbone.layer3.3.conv2_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":256 + }, + "backbone.layer3.4.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":256 + }, + "backbone.layer3.4.conv2_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":256 + }, + "backbone.layer3.5.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":256 + }, + "backbone.layer3.5.conv2_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":256 + }, + "backbone.layer4.0.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":512 + }, + "backbone.layer4.0.conv2_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":512 + }, + "backbone.layer4.0.conv3_(0, 2048)_2048":{ + "init_args":{ + "num_channels":2048, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":2048 + }, + "backbone.layer4.1.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":512 + }, + "backbone.layer4.1.conv2_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":461 + }, + "backbone.layer4.2.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":512 + }, + "backbone.layer4.2.conv2_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"number", + "divisor":1, + "min_value":1, + "min_ratio":0.5 + }, + "choice":512 + } + } + }, + "parse_cfg":{ + "type":"ChannelAnalyzer", + "demo_input":[ + 1, + 3, + 224, + 224 + ], + "tracer_type":"BackwardTracer" + } +} diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/README.md b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/README.md new file mode 100755 index 000000000..3a96b61c3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/README.md @@ -0,0 +1,62 @@ +# DMCP: Differentiable Markov Channel Pruning for Neural Networks + +## Abstract + +Recent works imply that the channel pruning can be regarded as searching optimal sub-structure from unpruned networks. However, existing works based on this observation require training and evaluating a large number of structures, which limits their application. In this paper, we propose a novel differentiable method for channel pruning, named Differentiable Markov Channel Pruning (DMCP), to efficiently search the optimal sub-structure. Our method is differentiable and can be directly optimized by gradient descent with respect to standard task loss and budget regularization (e.g. FLOPs constraint). In DMCP, we model the channel pruning as a Markov process, in which each state represents for retaining the corresponding channel during pruning, and transitions between states denote the pruning process. In the end, our method is able to implicitly select the proper number of channels in each layer by the Markov process with optimized transitions. To validate the effectiveness of our method, we perform extensive experiments on Imagenet with ResNet and MobilenetV2. Results show our method can achieve consistent improvement than stateof-the-art pruning methods in various FLOPs settings. + +## Getting Started + +#### Train DMCP from scratch + +```bash +GPUS=32 sh tools/slurm_train.sh $PARTITION $JOB_NAME \ + configs/pruning/mmcls/dmcp/dmcp_resnet50_supernet_32xb64.py \ + --work-dir $WORK_DIR +``` + +#### After the previous steps, retrain the selected pruned sub-network + +#### with 2GFLOPs based on the output structure + +#### 'DMCP_R50_2G.json'(SOURCECODE) + +```bash +GPUS=32 sh tools/slurm_train.sh $PARTITION $JOB_NAME \ + configs/pruning/mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py \ + --work-dir $WORK_DIR +``` + + + + + + + + + +## Citation + +```latex +@inproceedings{guo2020dmcp, + title={Dmcp: Differentiable markov channel pruning for neural networks}, + author={Guo, Shaopeng and Wang, Yujie and Li, Quanquan and Yan, Junjie}, + booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, + pages={1539--1547}, + year={2020} +} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py new file mode 100755 index 000000000..81880f4eb --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py @@ -0,0 +1,49 @@ +_base_ = ['dmcp_mbv2_supernet_32xb64.py'] + +paramwise_cfg = dict(norm_decay_mult=0.0, bias_decay_mult=0.0) + +_base_.optim_wrapper = dict( + optimizer=dict( + type='SGD', lr=0.8, momentum=0.9, weight_decay=0.00004, nesterov=True), + paramwise_cfg=paramwise_cfg) + +max_epochs = 100 + +_base_.param_scheduler = [ + # warm up learning rate scheduler + dict( + type='LinearLR', + start_factor=0.25, + by_epoch=True, + begin=0, + end=3, + convert_to_iter_based=True), + # main learning rate scheduler + dict( + type='CosineAnnealingLR', + T_max=max_epochs, + eta_min=1e-5, + by_epoch=True, + begin=3, + end=max_epochs, + convert_to_iter_based=True), +] + +_base_.train_cfg = dict(by_epoch=True, max_epochs=max_epochs, val_interval=1) + +custom_hooks = None + +# model settings +model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.supernet, + fix_subnet='configs/pruning/mmcls/dmcp/DMCP_MBV2_100M.json', + mode='mutator') + +default_hooks = _base_.default_hooks +default_hooks['checkpoint'] = dict(type='CheckpointHook', interval=5) + +_base_.model_wrapper_cfg = None + +randomness = dict(seed=4872, diff_rank_seed=True) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_supernet_32xb64.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_supernet_32xb64.py new file mode 100755 index 000000000..4109964c4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_supernet_32xb64.py @@ -0,0 +1,61 @@ +_base_ = [ + 'mmcls::_base_/default_runtime.py', + '../../../_base_/settings/imagenet_bs2048_dmcp.py', +] + +# model settings +supernet = dict( + _scope_='mmcls', + type='ImageClassifier', + backbone=dict(type='MobileNetV2', widen_factor=1.0), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=1000, + in_channels=1280, + loss=dict( + type='mmcls.LabelSmoothLoss', + mode='original', + num_classes=1000, + label_smooth_val=0.1, + loss_weight=1.0), + topk=(1, 5), + )) + +model = dict( + _scope_='mmrazor', + type='DMCP', + architecture=supernet, + distiller=dict( + type='ConfigurableDistiller', + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=1)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(recorder='fc', from_student=True), + preds_T=dict(recorder='fc', from_student=False)))), + mutator_cfg=dict( + type='DMCPChannelMutator', + channel_unit_cfg=dict( + type='DMCPChannelUnit', default_args=dict(choice_mode='number')), + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer')), + strategy=['max', 'min', 'scheduled_random', 'arch_random'], + arch_start_train=5000, + arch_train_freq=500, + flop_loss_weight=0.1, + distillation_times=10000, + target_flops=100) + +model_wrapper_cfg = dict( + type='mmrazor.DMCPDDP', + broadcast_buffers=False, + find_unused_parameters=True) + +randomness = dict(seed=0, diff_rank_seed=True) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py new file mode 100755 index 000000000..c612e3aa5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py @@ -0,0 +1,48 @@ +_base_ = ['dmcp_resnet50_supernet_32xb64.py'] + +paramwise_cfg = dict(norm_decay_mult=0.0, bias_decay_mult=0.0) + +_base_.optim_wrapper = dict( + optimizer=dict( + type='SGD', lr=0.8, momentum=0.9, weight_decay=0.0001, nesterov=True), + paramwise_cfg=paramwise_cfg) + +max_epochs = 100 + +_base_.param_scheduler = [ + # warm up learning rate scheduler + dict( + type='LinearLR', + start_factor=0.25, + by_epoch=True, + begin=0, + end=2, + convert_to_iter_based=True), + # main learning rate scheduler + dict( + type='CosineAnnealingLR', + T_max=max_epochs, + eta_min=1e-5, + by_epoch=True, + begin=2, + end=max_epochs, + convert_to_iter_based=True), +] + +_base_.train_cfg = dict(by_epoch=True, max_epochs=max_epochs, val_interval=1) + +custom_hooks = None + +model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.supernet, + fix_subnet='configs/pruning/mmcls/dmcp/DMCP_R50_2G.json', + mode='mutator') + +default_hooks = _base_.default_hooks +default_hooks['checkpoint'] = dict(type='CheckpointHook', interval=5) + +_base_.model_wrapper_cfg = None + +randomness = dict(seed=2016, diff_rank_seed=True) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_supernet_32xb64.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_supernet_32xb64.py new file mode 100755 index 000000000..9aeaeb838 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_supernet_32xb64.py @@ -0,0 +1,67 @@ +_base_ = [ + 'mmcls::_base_/default_runtime.py', + '../../../_base_/settings/imagenet_bs2048_dmcp.py', +] + +# model settings +supernet = dict( + _scope_='mmcls', + type='ImageClassifier', + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(3, ), + style='pytorch'), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=1000, + in_channels=2048, + loss=dict( + type='mmcls.LabelSmoothLoss', + mode='original', + num_classes=1000, + label_smooth_val=0.1, + loss_weight=1.0), + topk=(1, 5), + )) + +# model settings +model = dict( + _scope_='mmrazor', + type='DMCP', + architecture=supernet, + distiller=dict( + type='ConfigurableDistiller', + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=1)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(recorder='fc', from_student=True), + preds_T=dict(recorder='fc', from_student=False)))), + mutator_cfg=dict( + type='DMCPChannelMutator', + channel_unit_cfg=dict( + type='DMCPChannelUnit', default_args=dict(choice_mode='number')), + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer')), + strategy=['max', 'min', 'scheduled_random', 'arch_random'], + arch_start_train=5000, + arch_train_freq=500, + flop_loss_weight=0.1, + distillation_times=10000, + target_flops=2000) + +model_wrapper_cfg = dict( + type='mmrazor.DMCPDDP', + broadcast_buffers=False, + find_unused_parameters=True) + +randomness = dict(seed=2020, diff_rank_seed=True) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/metafile.yml b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/metafile.yml new file mode 100755 index 000000000..131f5c289 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/metafile.yml @@ -0,0 +1,19 @@ +# Models: + # - Name: dmcp_resnet50_subnet_32xb64 + # In Collection: DMCP + # Config: configs/pruning/mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py + # Weights: https://download.openmmlab.com/mmrazor/v1/pruning/dmcp/resnet50/2G/DMCP_R50_2G.pth + # Results: + # - Task: Image Classification + # Dataset: ImageNet-1k + # Metrics: + # Top 1 Accuracy: 76.11 + # - Name: dmcp_mbv2_subnet_32xb64 + # In Collection: DMCP + # Config: configs/pruning/mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py + # Weights: https://download.openmmlab.com/mmrazor/v1/pruning/dmcp/mobilenetv2/100M/DMCP_MBV2_100M.pth + # Results: + # - Task: Image Classification + # Dataset: ImageNet-1k + # Metrics: + # Top 1 Accuracy: 67.22 diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/README.md b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/README.md new file mode 100755 index 000000000..9b3b09936 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/README.md @@ -0,0 +1,11 @@ +# Group_fisher pruning + +> [Group Fisher Pruning for Practical Network Compression.](https://arxiv.org/pdf/2108.00708.pdf) + +## Abstract + +Network compression has been widely studied since it is able to reduce the memory and computation cost during inference. However, previous methods seldom deal with complicated structures like residual connections, group/depthwise convolution and feature pyramid network, where channels of multiple layers are coupled and need to be pruned simultaneously. In this paper, we present a general channel pruning approach that can be applied to various complicated structures. Particularly, we propose a layer grouping algorithm to find coupled channels automatically. Then we derive a unified metric based on Fisher information to evaluate the importance of a single channel and coupled channels. Moreover, we find that inference speedup on GPUs is more correlated with the reduction of memory rather than FLOPs, and thus we employ the memory reduction of each channel to normalize the importance. Our method can be used to prune any structures including those with coupled channels. We conduct extensive experiments on various backbones, including the classic ResNet and ResNeXt, mobilefriendly MobileNetV2, and the NAS-based RegNet, both on image classification and object detection which is under-explored. Experimental results validate that our method can effectively prune sophisticated networks, boosting inference speed without sacrificing accuracy. + +![pipeline](https://github.com/jshilong/FisherPruning/blob/main/resources/structures.png?raw=true) + +**Please refer to the [full README](../../base/group_fisher/README.md) for more details.** diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_deploy_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_deploy_mobilenet-v2_8xb32_in1k.py new file mode 100755 index 000000000..372f6a464 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_deploy_mobilenet-v2_8xb32_in1k.py @@ -0,0 +1,50 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = 'mmcls::mobilenet_v2/mobilenet-v2_8xb32_in1k.py' +fix_subnet = { + 'backbone.conv1.conv_(0, 32)_32': 21, + 'backbone.layer1.0.conv.1.conv_(0, 16)_16': 10, + 'backbone.layer2.0.conv.0.conv_(0, 96)_96': 45, + 'backbone.layer2.0.conv.2.conv_(0, 24)_24': 24, + 'backbone.layer2.1.conv.0.conv_(0, 144)_144': 73, + 'backbone.layer3.0.conv.0.conv_(0, 144)_144': 85, + 'backbone.layer3.0.conv.2.conv_(0, 32)_32': 32, + 'backbone.layer3.1.conv.0.conv_(0, 192)_192': 95, + 'backbone.layer3.2.conv.0.conv_(0, 192)_192': 76, + 'backbone.layer4.0.conv.0.conv_(0, 192)_192': 160, + 'backbone.layer4.0.conv.2.conv_(0, 64)_64': 64, + 'backbone.layer4.1.conv.0.conv_(0, 384)_384': 204, + 'backbone.layer4.2.conv.0.conv_(0, 384)_384': 200, + 'backbone.layer4.3.conv.0.conv_(0, 384)_384': 217, + 'backbone.layer5.0.conv.0.conv_(0, 384)_384': 344, + 'backbone.layer5.0.conv.2.conv_(0, 96)_96': 96, + 'backbone.layer5.1.conv.0.conv_(0, 576)_576': 348, + 'backbone.layer5.2.conv.0.conv_(0, 576)_576': 338, + 'backbone.layer6.0.conv.0.conv_(0, 576)_576': 543, + 'backbone.layer6.0.conv.2.conv_(0, 160)_160': 160, + 'backbone.layer6.1.conv.0.conv_(0, 960)_960': 810, + 'backbone.layer6.2.conv.0.conv_(0, 960)_960': 803, + 'backbone.layer7.0.conv.0.conv_(0, 960)_960': 944, + 'backbone.layer7.0.conv.2.conv_(0, 320)_320': 320 +} +divisor = 16 + +############################################################################## + +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py new file mode 100755 index 000000000..151e06103 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py @@ -0,0 +1,31 @@ +############################################################################# +"""# You have to fill these args. + +_base_(str): The path to your pruning config file. +pruned_path (str): The path to the checkpoint of the pruned model. +finetune_lr (float): The lr rate to finetune. Usually, we directly use the lr + rate of the pretrain. +""" + +_base_ = './group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py' +pruned_path = 'https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/mobilenet/act/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.pth' # noqa +finetune_lr = 0.045 +############################################################################## +algorithm = _base_.model +algorithm.init_cfg = dict(type='Pretrained', checkpoint=pruned_path) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherSubModel', + algorithm=algorithm, +) + +# restore lr +optim_wrapper = dict(optimizer=dict(lr=finetune_lr)) + +# remove pruning related hooks +custom_hooks = _base_.custom_hooks[:-2] + +# delete ddp +model_wrapper_cfg = None diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py new file mode 100755 index 000000000..f8ff9e006 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py @@ -0,0 +1,75 @@ +############################################################################# +"""You have to fill these args. + +_base_ (str): The path to your pretrained model checkpoint. +pretrained_path (str): The path to your pretrained model checkpoint. + +interval (int): Interval between pruning two channels. You should ensure you + can reach your target pruning ratio when the training ends. +normalization_type (str): GroupFisher uses two methods to normlized the channel + importance, including ['flops','act']. The former uses flops, while the + latter uses the memory occupation of activation feature maps. +lr_ratio (float): Ratio to decrease lr rate. As pruning progress is unstable, + you need to decrease the original lr rate until the pruning training work + steadly without getting nan. + +target_flop_ratio (float): The target flop ratio to prune your model. +input_shape (Tuple): input shape to measure the flops. +""" + +_base_ = 'mmcls::mobilenet_v2/mobilenet-v2_8xb32_in1k.py' +pretrained_path = 'https://download.openmmlab.com/mmclassification/v0/mobilenet_v2/mobilenet_v2_batch256_imagenet_20200708-3b2dc3af.pth' # noqa + +interval = 25 +normalization_type = 'act' +lr_ratio = 0.1125 + +target_flop_ratio = 0.65 +input_shape = (1, 3, 224, 224) +############################################################################## + +architecture = _base_.model + +if hasattr(_base_, 'data_preprocessor'): + architecture.update({'data_preprocessor': _base_.data_preprocessor}) + data_preprocessor = {} + +architecture.init_cfg = dict(type='Pretrained', checkpoint=pretrained_path) +architecture['_scope_'] = _base_.default_scope + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherAlgorithm', + architecture=architecture, + interval=interval, + mutator=dict( + type='GroupFisherChannelMutator', + parse_cfg=dict(type='ChannelAnalyzer', tracer_type='FxTracer'), + channel_unit_cfg=dict( + type='GroupFisherChannelUnit', + default_args=dict(normalization_type=normalization_type, ), + ), + ), +) + +model_wrapper_cfg = dict( + type='mmrazor.GroupFisherDDP', + broadcast_buffers=False, +) + +optim_wrapper = dict( + optimizer=dict(lr=_base_.optim_wrapper.optimizer.lr * lr_ratio)) + +custom_hooks = getattr(_base_, 'custom_hooks', []) + [ + dict(type='mmrazor.PruningStructureHook'), + dict( + type='mmrazor.ResourceInfoHook', + interval=interval, + demo_input=dict( + type='mmrazor.DefaultDemoInput', + input_shape=input_shape, + ), + save_ckpt_thr=[target_flop_ratio], + ), +] diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_deploy_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_deploy_mobilenet-v2_8xb32_in1k.py new file mode 100755 index 000000000..89f7c08a3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_deploy_mobilenet-v2_8xb32_in1k.py @@ -0,0 +1,49 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = 'mmcls::mobilenet_v2/mobilenet-v2_8xb32_in1k.py' +fix_subnet = { + 'backbone.conv1.conv_(0, 32)_32': 27, + 'backbone.layer1.0.conv.1.conv_(0, 16)_16': 16, + 'backbone.layer2.0.conv.0.conv_(0, 96)_96': 77, + 'backbone.layer2.0.conv.2.conv_(0, 24)_24': 24, + 'backbone.layer2.1.conv.0.conv_(0, 144)_144': 85, + 'backbone.layer3.0.conv.0.conv_(0, 144)_144': 115, + 'backbone.layer3.0.conv.2.conv_(0, 32)_32': 32, + 'backbone.layer3.1.conv.0.conv_(0, 192)_192': 102, + 'backbone.layer3.2.conv.0.conv_(0, 192)_192': 95, + 'backbone.layer4.0.conv.0.conv_(0, 192)_192': 181, + 'backbone.layer4.0.conv.2.conv_(0, 64)_64': 64, + 'backbone.layer4.1.conv.0.conv_(0, 384)_384': 169, + 'backbone.layer4.2.conv.0.conv_(0, 384)_384': 176, + 'backbone.layer4.3.conv.0.conv_(0, 384)_384': 180, + 'backbone.layer5.0.conv.0.conv_(0, 384)_384': 308, + 'backbone.layer5.0.conv.2.conv_(0, 96)_96': 96, + 'backbone.layer5.1.conv.0.conv_(0, 576)_576': 223, + 'backbone.layer5.2.conv.0.conv_(0, 576)_576': 241, + 'backbone.layer6.0.conv.0.conv_(0, 576)_576': 511, + 'backbone.layer6.0.conv.2.conv_(0, 160)_160': 160, + 'backbone.layer6.1.conv.0.conv_(0, 960)_960': 467, + 'backbone.layer6.2.conv.0.conv_(0, 960)_960': 510, + 'backbone.layer7.0.conv.0.conv_(0, 960)_960': 771, + 'backbone.layer7.0.conv.2.conv_(0, 320)_320': 320 +} +divisor = 16 + +############################################################################## +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py new file mode 100755 index 000000000..18c9a99f1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py @@ -0,0 +1,32 @@ +############################################################################# +"""# You have to fill these args. + +_base_(str): The path to your pruning config file. +pruned_path (str): The path to the checkpoint of the pruned model. +finetune_lr (float): The lr rate to finetune. Usually, we directly use the lr + rate of the pretrain. +""" + +_base_ = './group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py' +pruned_path = 'https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/mobilenet/flop/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.pth' # noqa +finetune_lr = 0.045 +############################################################################## + +algorithm = _base_.model +algorithm.init_cfg = dict(type='Pretrained', checkpoint=pruned_path) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherSubModel', + algorithm=algorithm, +) + +# restore lr +optim_wrapper = dict(optimizer=dict(lr=finetune_lr)) + +# remove pruning related hooks +custom_hooks = _base_.custom_hooks[:-2] + +# delete ddp +model_wrapper_cfg = None diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py new file mode 100755 index 000000000..65a1fdd20 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py @@ -0,0 +1,5 @@ +_base_ = './group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py' +model = dict( + mutator=dict( + channel_unit_cfg=dict( + default_args=dict(normalization_type='flops', ), ), ), ) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/metafile.yml b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/metafile.yml new file mode 100755 index 000000000..24f41eaae --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/metafile.yml @@ -0,0 +1,19 @@ +Models: + - Name: group_fisher_act_finetune_mobilenet-v2_8xb32_in1k + In Collection: GroupFisher + Config: configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/mobilenet/act/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.pth + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 70.82 + - Name: group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k + In Collection: GroupFisher + Config: configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/mobilenet/flop/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.pth + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 70.87 diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/script.sh b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/script.sh new file mode 100755 index 000000000..5281e5ac8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/script.sh @@ -0,0 +1,47 @@ +# act mode +bash ./tools/dist_train.sh configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py 8 +bash ./tools/dist_train.sh configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py 8 + +# flops mode +bash ./tools/dist_train.sh configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py 8 +bash ./tools/dist_train.sh configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py 8 + + +# deploy act mode +razor_config=configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_deploy_mobilenet-v2_8xb32_in1k.py +deploy_config=mmdeploy/configs/mmcls/classification_onnxruntime_dynamic.py + +python mmdeploy/tools/deploy.py $deploy_config \ + $razor_config \ + https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/mobilenet/act/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.pth \ + mmdeploy/tests/data/tiger.jpeg \ + --work-dir ./work_dirs/mmdeploy + +python mmdeploy/tools/profiler.py $deploy_config \ + $razor_config \ + mmdeploy/demo/resources \ + --model ./work_dirs/mmdeploy/end2end.onnx \ + --shape 224x224 \ + --device cpu \ + --num-iter 1000 \ + --warmup 100 + +# deploy flop mode + +razor_config=configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_deploy_mobilenet-v2_8xb32_in1k.py +deploy_config=mmdeploy/configs/mmcls/classification_onnxruntime_dynamic.py + +python mmdeploy/tools/deploy.py $deploy_config \ + $razor_config \ + https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/mobilenet/flop/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.pth \ + mmdeploy/tests/data/tiger.jpeg \ + --work-dir ./work_dirs/mmdeploy + +python mmdeploy/tools/profiler.py $deploy_config \ + $razor_config \ + mmdeploy/demo/resources \ + --model ./work_dirs/mmdeploy/end2end.onnx \ + --shape 224x224 \ + --device cpu \ + --num-iter 1000 \ + --warmup 100 diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_deploy_resnet50_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_deploy_resnet50_8xb32_in1k.py new file mode 100755 index 000000000..8fcb4082a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_deploy_resnet50_8xb32_in1k.py @@ -0,0 +1,61 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = 'mmcls::resnet/resnet50_8xb32_in1k.py' +fix_subnet = { + 'backbone.conv1_(0, 64)_64': 61, + 'backbone.layer1.0.conv1_(0, 64)_64': 27, + 'backbone.layer1.0.conv2_(0, 64)_64': 35, + 'backbone.layer1.0.conv3_(0, 256)_256': 241, + 'backbone.layer1.1.conv1_(0, 64)_64': 32, + 'backbone.layer1.1.conv2_(0, 64)_64': 29, + 'backbone.layer1.2.conv1_(0, 64)_64': 27, + 'backbone.layer1.2.conv2_(0, 64)_64': 42, + 'backbone.layer2.0.conv1_(0, 128)_128': 87, + 'backbone.layer2.0.conv2_(0, 128)_128': 107, + 'backbone.layer2.0.conv3_(0, 512)_512': 512, + 'backbone.layer2.1.conv1_(0, 128)_128': 44, + 'backbone.layer2.1.conv2_(0, 128)_128': 50, + 'backbone.layer2.2.conv1_(0, 128)_128': 52, + 'backbone.layer2.2.conv2_(0, 128)_128': 81, + 'backbone.layer2.3.conv1_(0, 128)_128': 47, + 'backbone.layer2.3.conv2_(0, 128)_128': 50, + 'backbone.layer3.0.conv1_(0, 256)_256': 210, + 'backbone.layer3.0.conv2_(0, 256)_256': 206, + 'backbone.layer3.0.conv3_(0, 1024)_1024': 1024, + 'backbone.layer3.1.conv1_(0, 256)_256': 107, + 'backbone.layer3.1.conv2_(0, 256)_256': 108, + 'backbone.layer3.2.conv1_(0, 256)_256': 86, + 'backbone.layer3.2.conv2_(0, 256)_256': 126, + 'backbone.layer3.3.conv1_(0, 256)_256': 91, + 'backbone.layer3.3.conv2_(0, 256)_256': 112, + 'backbone.layer3.4.conv1_(0, 256)_256': 98, + 'backbone.layer3.4.conv2_(0, 256)_256': 110, + 'backbone.layer3.5.conv1_(0, 256)_256': 112, + 'backbone.layer3.5.conv2_(0, 256)_256': 115, + 'backbone.layer4.0.conv1_(0, 512)_512': 397, + 'backbone.layer4.0.conv2_(0, 512)_512': 427, + 'backbone.layer4.1.conv1_(0, 512)_512': 373, + 'backbone.layer4.1.conv2_(0, 512)_512': 348, + 'backbone.layer4.2.conv1_(0, 512)_512': 433, + 'backbone.layer4.2.conv2_(0, 512)_512': 384 +} +divisor = 8 +############################################################################## + +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py new file mode 100755 index 000000000..5d1f9380c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py @@ -0,0 +1,31 @@ +############################################################################# +"""# You have to fill these args. + +_base_(str): The path to your pruning config file. +pruned_path (str): The path to the checkpoint of the pruned model. +finetune_lr (float): The lr rate to finetune. Usually, we directly use the lr + rate of the pretrain. +""" + +_base_ = './group_fisher_act_prune_resnet50_8xb32_in1k.py' +pruned_path = 'https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/act/group_fisher_act_prune_resnet50_8xb32_in1k.pth' # noqa +finetune_lr = 0.1 +############################################################################## +algorithm = _base_.model +algorithm.init_cfg = dict(type='Pretrained', checkpoint=pruned_path) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherSubModel', + algorithm=algorithm, +) + +# restore lr +optim_wrapper = dict(optimizer=dict(lr=finetune_lr)) + +# remove pruning related hooks +custom_hooks = _base_.custom_hooks[:-2] + +# delete ddp +model_wrapper_cfg = None diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.py new file mode 100755 index 000000000..356c89937 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.py @@ -0,0 +1,61 @@ +############################################################################# +"""# You have to fill these args. + +_base_(str): The path to your pruning config file. +pruned_path (str): The path to the checkpoint of the pruned model. +finetune_lr (float): The lr rate to finetune. Usually, we directly use the lr + rate of the pretrain. +""" + +_base_ = './group_fisher_act_prune_resnet50_8xb32_in1k.py' +pruned_path = 'https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/act/group_fisher_act_prune_resnet50_8xb32_in1k.pth' # noqa +finetune_lr = 0.1 +############################################################################## + +algorithm = _base_.model +algorithm.init_cfg = dict(type='Pretrained', checkpoint=pruned_path) + +teacher = algorithm.architecture + +pruned = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherSubModel', + algorithm=algorithm, +) + +model = dict( + _scope_='mmrazor', + _delete_=True, + type='SingleTeacherDistill', + data_preprocessor=None, + architecture=pruned, + teacher=teacher, + distiller=dict( + type='ConfigurableDistiller', + student_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + teacher_recorders=dict( + fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='DISTLoss', tau=1, loss_weight=1)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(from_student=True, recorder='fc'), + preds_T=dict(from_student=False, recorder='fc'))))) + +find_unused_parameters = True +val_cfg = dict(_delete_=True, type='mmrazor.SingleTeacherDistillValLoop') + +# restore lr +optim_wrapper = dict(optimizer=dict(lr=finetune_lr)) + +# remove pruning related hooks +custom_hooks = _base_.custom_hooks[:-2] + +# delete ddp +model_wrapper_cfg = None + +_base_ = './resnet_group_fisher_prune.py' + +# 76.3520 diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_prune_resnet50_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_prune_resnet50_8xb32_in1k.py new file mode 100755 index 000000000..454c0cc8e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_prune_resnet50_8xb32_in1k.py @@ -0,0 +1,75 @@ +############################################################################# +"""You have to fill these args. + +_base_ (str): The path to your pretrained model checkpoint. +pretrained_path (str): The path to your pretrained model checkpoint. + +interval (int): Interval between pruning two channels. You should ensure you + can reach your target pruning ratio when the training ends. +normalization_type (str): GroupFisher uses two methods to normlized the channel + importance, including ['flops','act']. The former uses flops, while the + latter uses the memory occupation of activation feature maps. +lr_ratio (float): Ratio to decrease lr rate. As pruning progress is unstable, + you need to decrease the original lr rate until the pruning training work + steadly without getting nan. + +target_flop_ratio (float): The target flop ratio to prune your model. +input_shape (Tuple): input shape to measure the flops. +""" + +_base_ = 'mmcls::resnet/resnet50_8xb32_in1k.py' +pretrained_path = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth' # noqa + +interval = 25 +normalization_type = 'act' +lr_ratio = 0.04 + +target_flop_ratio = 0.5 +input_shape = [1, 3, 224, 224] +############################################################################## + +architecture = _base_.model + +if hasattr(_base_, 'data_preprocessor'): + architecture.update({'data_preprocessor': _base_.data_preprocessor}) + data_preprocessor = {} + +architecture.init_cfg = dict(type='Pretrained', checkpoint=pretrained_path) +architecture['_scope_'] = _base_.default_scope + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherAlgorithm', + architecture=architecture, + interval=interval, + mutator=dict( + type='GroupFisherChannelMutator', + parse_cfg=dict(type='ChannelAnalyzer', tracer_type='FxTracer'), + channel_unit_cfg=dict( + type='GroupFisherChannelUnit', + default_args=dict(normalization_type=normalization_type, ), + ), + ), +) + +model_wrapper_cfg = dict( + type='mmrazor.GroupFisherDDP', + broadcast_buffers=False, +) + +optim_wrapper = dict( + optimizer=dict(lr=_base_.optim_wrapper.optimizer.lr * lr_ratio)) + +custom_hooks = getattr(_base_, 'custom_hooks', []) + [ + dict(type='mmrazor.PruningStructureHook'), + dict( + type='mmrazor.ResourceInfoHook', + interval=interval, + demo_input=dict( + type='mmrazor.DefaultDemoInput', + input_shape=input_shape, + ), + save_ckpt_thr=[target_flop_ratio], + ), +] diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_deploy_resnet50_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_deploy_resnet50_8xb32_in1k.py new file mode 100755 index 000000000..7d28a0ab5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_deploy_resnet50_8xb32_in1k.py @@ -0,0 +1,61 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = 'mmcls::resnet/resnet50_8xb32_in1k.py' +fix_subnet = { + 'backbone.conv1_(0, 64)_64': 61, + 'backbone.layer1.0.conv1_(0, 64)_64': 28, + 'backbone.layer1.0.conv2_(0, 64)_64': 35, + 'backbone.layer1.0.conv3_(0, 256)_256': 242, + 'backbone.layer1.1.conv1_(0, 64)_64': 31, + 'backbone.layer1.1.conv2_(0, 64)_64': 28, + 'backbone.layer1.2.conv1_(0, 64)_64': 26, + 'backbone.layer1.2.conv2_(0, 64)_64': 41, + 'backbone.layer2.0.conv1_(0, 128)_128': 90, + 'backbone.layer2.0.conv2_(0, 128)_128': 107, + 'backbone.layer2.0.conv3_(0, 512)_512': 509, + 'backbone.layer2.1.conv1_(0, 128)_128': 42, + 'backbone.layer2.1.conv2_(0, 128)_128': 50, + 'backbone.layer2.2.conv1_(0, 128)_128': 51, + 'backbone.layer2.2.conv2_(0, 128)_128': 84, + 'backbone.layer2.3.conv1_(0, 128)_128': 49, + 'backbone.layer2.3.conv2_(0, 128)_128': 51, + 'backbone.layer3.0.conv1_(0, 256)_256': 210, + 'backbone.layer3.0.conv2_(0, 256)_256': 207, + 'backbone.layer3.0.conv3_(0, 1024)_1024': 1024, + 'backbone.layer3.1.conv1_(0, 256)_256': 103, + 'backbone.layer3.1.conv2_(0, 256)_256': 108, + 'backbone.layer3.2.conv1_(0, 256)_256': 90, + 'backbone.layer3.2.conv2_(0, 256)_256': 124, + 'backbone.layer3.3.conv1_(0, 256)_256': 94, + 'backbone.layer3.3.conv2_(0, 256)_256': 114, + 'backbone.layer3.4.conv1_(0, 256)_256': 99, + 'backbone.layer3.4.conv2_(0, 256)_256': 111, + 'backbone.layer3.5.conv1_(0, 256)_256': 108, + 'backbone.layer3.5.conv2_(0, 256)_256': 111, + 'backbone.layer4.0.conv1_(0, 512)_512': 400, + 'backbone.layer4.0.conv2_(0, 512)_512': 421, + 'backbone.layer4.1.conv1_(0, 512)_512': 377, + 'backbone.layer4.1.conv2_(0, 512)_512': 347, + 'backbone.layer4.2.conv1_(0, 512)_512': 443, + 'backbone.layer4.2.conv2_(0, 512)_512': 376 +} +divisor = 16 +############################################################################## + +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py new file mode 100755 index 000000000..b05be2676 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py @@ -0,0 +1,31 @@ +############################################################################# +"""# You have to fill these args. + +_base_(str): The path to your pruning config file. +pruned_path (str): The path to the checkpoint of the pruned model. +finetune_lr (float): The lr rate to finetune. Usually, we directly use the lr + rate of the pretrain. +""" + +_base_ = './group_fisher_flops_prune_resnet50_8xb32_in1k.py' +pruned_path = 'https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/flops/group_fisher_flops_prune_resnet50_8xb32_in1k.pth' # noqa +finetune_lr = 0.1 +############################################################################## +algorithm = _base_.model +algorithm.init_cfg = dict(type='Pretrained', checkpoint=pruned_path) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherSubModel', + algorithm=algorithm, +) + +# restore lr +optim_wrapper = dict(optimizer=dict(lr=finetune_lr)) + +# remove pruning related hooks +custom_hooks = _base_.custom_hooks[:-2] + +# delete ddp +model_wrapper_cfg = None diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_prune_resnet50_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_prune_resnet50_8xb32_in1k.py new file mode 100755 index 000000000..06b90bda0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_prune_resnet50_8xb32_in1k.py @@ -0,0 +1,5 @@ +_base_ = './group_fisher_act_prune_resnet50_8xb32_in1k.py' +model = dict( + mutator=dict( + channel_unit_cfg=dict( + default_args=dict(normalization_type='flops', ), ), ), ) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/metafile.yml b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/metafile.yml new file mode 100755 index 000000000..fd670a3c2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/metafile.yml @@ -0,0 +1,19 @@ +Models: + - Name: group_fisher_act_finetune_resnet50_8xb32_in1k + In Collection: GroupFisher + Config: configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/act/group_fisher_act_finetune_resnet50_8xb32_in1k.pth + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 75.22 + - Name: group_fisher_flops_finetune_resnet50_8xb32_in1k + In Collection: GroupFisher + Config: configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/flops/group_fisher_flops_finetune_resnet50_8xb32_in1k.pth + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 75.61 diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/script.sh b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/script.sh new file mode 100755 index 000000000..59ec7c567 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/script.sh @@ -0,0 +1,49 @@ +# act mode +bash ./tools/dist_train.sh configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_prune_resnet50_8xb32_in1k.py.py 8 +bash ./tools/dist_train.sh configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py.py 8 + +# flops mode +bash ./tools/dist_train.sh configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_prune_resnet50_8xb32_in1k.py.py 8 +bash ./tools/dist_train.sh configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py 8 + + +# deploy act mode + +razor_config=configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_deploy_resnet50_8xb32_in1k.py +deploy_config=mmdeploy/configs/mmcls/classification_onnxruntime_dynamic.py + +python mmdeploy/tools/deploy.py $deploy_config \ + $razor_config \ + https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/act/group_fisher_act_finetune_resnet50_8xb32_in1k.pth \ + mmdeploy/tests/data/tiger.jpeg \ + --work-dir ./work_dirs/mmdeploy + +python mmdeploy/tools/profiler.py $deploy_config \ + $razor_config \ + mmdeploy/demo/resources \ + --model ./work_dirs/mmdeploy/end2end.onnx \ + --shape 224x224 \ + --device cpu \ + --num-iter 1000 \ + --warmup 100 + + +# deploy flops mode + +razor_config=configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_deploy_resnet50_8xb32_in1k.py +deploy_config=mmdeploy/configs/mmcls/classification_onnxruntime_dynamic.py + +python mmdeploy/tools/deploy.py $deploy_config \ + $razor_config \ + https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/resnet50/flops/group_fisher_flops_finetune_resnet50_8xb32_in1k.pth \ + mmdeploy/tests/data/tiger.jpeg \ + --work-dir ./work_dirs/mmdeploy + +python mmdeploy/tools/profiler.py $deploy_config \ + $razor_config \ + mmdeploy/demo/resources \ + --model ./work_dirs/mmdeploy/end2end.onnx \ + --shape 224x224 \ + --device cpu \ + --num-iter 1000 \ + --warmup 100 diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/README.md b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/README.md new file mode 100755 index 000000000..2b6509298 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/README.md @@ -0,0 +1,61 @@ +# L1-norm pruning + +> [Pruning Filters for Efficient ConvNets.](https://arxiv.org/pdf/1608.08710.pdf) + + + +## Implementation + +L1-norm pruning is a classical filter pruning algorithm. It prunes filers(channels) according to the l1-norm of the weight of a conv layer. + +We use ItePruneAlgorithm and L1MutableChannelUnit to implement l1-norm pruning. Please refer to [Pruning User Guide](../../../../docs/en/user_guides/pruning_user_guide.md) for more configuration detail. + +| Model | Top-1 | Gap | Flop(G) | Pruned | Parameters | Pruned | Config | Download | +| ----------------- | ----- | ----- | ------- | ------ | ---------- | ------ | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ResNet34 | 73.62 | - | 3.68 | - | 2.18 | - | [mmcls](https://github.com/open-mmlab/mmclassification/blob/1.x/configs/resnet/resnet34_8xb32_in1k.py) | [model](https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.pth) \| [log](https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.log.json) | +| ResNet34_Pruned_A | 73.61 | -0.01 | 3.10 | 15.8% | 2.01 | 7.8% | [config](./l1-norm_resnet34_8xb32_in1k_a.py) | [model](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/l1-norm/l1-norm_resnet34_8xb32_in1k_a.pth) \| [log](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/l1-norm/l1-norm_resnet34_8xb32_in1k_a.json) | +| ResNet34_Pruned_B | 73.20 | -0.42 | 2.79 | 24.2% | 1.95 | 10.6% | [config](./l1-norm_resnet34_8xb32_in1k_a.py) | [model](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/l1-norm/l1-norm_resnet34_8xb32_in1k_b.pth) \| [log](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/l1-norm/l1-norm_resnet34_8xb32_in1k_b.json) | +| ResNet34_Pruned_C | 73.89 | +0.27 | 3.40 | 7.6% | 2.02 | 7.3% | [config](./l1-norm_resnet34_8xb32_in1k_a.py) | [model](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/l1-norm/l1-norm_resnet34_8xb32_in1k_c.pth) \| [log](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/l1-norm/l1-norm_resnet34_8xb32_in1k_c.json) | + +**Note:** There is a different implementation from the original paper. We pruned the layers related to the shortcut with a shared pruning decision, while the original paper pruned them separately in *Pruned C*. This may be why our *Pruned C* outperforms *Prune A* and *Prune B*, while *Pruned C* is worst in the original paper. + +## Getting Started + +### Prune + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 PORT=29500 ./tools/dist_train.sh \ + {prune_config_path}.py 8 --work-dir $WORK_DIR +``` + +after the pruning process, you can get a checkpoint file in the work_dir. This checkpoint file including all parameters of the original model. In the next step, we will use the checkpoint to export a pruned checkpoint. + +### Get the pruned model + +```bash +python ./tools/pruning/get_static_model_from_algorithm.py \ + {prune_config_path}.py \ + {checkpoint_file}.pth \ + --o {output_folder} +``` + +This step will export a pruned checkpoint and a json file which records the pruning structure. This two file will be used to deploy the pruned model. + +### Deploy + +For a pruned model, you only need to use the pruning deploy config instead of the pretrain config to deploy the pruned version of your model. If you are not fimilar with MMDeploy, please refer to [mmdeploy](https://github.com/open-mmlab/mmdeploy/tree/1.x). + +```bash +python {mmdeploy}/tools/deploy.py \ + {mmdeploy}/{mmdeploy_config}.py \ + {pruning_deploy_config}.py \ + {pruned_checkpoint}.pth \ + {mmdeploy}/tests/data/tiger.jpeg +``` + +### Get the Flops and Parameters of a Pruned Model + +```bash +python ./tools/pruning/get_flops.py \ + {pruning_deploy_config}.py +``` diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py new file mode 100755 index 000000000..25a92fd36 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py @@ -0,0 +1,60 @@ +_base_ = ['mmcls::resnet/resnet34_8xb32_in1k.py'] + +un_prune = 1.0 +stage_ratio_1 = 0.7 +stage_ratio_2 = 0.7 +stage_ratio_3 = 0.7 +stage_ratio_4 = un_prune + +# the config template of target_pruning_ratio can be got by +# python ./tools/get_channel_units.py {config_file} --choice +target_pruning_ratio = { + # stage 1 + 'backbone.conv1_(0, 64)_64': un_prune, # short cut layers + 'backbone.layer1.0.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.1.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.2.conv1_(0, 64)_64': un_prune, + # stage 2 + 'backbone.layer2.0.conv1_(0, 128)_128': un_prune, + 'backbone.layer2.0.conv2_(0, 128)_128': un_prune, # short cut layers + 'backbone.layer2.1.conv1_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.2.conv1_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.3.conv1_(0, 128)_128': un_prune, + # stage 3 + 'backbone.layer3.0.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.0.conv2_(0, 256)_256': un_prune, # short cut layers + 'backbone.layer3.1.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.2.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.3.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.4.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.5.conv1_(0, 256)_256': un_prune, + # stage 4 + 'backbone.layer4.0.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv2_(0, 512)_512': un_prune, # short cut layers + 'backbone.layer4.1.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv1_(0, 512)_512': stage_ratio_4 +} +data_preprocessor = {'type': 'mmcls.ClsDataPreprocessor'} +architecture = _base_.model +architecture.update({ + 'init_cfg': { + 'type': + 'Pretrained', + 'checkpoint': + 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet34_8xb32_in1k_20210831-f257d4e6.pth' # noqa + } +}) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='ItePruneAlgorithm', + architecture=architecture, + mutator_cfg=dict( + type='ChannelMutator', + channel_unit_cfg=dict( + type='L1MutableChannelUnit', + default_args=dict(choice_mode='ratio'))), + target_pruning_ratio=target_pruning_ratio, + step_freq=1, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a_deploy.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a_deploy.py new file mode 100755 index 000000000..c754d11fc --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a_deploy.py @@ -0,0 +1,57 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = ['mmcls::resnet/resnet34_8xb32_in1k.py'] +un_prune = 1.0 +stage_ratio_1 = 0.7 +stage_ratio_2 = 0.7 +stage_ratio_3 = 0.7 +stage_ratio_4 = un_prune + +# the config template of target_pruning_ratio can be got by +# python ./tools/get_channel_units.py {config_file} --choice +fix_subnet = { + # stage 1 + 'backbone.conv1_(0, 64)_64': un_prune, # short cut layers + 'backbone.layer1.0.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.1.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.2.conv1_(0, 64)_64': un_prune, + # stage 2 + 'backbone.layer2.0.conv1_(0, 128)_128': un_prune, + 'backbone.layer2.0.conv2_(0, 128)_128': un_prune, # short cut layers + 'backbone.layer2.1.conv1_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.2.conv1_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.3.conv1_(0, 128)_128': un_prune, + # stage 3 + 'backbone.layer3.0.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.0.conv2_(0, 256)_256': un_prune, # short cut layers + 'backbone.layer3.1.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.2.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.3.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.4.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.5.conv1_(0, 256)_256': un_prune, + # stage 4 + 'backbone.layer4.0.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv2_(0, 512)_512': un_prune, # short cut layers + 'backbone.layer4.1.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv1_(0, 512)_512': stage_ratio_4 +} +divisor = 8 +############################################################################## + +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b.py new file mode 100755 index 000000000..6f829e7df --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b.py @@ -0,0 +1,38 @@ +_base_ = ['./l1-norm_resnet34_8xb32_in1k_a.py'] + +un_prune = 1.0 +stage_ratio_1 = 0.5 +stage_ratio_2 = 0.4 +stage_ratio_3 = 0.6 +stage_ratio_4 = un_prune + +# the config template of target_pruning_ratio can be got by +# python ./tools/get_channel_units.py {config_file} --choice +target_pruning_ratio = { + # stage 1 + 'backbone.conv1_(0, 64)_64': un_prune, # short cut layers + 'backbone.layer1.0.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.1.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.2.conv1_(0, 64)_64': un_prune, + # stage 2 + 'backbone.layer2.0.conv1_(0, 128)_128': un_prune, + 'backbone.layer2.0.conv2_(0, 128)_128': un_prune, # short cut layers + 'backbone.layer2.1.conv1_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.2.conv1_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.3.conv1_(0, 128)_128': un_prune, + # stage 3 + 'backbone.layer3.0.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.0.conv2_(0, 256)_256': un_prune, # short cut layers + 'backbone.layer3.1.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.2.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.3.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.4.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.5.conv1_(0, 256)_256': un_prune, + # stage 4 + 'backbone.layer4.0.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv2_(0, 512)_512': un_prune, # short cut layers + 'backbone.layer4.1.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv1_(0, 512)_512': stage_ratio_4 +} + +model = dict(target_pruning_ratio=target_pruning_ratio, ) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b_deploy.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b_deploy.py new file mode 100755 index 000000000..636ff0766 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b_deploy.py @@ -0,0 +1,57 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = ['mmcls::resnet/resnet34_8xb32_in1k.py'] + +un_prune = 1.0 +stage_ratio_1 = 0.5 +stage_ratio_2 = 0.4 +stage_ratio_3 = 0.6 +stage_ratio_4 = un_prune + +fix_subnet = { + # stage 1 + 'backbone.conv1_(0, 64)_64': un_prune, # short cut layers + 'backbone.layer1.0.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.1.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.2.conv1_(0, 64)_64': un_prune, + # stage 2 + 'backbone.layer2.0.conv1_(0, 128)_128': un_prune, + 'backbone.layer2.0.conv2_(0, 128)_128': un_prune, # short cut layers + 'backbone.layer2.1.conv1_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.2.conv1_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.3.conv1_(0, 128)_128': un_prune, + # stage 3 + 'backbone.layer3.0.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.0.conv2_(0, 256)_256': un_prune, # short cut layers + 'backbone.layer3.1.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.2.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.3.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.4.conv1_(0, 256)_256': stage_ratio_3, + 'backbone.layer3.5.conv1_(0, 256)_256': un_prune, + # stage 4 + 'backbone.layer4.0.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv2_(0, 512)_512': un_prune, # short cut layers + 'backbone.layer4.1.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv1_(0, 512)_512': stage_ratio_4 +} + +divisor = 8 +############################################################################## + +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c.py new file mode 100755 index 000000000..d597471a3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c.py @@ -0,0 +1,34 @@ +_base_ = ['./l1-norm_resnet34_8xb32_in1k_a.py'] + +un_prune = 1.0 + +# the config template of target_pruning_ratio can be got by +# python ./tools/get_channel_units.py {config_file} --choice +target_pruning_ratio = { + # stage 1 + 'backbone.conv1_(0, 64)_64': un_prune, # short cut layers + 'backbone.layer1.0.conv1_(0, 64)_64': un_prune, + 'backbone.layer1.1.conv1_(0, 64)_64': un_prune, + 'backbone.layer1.2.conv1_(0, 64)_64': un_prune, + # stage 2 + 'backbone.layer2.0.conv1_(0, 128)_128': un_prune, + 'backbone.layer2.0.conv2_(0, 128)_128': un_prune, # short cut layers + 'backbone.layer2.1.conv1_(0, 128)_128': un_prune, + 'backbone.layer2.2.conv1_(0, 128)_128': un_prune, + 'backbone.layer2.3.conv1_(0, 128)_128': un_prune, + # stage 3 + 'backbone.layer3.0.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.0.conv2_(0, 256)_256': 0.8, # short cut layers + 'backbone.layer3.1.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.2.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.3.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.4.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.5.conv1_(0, 256)_256': un_prune, + # stage 4 + 'backbone.layer4.0.conv1_(0, 512)_512': un_prune, + 'backbone.layer4.0.conv2_(0, 512)_512': un_prune, # short cut layers + 'backbone.layer4.1.conv1_(0, 512)_512': un_prune, + 'backbone.layer4.2.conv1_(0, 512)_512': un_prune +} + +model = dict(target_pruning_ratio=target_pruning_ratio, ) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c_deploy.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c_deploy.py new file mode 100755 index 000000000..2c7a42e12 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c_deploy.py @@ -0,0 +1,54 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = ['mmcls::resnet/resnet34_8xb32_in1k.py'] +un_prune = 1.0 + +# the config template of target_pruning_ratio can be got by +# python ./tools/get_channel_units.py {config_file} --choice +fix_subnet = { + # stage 1 + 'backbone.conv1_(0, 64)_64': un_prune, # short cut layers + 'backbone.layer1.0.conv1_(0, 64)_64': un_prune, + 'backbone.layer1.1.conv1_(0, 64)_64': un_prune, + 'backbone.layer1.2.conv1_(0, 64)_64': un_prune, + # stage 2 + 'backbone.layer2.0.conv1_(0, 128)_128': un_prune, + 'backbone.layer2.0.conv2_(0, 128)_128': un_prune, # short cut layers + 'backbone.layer2.1.conv1_(0, 128)_128': un_prune, + 'backbone.layer2.2.conv1_(0, 128)_128': un_prune, + 'backbone.layer2.3.conv1_(0, 128)_128': un_prune, + # stage 3 + 'backbone.layer3.0.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.0.conv2_(0, 256)_256': 0.8, # short cut layers + 'backbone.layer3.1.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.2.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.3.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.4.conv1_(0, 256)_256': un_prune, + 'backbone.layer3.5.conv1_(0, 256)_256': un_prune, + # stage 4 + 'backbone.layer4.0.conv1_(0, 512)_512': un_prune, + 'backbone.layer4.0.conv2_(0, 512)_512': un_prune, # short cut layers + 'backbone.layer4.1.conv1_(0, 512)_512': un_prune, + 'backbone.layer4.2.conv1_(0, 512)_512': un_prune +} + +divisor = 8 +############################################################################## + +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/metafile.yml b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/metafile.yml new file mode 100755 index 000000000..3009fdc25 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/metafile.yml @@ -0,0 +1,28 @@ +Models: + - Name: l1-norm_resnet34_8xb32_in1k_a + In Collection: L1-norm + Config: configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py + Weights: https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/l1-norm/l1-norm_resnet34_8xb32_in1k_a.pth + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 73.61 + - Name: l1-norm_resnet34_8xb32_in1k_b + In Collection: L1-norm + Config: configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b.py + Weights: https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/l1-norm/l1-norm_resnet34_8xb32_in1k_b.pth + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 73.20 + - Name: l1-norm_resnet34_8xb32_in1k_c + In Collection: L1-norm + Config: configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c.py + Weights: https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/l1-norm/l1-norm_resnet34_8xb32_in1k_c.pth + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 73.89 diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/script.sh b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/script.sh new file mode 100755 index 000000000..2bc1e9274 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/script.sh @@ -0,0 +1,25 @@ + +# export pruned checkpoint example + +python ./tools/pruning/get_static_model_from_algorithm.py configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/pruning/l1-norm/l1-norm_resnet34_8xb32_in1k_a.pth -o ./work_dirs/norm_resnet34_8xb32_in1k_a + +# deploy example + +razor_config=configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a_deploy.py +deploy_config=mmdeploy/configs/mmcls/classification_onnxruntime_dynamic.py +static_model_checkpoint_path=path/to/pruend/checkpoint + +python mmdeploy/tools/deploy.py $deploy_config \ + $razor_config \ + $static_model_checkpoint_path \ + mmdeploy/tests/data/tiger.jpeg \ + --work-dir ./work_dirs/mmdeploy + +python mmdeploy/tools/profiler.py $deploy_config \ + $razor_config \ + mmdeploy/demo/resources \ + --model ./work_dirs/mmdeploy/end2end.onnx \ + --shape 224x224 \ + --device cpu \ + --num-iter 1000 \ + --warmup 100 diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/README.md b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/README.md new file mode 100755 index 000000000..c156e19f5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/README.md @@ -0,0 +1,82 @@ +# Training Compact CNNs for Image Classification using Dynamic-coded Filter Fusion + +## Abstract + +The mainstream approach for filter pruning is usually either to force a hard-coded importance estimation upon a computation-heavy pretrained model to select “important†filters, or to impose a hyperparameter-sensitive sparse constraint on the loss objective to regularize the network training. In this paper, we present a novel filter pruning method, dubbed dynamic-coded filter fusion (DCFF), to derive compact CNNs in a computationeconomical and regularization-free manner for efficient image classification. Each filter in our DCFF is firstly given an intersimilarity distribution with a temperature parameter as a filter proxy, on top of which, a fresh Kullback-Leibler divergence based dynamic-coded criterion is proposed to evaluate the filter importance. In contrast to simply keeping high-score filters in other methods, we propose the concept of filter fusion, i.e., the weighted averages using the assigned proxies, as our preserved filters. We obtain a one-hot inter-similarity distribution as the temperature parameter approaches infinity. Thus, the relative importance of each filter can vary along with the training of the compact CNN, leading to dynamically changeable fused filters without both the dependency on the pretrained model and the introduction of sparse constraints. Extensive experiments on classification benchmarks demonstrate the superiority of our DCFF over the compared counterparts. For example, our DCFF derives a compact VGGNet-16 with only 72.77M FLOPs and 1.06M parameters while reaching top-1 accuracy of 93.47% on CIFAR-10. A compact ResNet-50 is obtained with 63.8% FLOPs and 58.6% parameter reductions, retaining 75.60% top1 accuracy on ILSVRC-2012. + +![pipeline](https://user-images.githubusercontent.com/31244134/189286581-722853ba-c6d7-4a39-b902-37995b444c71.jpg) + +## Results and models + +### 1. Classification + +| Dataset | Backbone | Params(M) | FLOPs(M) | lr_type | Top-1 (%) | Top-5 (%) | CPrate | Config | Download | +| :------: | :----------: | :-------: | :------: | :-----: | :-------: | :-------: | :---------------------------------------------: | :--------------------------------------------------: | :--------------------------: | +| ImageNet | DCFFResNet50 | 15.16 | 2260 | step | 73.96 | 91.66 | \[0.0\]+\[0.35,0.4,0.1\]\*10+\[0.3,0.3,0.1\]\*6 | [config](../../mmcls/dcff/dcff_resnet_8xb32_in1k.py) | [model](<>) \| \[log\] (\<>) | + +### 2. Detection + +| Dataset | Method | Backbone | Style | Lr schd | Params(M) | FLOPs(M) | bbox AP | CPrate | Config | Download | +| :-----: | :---------: | :----------: | :-----: | :-----: | :-------: | :------: | :-----: | :---------------------------------------------: | :---------------------------------------------------------------: | :--------------------------: | +| COCO | Faster_RCNN | DCFFResNet50 | pytorch | step | 33.31 | 168320 | 35.8 | \[0.0\]+\[0.35,0.4,0.1\]\*10+\[0.3,0.3,0.1\]\*6 | [config](../../mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py) | [model](<>) \| \[log\] (\<>) | + +### 3. Segmentation + +| Dataset | Method | Backbone | crop size | Lr schd | Params(M) | FLOPs(M) | mIoU | CPrate | Config | Download | +| :--------: | :-------: | :-------------: | :-------: | :-----: | :-------: | :------: | :---: | :-----------------------------------------------------------------: | :-------------------------------------------------------------------: | :--------------------------: | +| Cityscapes | PointRend | DCFFResNetV1c50 | 512x1024 | 160k | 18.43 | 74410 | 76.75 | \[0.0, 0.0, 0.0\] + \[0.35, 0.4, 0.1\] * 10 + \[0.3, 0.3, 0.1\] * 6 | [config](../../mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py) | [model](<>) \| \[log\] (\<>) | + +### 4. Pose + +| Dataset | Method | Backbone | crop size | total epochs | Params(M) | FLOPs(M) | AP | CPrate | Config | Download | +| :-----: | :-------------: | :----------: | :-------: | :----------: | :-------: | :------: | :--: | :--------------------------------------------------------: | :---------------------------------------------------------------: | :--------------------------: | +| COCO | TopDown HeatMap | DCFFResNet50 | 256x192 | 300 | 26.95 | 4290 | 68.3 | \[0.0\] + \[0.2, 0.2, 0.1\] * 10 + \[0.15, 0.15, 0.1\] * 6 | [config](../../mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py) | [model](<>) \| \[log\] (\<>) | + +## Citation + +```latex +@article{lin2021training, + title={Training Compact CNNs for Image Classification using Dynamic-coded Filter Fusion}, + author={Lin, Mingbao and Ji, Rongrong and Chen, Bohong and Chao, Fei and Liu, Jianzhuang and Zeng, Wei and Tian, Yonghong and Tian, Qi}, + journal={arXiv preprint arXiv:2107.06916}, + year={2021} +} +``` + +## Get Started + +### Generate channel_config file + +Generate `resnet_det.json` with `tools/pruning/get_channel_units.py`. + +```bash +python tools/pruning/get_channel_units.py + configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py \ + -c -i --output-path=configs/pruning/mmcls/dcff/resnet_det.json +``` + +Then set layers' pruning rates `target_pruning_ratio` by `resnet_det.json`. + +### Train DCFF + +#### Detection + +##### COCO + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py 4 \ + --work-dir $WORK_DIR +``` + +### Test DCFF + +#### Detection + +##### COCO + +```bash +CUDA_VISIBLE_DEVICES=0 PORT=29500 ./tools/dist_test.sh \ + configs/pruning/mmdet/dcff/dcff_compact_faster_rcnn_resnet50_8xb4_coco.py \ + $CKPT 1 --work-dir $WORK_DIR +``` diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_compact_faster_rcnn_resnet50_8xb4_coco.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_compact_faster_rcnn_resnet50_8xb4_coco.py new file mode 100755 index 000000000..5a2db5c11 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_compact_faster_rcnn_resnet50_8xb4_coco.py @@ -0,0 +1,12 @@ +_base_ = ['dcff_faster_rcnn_resnet50_8xb4_coco.py'] + +# model settings +_base_.model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.architecture, + fix_subnet='configs/pruning/mmdet/dcff/fix_subnet.json', + mode='mutator', + init_cfg=dict( + type='Pretrained', + checkpoint='configs/pruning/mmdet/dcff/fix_subnet_weight.pth')) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py new file mode 100755 index 000000000..5d51677b8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py @@ -0,0 +1,87 @@ +_base_ = [ + './dcff_faster_rcnn_resnet50_fpn.py', + 'mmdet::_base_/datasets/coco_detection.py', + 'mmdet::_base_/schedules/schedule_2x.py', + 'mmdet::_base_/default_runtime.py' +] + +stage_ratio_1 = 0.65 +stage_ratio_2 = 0.6 +stage_ratio_3 = 0.9 +stage_ratio_4 = 0.7 + +# the config template of target_pruning_ratio can be got by +# python ./tools/pruning/get_channel_units.py {config_file} --choice +target_pruning_ratio = { + 'backbone.layer1.0.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.0.conv2_(0, 64)_64': stage_ratio_2, + 'backbone.layer1.0.conv3_(0, 256)_256': stage_ratio_3, + 'backbone.layer1.1.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.1.conv2_(0, 64)_64': stage_ratio_2, + 'backbone.layer1.2.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.2.conv2_(0, 64)_64': stage_ratio_2, + # block 1 [0.65, 0.6] downsample=[0.9] + 'backbone.layer2.0.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.0.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.0.conv3_(0, 512)_512': stage_ratio_3, + 'backbone.layer2.1.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.1.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.2.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.2.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.3.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.3.conv2_(0, 128)_128': stage_ratio_2, + # block 2 [0.65, 0.6] downsample=[0.9] + 'backbone.layer3.0.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.0.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.0.conv3_(0, 1024)_1024': stage_ratio_3, + 'backbone.layer3.1.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.1.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.2.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.2.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.3.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.3.conv2_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.4.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.4.conv2_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.5.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.5.conv2_(0, 256)_256': stage_ratio_4, + # block 3 [0.65, 0.6]*2+[0.7, 0.7]*2 downsample=[0.9] + 'backbone.layer4.0.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv2_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv3_(0, 2048)_2048': stage_ratio_3, + 'backbone.layer4.1.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.1.conv2_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv2_(0, 512)_512': stage_ratio_4 + # block 4 [0.7, 0.7] downsample=[0.9] +} + +optim_wrapper = dict( + optimizer=dict(type='SGD', lr=0.04, momentum=0.9, weight_decay=0.0001)) +param_scheduler = dict( + type='MultiStepLR', + by_epoch=True, + milestones=[60, 80, 95], + gamma=0.1, + _delete_=True) +train_cfg = dict(max_epochs=120, val_interval=1) + +model = dict( + _scope_='mmrazor', + type='DCFF', + architecture=_base_.architecture, + mutator_cfg=dict( + type='DCFFChannelMutator', + channel_unit_cfg=dict( + type='DCFFChannelUnit', default_args=dict(choice_mode='ratio')), + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='FxTracer')), + target_pruning_ratio=target_pruning_ratio, + step_freq=1, + linear_schedule=False) + +model_wrapper = dict( + type='mmcv.MMDistributedDataParallel', find_unused_parameters=True) + +val_cfg = dict(_delete_=True, type='mmrazor.ItePruneValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_fpn.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_fpn.py new file mode 100755 index 000000000..0ce540338 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_fpn.py @@ -0,0 +1,114 @@ +# architecture settings +architecture = dict( + _scope_='mmdet', + type='FasterRCNN', + data_preprocessor=dict( + type='DetDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True, + pad_size_divisor=32), + backbone=dict( + type='ResNet', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + frozen_stages=1, + norm_cfg=dict(type='BN', requires_grad=True), + norm_eval=True, + style='pytorch'), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=5), + rpn_head=dict( + type='RPNHead', + in_channels=256, + feat_channels=256, + anchor_generator=dict( + type='AnchorGenerator', + scales=[8], + ratios=[0.5, 1.0, 2.0], + strides=[4, 8, 16, 32, 64]), + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[.0, .0, .0, .0], + target_stds=[1.0, 1.0, 1.0, 1.0]), + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0)), + roi_head=dict( + type='StandardRoIHead', + bbox_roi_extractor=dict( + type='SingleRoIExtractor', + roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0), + out_channels=256, + featmap_strides=[4, 8, 16, 32]), + bbox_head=dict( + type='Shared2FCBBoxHead', + in_channels=256, + fc_out_channels=1024, + roi_feat_size=7, + num_classes=80, + bbox_coder=dict( + type='DeltaXYWHBBoxCoder', + target_means=[0., 0., 0., 0.], + target_stds=[0.1, 0.1, 0.2, 0.2]), + reg_class_agnostic=False, + loss_cls=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), + loss_bbox=dict(type='L1Loss', loss_weight=1.0))), + # model training and testing settings + train_cfg=dict( + rpn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.7, + neg_iou_thr=0.3, + min_pos_iou=0.3, + match_low_quality=True, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=256, + pos_fraction=0.5, + neg_pos_ub=-1, + add_gt_as_proposals=False), + allowed_border=-1, + pos_weight=-1, + debug=False), + rpn_proposal=dict( + nms_pre=2000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + assigner=dict( + type='MaxIoUAssigner', + pos_iou_thr=0.5, + neg_iou_thr=0.5, + min_pos_iou=0.5, + match_low_quality=False, + ignore_iof_thr=-1), + sampler=dict( + type='RandomSampler', + num=512, + pos_fraction=0.25, + neg_pos_ub=-1, + add_gt_as_proposals=True), + pos_weight=-1, + debug=False)), + test_cfg=dict( + rpn=dict( + nms_pre=1000, + max_per_img=1000, + nms=dict(type='nms', iou_threshold=0.7), + min_bbox_size=0), + rcnn=dict( + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.5), + max_per_img=100) + # soft-nms is also supported for rcnn testing + # e.g., nms=dict(type='soft_nms', iou_threshold=0.5, min_score=0.05) + )) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/fix_subnet.json b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/fix_subnet.json new file mode 100755 index 000000000..dfdcea758 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/fix_subnet.json @@ -0,0 +1,141 @@ +{ + "type":"DCFFChannelMutator", + "channel_unit_cfg":{ + "type":"DCFFChannelUnit", + "default_args":{ + "choice_mode":"ratio" + }, + "units":{ + "backbone.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":1.0 + }, + "backbone.layer1.0.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.640625 + }, + "backbone.layer1.1.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.640625 + }, + "backbone.layer2.0.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer2.0.conv2_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.59375 + }, + "backbone.layer2.1.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer3.0.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer3.0.conv2_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.59765625 + }, + "backbone.layer3.1.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer4.0.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + }, + "backbone.layer4.0.conv2_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + }, + "backbone.layer4.1.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + } + } + }, + "parse_cfg":{ + "type":"ChannelAnalyzer", + "demo_input":[ + 1, + 3, + 224, + 224 + ], + "tracer_type":"BackwardTracer" + } +} diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/README.md b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/README.md new file mode 100755 index 000000000..9b3b09936 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/README.md @@ -0,0 +1,11 @@ +# Group_fisher pruning + +> [Group Fisher Pruning for Practical Network Compression.](https://arxiv.org/pdf/2108.00708.pdf) + +## Abstract + +Network compression has been widely studied since it is able to reduce the memory and computation cost during inference. However, previous methods seldom deal with complicated structures like residual connections, group/depthwise convolution and feature pyramid network, where channels of multiple layers are coupled and need to be pruned simultaneously. In this paper, we present a general channel pruning approach that can be applied to various complicated structures. Particularly, we propose a layer grouping algorithm to find coupled channels automatically. Then we derive a unified metric based on Fisher information to evaluate the importance of a single channel and coupled channels. Moreover, we find that inference speedup on GPUs is more correlated with the reduction of memory rather than FLOPs, and thus we employ the memory reduction of each channel to normalize the importance. Our method can be used to prune any structures including those with coupled channels. We conduct extensive experiments on various backbones, including the classic ResNet and ResNeXt, mobilefriendly MobileNetV2, and the NAS-based RegNet, both on image classification and object detection which is under-explored. Experimental results validate that our method can effectively prune sophisticated networks, boosting inference speed without sacrificing accuracy. + +![pipeline](https://github.com/jshilong/FisherPruning/blob/main/resources/structures.png?raw=true) + +**Please refer to the [full README](../../base/group_fisher/README.md) for more details.** diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_deploy_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_deploy_retinanet_r50_fpn_1x_coco.py new file mode 100755 index 000000000..1146fc78a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_deploy_retinanet_r50_fpn_1x_coco.py @@ -0,0 +1,73 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = 'mmdet::retinanet/retinanet_r50_fpn_1x_coco.py' +fix_subnet = { + 'backbone.conv1_(0, 64)_64': 60, + 'backbone.layer1.0.conv1_(0, 64)_64': 48, + 'backbone.layer1.0.conv2_(0, 64)_64': 44, + 'backbone.layer1.0.conv3_(0, 256)_256': 250, + 'backbone.layer1.1.conv1_(0, 64)_64': 40, + 'backbone.layer1.1.conv2_(0, 64)_64': 41, + 'backbone.layer1.2.conv1_(0, 64)_64': 48, + 'backbone.layer1.2.conv2_(0, 64)_64': 62, + 'backbone.layer2.0.conv1_(0, 128)_128': 115, + 'backbone.layer2.0.conv2_(0, 128)_128': 127, + 'backbone.layer2.0.conv3_(0, 512)_512': 511, + 'backbone.layer2.1.conv1_(0, 128)_128': 69, + 'backbone.layer2.1.conv2_(0, 128)_128': 83, + 'backbone.layer2.2.conv1_(0, 128)_128': 111, + 'backbone.layer2.2.conv2_(0, 128)_128': 121, + 'backbone.layer2.3.conv1_(0, 128)_128': 122, + 'backbone.layer2.3.conv2_(0, 128)_128': 128, + 'backbone.layer3.0.conv1_(0, 256)_256': 255, + 'backbone.layer3.0.conv2_(0, 256)_256': 256, + 'backbone.layer3.0.conv3_(0, 1024)_1024': 1024, + 'backbone.layer3.1.conv1_(0, 256)_256': 216, + 'backbone.layer3.1.conv2_(0, 256)_256': 223, + 'backbone.layer3.2.conv1_(0, 256)_256': 229, + 'backbone.layer3.2.conv2_(0, 256)_256': 247, + 'backbone.layer3.3.conv1_(0, 256)_256': 239, + 'backbone.layer3.3.conv2_(0, 256)_256': 246, + 'backbone.layer3.4.conv1_(0, 256)_256': 237, + 'backbone.layer3.4.conv2_(0, 256)_256': 239, + 'backbone.layer3.5.conv1_(0, 256)_256': 233, + 'backbone.layer3.5.conv2_(0, 256)_256': 221, + 'backbone.layer4.0.conv1_(0, 512)_512': 499, + 'backbone.layer4.0.conv2_(0, 512)_512': 494, + 'backbone.layer4.0.conv3_(0, 2048)_2048': 2031, + 'backbone.layer4.1.conv1_(0, 512)_512': 451, + 'backbone.layer4.1.conv2_(0, 512)_512': 401, + 'backbone.layer4.2.conv1_(0, 512)_512': 396, + 'backbone.layer4.2.conv2_(0, 512)_512': 237, + 'neck.lateral_convs.0.conv_(0, 256)_256': 237, + 'neck.fpn_convs.0.conv_(0, 256)_256': 241, + 'bbox_head.cls_convs.0.conv_(0, 256)_256': 133, + 'bbox_head.cls_convs.1.conv_(0, 256)_256': 134, + 'bbox_head.cls_convs.2.conv_(0, 256)_256': 139, + 'bbox_head.cls_convs.3.conv_(0, 256)_256': 79, + 'bbox_head.reg_convs.0.conv_(0, 256)_256': 89, + 'bbox_head.reg_convs.1.conv_(0, 256)_256': 92, + 'bbox_head.reg_convs.2.conv_(0, 256)_256': 82, + 'bbox_head.reg_convs.3.conv_(0, 256)_256': 117 +} +divisor = 16 + +############################################################################## + +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py new file mode 100755 index 000000000..b0f7d08de --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py @@ -0,0 +1,31 @@ +############################################################################# +"""# You have to fill these args. + +_base_(str): The path to your pruning config file. +pruned_path (str): The path to the checkpoint of the pruned model. +finetune_lr (float): The lr rate to finetune. Usually, we directly use the lr + rate of the pretrain. +""" + +_base_ = './group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py' +pruned_path = 'https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/retinanet/act/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.pth' # noqa +finetune_lr = 0.005 +############################################################################## +algorithm = _base_.model +algorithm.init_cfg = dict(type='Pretrained', checkpoint=pruned_path) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherSubModel', + algorithm=algorithm, +) + +# restore lr +optim_wrapper = dict(optimizer=dict(lr=finetune_lr)) + +# remove pruning related hooks +custom_hooks = _base_.custom_hooks[:-2] + +# delete ddp +model_wrapper_cfg = None diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py new file mode 100755 index 000000000..1bfb07081 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py @@ -0,0 +1,76 @@ +############################################################################# +"""You have to fill these args. + +_base_ (str): The path to your pretrained model checkpoint. +pretrained_path (str): The path to your pretrained model checkpoint. + +interval (int): Interval between pruning two channels. You should ensure you + can reach your target pruning ratio when the training ends. +normalization_type (str): GroupFisher uses two methods to normlized the channel + importance, including ['flops','act']. The former uses flops, while the + latter uses the memory occupation of activation feature maps. +lr_ratio (float): Ratio to decrease lr rate. As pruning progress is unstable, + you need to decrease the original lr rate until the pruning training work + steadly without getting nan. + +target_flop_ratio (float): The target flop ratio to prune your model. +input_shape (Tuple): input shape to measure the flops. +""" + +_base_ = 'mmdet::retinanet/retinanet_r50_fpn_1x_coco.py' +pretrained_path = 'https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_1x_coco/retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth' # noqa + +interval = 10 +normalization_type = 'act' +lr_ratio = 0.1 + +target_flop_ratio = 0.5 +input_shape = (1, 3, 1333, 800) +############################################################################## + +architecture = _base_.model + +if hasattr(_base_, 'data_preprocessor'): + architecture.update({'data_preprocessor': _base_.data_preprocessor}) + data_preprocessor = {} + +architecture.init_cfg = dict(type='Pretrained', checkpoint=pretrained_path) +architecture['_scope_'] = _base_.default_scope +architecture.backbone.frozen_stages = -1 + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherAlgorithm', + architecture=architecture, + interval=interval, + mutator=dict( + type='GroupFisherChannelMutator', + parse_cfg=dict(type='ChannelAnalyzer', tracer_type='FxTracer'), + channel_unit_cfg=dict( + type='GroupFisherChannelUnit', + default_args=dict(normalization_type=normalization_type, ), + ), + ), +) + +model_wrapper_cfg = dict( + type='mmrazor.GroupFisherDDP', + broadcast_buffers=False, +) + +optim_wrapper = dict( + optimizer=dict(lr=_base_.optim_wrapper.optimizer.lr * lr_ratio)) + +custom_hooks = getattr(_base_, 'custom_hooks', []) + [ + dict(type='mmrazor.PruningStructureHook'), + dict( + type='mmrazor.ResourceInfoHook', + interval=interval, + demo_input=dict( + type='mmrazor.DefaultDemoInput', + input_shape=input_shape, + ), + save_ckpt_thr=[target_flop_ratio], + ), +] diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_deploy_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_deploy_retinanet_r50_fpn_1x_coco.py new file mode 100755 index 000000000..88446dbe8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_deploy_retinanet_r50_fpn_1x_coco.py @@ -0,0 +1,73 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = 'mmdet::retinanet/retinanet_r50_fpn_1x_coco.py' +fix_subnet = { + 'backbone.conv1_(0, 64)_64': 60, + 'backbone.layer1.0.conv1_(0, 64)_64': 47, + 'backbone.layer1.0.conv2_(0, 64)_64': 44, + 'backbone.layer1.0.conv3_(0, 256)_256': 249, + 'backbone.layer1.1.conv1_(0, 64)_64': 37, + 'backbone.layer1.1.conv2_(0, 64)_64': 37, + 'backbone.layer1.2.conv1_(0, 64)_64': 44, + 'backbone.layer1.2.conv2_(0, 64)_64': 62, + 'backbone.layer2.0.conv1_(0, 128)_128': 114, + 'backbone.layer2.0.conv2_(0, 128)_128': 127, + 'backbone.layer2.0.conv3_(0, 512)_512': 511, + 'backbone.layer2.1.conv1_(0, 128)_128': 65, + 'backbone.layer2.1.conv2_(0, 128)_128': 83, + 'backbone.layer2.2.conv1_(0, 128)_128': 106, + 'backbone.layer2.2.conv2_(0, 128)_128': 118, + 'backbone.layer2.3.conv1_(0, 128)_128': 118, + 'backbone.layer2.3.conv2_(0, 128)_128': 127, + 'backbone.layer3.0.conv1_(0, 256)_256': 255, + 'backbone.layer3.0.conv2_(0, 256)_256': 256, + 'backbone.layer3.0.conv3_(0, 1024)_1024': 1024, + 'backbone.layer3.1.conv1_(0, 256)_256': 214, + 'backbone.layer3.1.conv2_(0, 256)_256': 232, + 'backbone.layer3.2.conv1_(0, 256)_256': 224, + 'backbone.layer3.2.conv2_(0, 256)_256': 247, + 'backbone.layer3.3.conv1_(0, 256)_256': 240, + 'backbone.layer3.3.conv2_(0, 256)_256': 246, + 'backbone.layer3.4.conv1_(0, 256)_256': 240, + 'backbone.layer3.4.conv2_(0, 256)_256': 243, + 'backbone.layer3.5.conv1_(0, 256)_256': 238, + 'backbone.layer3.5.conv2_(0, 256)_256': 232, + 'backbone.layer4.0.conv1_(0, 512)_512': 503, + 'backbone.layer4.0.conv2_(0, 512)_512': 500, + 'backbone.layer4.0.conv3_(0, 2048)_2048': 2041, + 'backbone.layer4.1.conv1_(0, 512)_512': 466, + 'backbone.layer4.1.conv2_(0, 512)_512': 430, + 'backbone.layer4.2.conv1_(0, 512)_512': 406, + 'backbone.layer4.2.conv2_(0, 512)_512': 274, + 'neck.lateral_convs.0.conv_(0, 256)_256': 236, + 'neck.fpn_convs.0.conv_(0, 256)_256': 225, + 'bbox_head.cls_convs.0.conv_(0, 256)_256': 140, + 'bbox_head.cls_convs.1.conv_(0, 256)_256': 133, + 'bbox_head.cls_convs.2.conv_(0, 256)_256': 139, + 'bbox_head.cls_convs.3.conv_(0, 256)_256': 86, + 'bbox_head.reg_convs.0.conv_(0, 256)_256': 89, + 'bbox_head.reg_convs.1.conv_(0, 256)_256': 89, + 'bbox_head.reg_convs.2.conv_(0, 256)_256': 76, + 'bbox_head.reg_convs.3.conv_(0, 256)_256': 122, +} +divisor = 16 + +############################################################################## + +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py new file mode 100755 index 000000000..9d2d3a001 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py @@ -0,0 +1,31 @@ +############################################################################# +"""# You have to fill these args. + +_base_(str): The path to your pruning config file. +pruned_path (str): The path to the checkpoint of the pruned model. +finetune_lr (float): The lr rate to finetune. Usually, we directly use the lr + rate of the pretrain. +""" + +_base_ = './group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py' +pruned_path = 'https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/retinanet/flops/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.pth' # noqa +finetune_lr = 0.005 +############################################################################## +algorithm = _base_.model +algorithm.init_cfg = dict(type='Pretrained', checkpoint=pruned_path) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherSubModel', + algorithm=algorithm, +) + +# restore lr +optim_wrapper = dict(optimizer=dict(lr=finetune_lr)) + +# remove pruning related hooks +custom_hooks = _base_.custom_hooks[:-2] + +# delete ddp +model_wrapper_cfg = None diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py new file mode 100755 index 000000000..162db3bed --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py @@ -0,0 +1,5 @@ +_base_ = './group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py' +model = dict( + mutator=dict( + channel_unit_cfg=dict( + default_args=dict(normalization_type='flops', ), ), ), ) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/metafile.yml b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/metafile.yml new file mode 100755 index 000000000..232f9cb97 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/metafile.yml @@ -0,0 +1,19 @@ +Models: + - Name: group_fisher_act_finetune_retinanet_r50_fpn_1x_coco + In Collection: GroupFisher + Config: configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py + Weights: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/retinanet/act/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.pth + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.5 + - Name: group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco + In Collection: GroupFisher + Config: configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py + Weights: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/retinanet/flops/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.pth + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.6 diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/script.sh b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/script.sh new file mode 100755 index 000000000..b14243a4d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/script.sh @@ -0,0 +1,49 @@ +# act mode +bash ./tools/dist_train.sh configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py 8 +bash ./tools/dist_train.sh configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py 8 + +# flops mode +bash ./tools/dist_train.sh configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py 8 +bash ./tools/dist_train.sh configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py 8 + + + +# deploy act mode + +razor_config=configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_deploy_retinanet_r50_fpn_1x_coco.py +deploy_config=mmdeploy/configs/mmdet/detection/detection_onnxruntime_static.py + +python mmdeploy/tools/deploy.py $deploy_config \ + $razor_config \ + https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/retinanet/act/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.pth \ + mmdeploy/tests/data/tiger.jpeg \ + --work-dir ./work_dirs/mmdeploy + +python mmdeploy/tools/profiler.py $deploy_config \ + $razor_config \ + mmdeploy/demo/resources \ + --model ./work_dirs/mmdeploy/end2end.onnx \ + --shape 800x1248 \ + --device cpu \ + --num-iter 1000 \ + --warmup 100 + +# deploy flop mode + +razor_config=configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_deploy_retinanet_r50_fpn_1x_coco.py +deploy_config=mmdeploy/configs/mmdet/detection/detection_onnxruntime_static.py + +python mmdeploy/tools/deploy.py $deploy_config \ + $razor_config \ + https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/retinanet/flops/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.pth \ + mmdeploy/tests/data/tiger.jpeg \ + --work-dir ./work_dirs/mmdeploy + +python mmdeploy/tools/profiler.py $deploy_config \ + $razor_config \ + mmdeploy/demo/resources \ + --model ./work_dirs/mmdeploy/end2end.onnx \ + --shape 800x1248 \ + --device cpu \ + --num-iter 1000 \ + --warmup 100 diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/README.md b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/README.md new file mode 100755 index 000000000..f08efe4ff --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/README.md @@ -0,0 +1,82 @@ +# Training Compact CNNs for Image Classification using Dynamic-coded Filter Fusion + +## Abstract + +The mainstream approach for filter pruning is usually either to force a hard-coded importance estimation upon a computation-heavy pretrained model to select “important†filters, or to impose a hyperparameter-sensitive sparse constraint on the loss objective to regularize the network training. In this paper, we present a novel filter pruning method, dubbed dynamic-coded filter fusion (DCFF), to derive compact CNNs in a computationeconomical and regularization-free manner for efficient image classification. Each filter in our DCFF is firstly given an intersimilarity distribution with a temperature parameter as a filter proxy, on top of which, a fresh Kullback-Leibler divergence based dynamic-coded criterion is proposed to evaluate the filter importance. In contrast to simply keeping high-score filters in other methods, we propose the concept of filter fusion, i.e., the weighted averages using the assigned proxies, as our preserved filters. We obtain a one-hot inter-similarity distribution as the temperature parameter approaches infinity. Thus, the relative importance of each filter can vary along with the training of the compact CNN, leading to dynamically changeable fused filters without both the dependency on the pretrained model and the introduction of sparse constraints. Extensive experiments on classification benchmarks demonstrate the superiority of our DCFF over the compared counterparts. For example, our DCFF derives a compact VGGNet-16 with only 72.77M FLOPs and 1.06M parameters while reaching top-1 accuracy of 93.47% on CIFAR-10. A compact ResNet-50 is obtained with 63.8% FLOPs and 58.6% parameter reductions, retaining 75.60% top1 accuracy on ILSVRC-2012. + +![pipeline](https://user-images.githubusercontent.com/31244134/189286581-722853ba-c6d7-4a39-b902-37995b444c71.jpg) + +## Results and models + +### 1. Classification + +| Dataset | Backbone | Params(M) | FLOPs(M) | lr_type | Top-1 (%) | Top-5 (%) | CPrate | Config | Download | +| :------: | :----------: | :-------: | :------: | :-----: | :-------: | :-------: | :---------------------------------------------: | :--------------------------------------------------: | :--------------------------: | +| ImageNet | DCFFResNet50 | 15.16 | 2260 | step | 73.96 | 91.66 | \[0.0\]+\[0.35,0.4,0.1\]\*10+\[0.3,0.3,0.1\]\*6 | [config](../../mmcls/dcff/dcff_resnet_8xb32_in1k.py) | [model](<>) \| \[log\] (\<>) | + +### 2. Detection + +| Dataset | Method | Backbone | Style | Lr schd | Params(M) | FLOPs(M) | bbox AP | CPrate | Config | Download | +| :-----: | :---------: | :----------: | :-----: | :-----: | :-------: | :------: | :-----: | :---------------------------------------------: | :---------------------------------------------------------------: | :--------------------------: | +| COCO | Faster_RCNN | DCFFResNet50 | pytorch | step | 33.31 | 168320 | 35.8 | \[0.0\]+\[0.35,0.4,0.1\]\*10+\[0.3,0.3,0.1\]\*6 | [config](../../mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py) | [model](<>) \| \[log\] (\<>) | + +### 3. Segmentation + +| Dataset | Method | Backbone | crop size | Lr schd | Params(M) | FLOPs(M) | mIoU | CPrate | Config | Download | +| :--------: | :-------: | :-------------: | :-------: | :-----: | :-------: | :------: | :---: | :-----------------------------------------------------------------: | :-------------------------------------------------------------------: | :--------------------------: | +| Cityscapes | PointRend | DCFFResNetV1c50 | 512x1024 | 160k | 18.43 | 74410 | 76.75 | \[0.0, 0.0, 0.0\] + \[0.35, 0.4, 0.1\] * 10 + \[0.3, 0.3, 0.1\] * 6 | [config](../../mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py) | [model](<>) \| \[log\] (\<>) | + +### 4. Pose + +| Dataset | Method | Backbone | crop size | total epochs | Params(M) | FLOPs(M) | AP | CPrate | Config | Download | +| :-----: | :-------------: | :----------: | :-------: | :----------: | :-------: | :------: | :--: | :--------------------------------------------------------: | :---------------------------------------------------------------: | :--------------------------: | +| COCO | TopDown HeatMap | DCFFResNet50 | 256x192 | 300 | 26.95 | 4290 | 68.3 | \[0.0\] + \[0.2, 0.2, 0.1\] * 10 + \[0.15, 0.15, 0.1\] * 6 | [config](../../mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py) | [model](<>) \| \[log\] (\<>) | + +## Citation + +```latex +@article{lin2021training, + title={Training Compact CNNs for Image Classification using Dynamic-coded Filter Fusion}, + author={Lin, Mingbao and Ji, Rongrong and Chen, Bohong and Chao, Fei and Liu, Jianzhuang and Zeng, Wei and Tian, Yonghong and Tian, Qi}, + journal={arXiv preprint arXiv:2107.06916}, + year={2021} +} +``` + +## Get Started + +### Generate channel_config file + +Generate `resnet_pose.json` with `tools/pruning/get_channel_units.py`. + +```bash +python tools/pruning/get_channel_units.py + configs/pruning/mmpose/dcff/dcff_topdown_heatmap_resnet50.py \ + -c -i --output-path=configs/pruning/mmpose/dcff/resnet_pose.json +``` + +Then set layers' pruning rates `target_pruning_ratio` by `resnet_pose.json`. + +### Train DCFF + +#### Pose + +##### COCO + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/pruning/mmpose/dcff/dcff_topdown_heatmap_resnet50.py 4 \ + --work-dir $WORK_DIR +``` + +### Test DCFF + +#### Pose + +##### COCO + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_test.sh \ + configs/pruning/mmpose/dcff/dcff_compact_topdown_heatmap_resnet50.py \ + $CKPT 1 --work-dir $WORK_DIR +``` diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_compact_topdown_heatmap_resnet50_coco.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_compact_topdown_heatmap_resnet50_coco.py new file mode 100755 index 000000000..ba5032379 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_compact_topdown_heatmap_resnet50_coco.py @@ -0,0 +1,12 @@ +_base_ = ['dcff_topdown_heatmap_resnet50_coco.py'] + +# model settings +_base_.model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.architecture, + fix_subnet='configs/pruning/mmpose/dcff/fix_subnet.json', + mode='mutator', + init_cfg=dict( + type='Pretrained', + checkpoint='configs/pruning/mmpose/dcff/fix_subnet_weight.pth')) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py new file mode 100755 index 000000000..d18bccc02 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py @@ -0,0 +1,188 @@ +_base_ = [ + 'mmpose::_base_/default_runtime.py', +] +train_cfg = dict(max_epochs=300, val_interval=10) + +optim_wrapper = dict(optimizer=dict(type='Adam', lr=5e-4), clip_grad=None) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=300, + milestones=[170, 220, 280], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='coco/AP', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +architecture = dict( + type='mmpose.TopdownPoseEstimator', + data_preprocessor=dict( + type='mmpose.PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='mmpose.ResNet', + depth=50, + num_stages=4, + out_indices=(3, ), + ), + head=dict( + type='mmpose.HeatmapHead', + in_channels=1843, + out_channels=17, + loss=dict(type='mmpose.KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +stage_ratio_1 = 0.8 +stage_ratio_2 = 0.8 +stage_ratio_3 = 0.9 +stage_ratio_4 = 0.85 + +# the config template of target_pruning_ratio can be got by +# python ./tools/pruning/get_channel_units.py {config_file} --choice +target_pruning_ratio = { + 'backbone.layer1.0.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.0.conv2_(0, 64)_64': stage_ratio_2, + 'backbone.layer1.0.conv3_(0, 256)_256': stage_ratio_3, + 'backbone.layer1.1.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.1.conv2_(0, 64)_64': stage_ratio_2, + 'backbone.layer1.2.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.2.conv2_(0, 64)_64': stage_ratio_2, + # block 1 [0.8, 0.8] downsample=[0.9] + 'backbone.layer2.0.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.0.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.0.conv3_(0, 512)_512': stage_ratio_3, + 'backbone.layer2.1.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.1.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.2.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.2.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.3.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.3.conv2_(0, 128)_128': stage_ratio_2, + # block 2 [0.8, 0.8] downsample=[0.9] + 'backbone.layer3.0.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.0.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.0.conv3_(0, 1024)_1024': stage_ratio_3, + 'backbone.layer3.1.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.1.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.2.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.2.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.3.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.3.conv2_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.4.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.4.conv2_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.5.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.5.conv2_(0, 256)_256': stage_ratio_4, + # block 3 [0.8, 0.8]*2+[0.8, 0.85]*2 downsample=[0.9] + 'backbone.layer4.0.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv2_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv3_(0, 2048)_2048': stage_ratio_3, + 'backbone.layer4.1.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.1.conv2_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv2_(0, 512)_512': stage_ratio_4 + # block 4 [0.85, 0.85] downsample=[0.9] +} + +model = dict( + _scope_='mmrazor', + type='DCFF', + architecture=architecture, + mutator_cfg=dict( + type='DCFFChannelMutator', + channel_unit_cfg=dict( + type='DCFFChannelUnit', default_args=dict(choice_mode='ratio')), + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer')), + target_pruning_ratio=target_pruning_ratio, + step_freq=1, + linear_schedule=False) + +dataset_type = 'CocoDataset' +data_mode = 'topdown' +data_root = 'data/coco/' + +file_client_args = dict(backend='disk') + +train_pipeline = [ + dict(type='LoadImage', file_client_args=file_client_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', target_type='heatmap', encoder=codec), + dict(type='PackPoseInputs') +] + +test_pipeline = [ + dict(type='LoadImage', file_client_args=file_client_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_train2017.json', + data_prefix=dict(img='train2017/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_val2017.json', + data_prefix=dict(img='val2017/'), + test_mode=True, + bbox_file='data/coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + pipeline=test_pipeline, + )) +test_dataloader = val_dataloader + +model_wrapper = dict( + type='mmcv.MMDistributedDataParallel', find_unused_parameters=True) + +val_evaluator = dict( + type='mmpose.CocoMetric', + ann_file=data_root + 'annotations/person_keypoints_val2017.json') +test_evaluator = val_evaluator + +val_cfg = dict(_delete_=True, type='mmrazor.ItePruneValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/fix_subnet.json b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/fix_subnet.json new file mode 100755 index 000000000..dfdcea758 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/fix_subnet.json @@ -0,0 +1,141 @@ +{ + "type":"DCFFChannelMutator", + "channel_unit_cfg":{ + "type":"DCFFChannelUnit", + "default_args":{ + "choice_mode":"ratio" + }, + "units":{ + "backbone.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":1.0 + }, + "backbone.layer1.0.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.640625 + }, + "backbone.layer1.1.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.640625 + }, + "backbone.layer2.0.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer2.0.conv2_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.59375 + }, + "backbone.layer2.1.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer3.0.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer3.0.conv2_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.59765625 + }, + "backbone.layer3.1.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer4.0.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + }, + "backbone.layer4.0.conv2_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + }, + "backbone.layer4.1.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + } + } + }, + "parse_cfg":{ + "type":"ChannelAnalyzer", + "demo_input":[ + 1, + 3, + 224, + 224 + ], + "tracer_type":"BackwardTracer" + } +} diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_aic-coco-256x192.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_aic-coco-256x192.py new file mode 100755 index 000000000..3c720566f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_aic-coco-256x192.py @@ -0,0 +1,53 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = 'mmpose::body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_aic-coco-256x192.py' # noqa +fix_subnet = { + 'backbone.stem.0.conv_(0, 16)_16': 8, + 'backbone.stem.1.conv_(0, 16)_16': 9, + 'backbone.stem.2.conv_(0, 32)_32': 9, + 'backbone.stage1.0.conv_(0, 64)_64': 32, + 'backbone.stage1.1.short_conv.conv_(0, 32)_32': 30, + 'backbone.stage1.1.main_conv.conv_(0, 32)_32': 29, + 'backbone.stage1.1.blocks.0.conv1.conv_(0, 32)_32': 24, + 'backbone.stage1.1.final_conv.conv_(0, 64)_64': 27, + 'backbone.stage2.0.conv_(0, 128)_128': 62, + 'backbone.stage2.1.short_conv.conv_(0, 64)_64': 63, + 'backbone.stage2.1.main_conv.conv_(0, 64)_64': 64, + 'backbone.stage2.1.blocks.0.conv1.conv_(0, 64)_64': 56, + 'backbone.stage2.1.blocks.1.conv1.conv_(0, 64)_64': 62, + 'backbone.stage2.1.final_conv.conv_(0, 128)_128': 65, + 'backbone.stage3.0.conv_(0, 256)_256': 167, + 'backbone.stage3.1.short_conv.conv_(0, 128)_128': 127, + 'backbone.stage3.1.main_conv.conv_(0, 128)_128': 128, + 'backbone.stage3.1.blocks.0.conv1.conv_(0, 128)_128': 124, + 'backbone.stage3.1.blocks.1.conv1.conv_(0, 128)_128': 123, + 'backbone.stage3.1.final_conv.conv_(0, 256)_256': 172, + 'backbone.stage4.0.conv_(0, 512)_512': 337, + 'backbone.stage4.1.conv1.conv_(0, 256)_256': 256, + 'backbone.stage4.1.conv2.conv_(0, 512)_512': 379, + 'backbone.stage4.2.short_conv.conv_(0, 256)_256': 188, + 'backbone.stage4.2.main_conv.conv_(0, 256)_256': 227, + 'backbone.stage4.2.blocks.0.conv1.conv_(0, 256)_256': 238, + 'backbone.stage4.2.blocks.0.conv2.pointwise_conv.conv_(0, 256)_256': 195, + 'backbone.stage4.2.final_conv.conv_(0, 512)_512': 163 +} +divisor = 8 +############################################################################## + +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_coco-256x192.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_coco-256x192.py new file mode 100755 index 000000000..64fa6c2b6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_coco-256x192.py @@ -0,0 +1,53 @@ +############################################################################# +"""You have to fill these args. + +_base_(str): The path to your pretrain config file. +fix_subnet (Union[dict,str]): The dict store the pruning structure or the + json file including it. +divisor (int): The divisor the make the channel number divisible. +""" + +_base_ = 'mmpose::body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_coco-256x192.py' # noqa +fix_subnet = { + 'backbone.stem.0.conv_(0, 16)_16': 8, + 'backbone.stem.1.conv_(0, 16)_16': 10, + 'backbone.stem.2.conv_(0, 32)_32': 11, + 'backbone.stage1.0.conv_(0, 64)_64': 32, + 'backbone.stage1.1.short_conv.conv_(0, 32)_32': 32, + 'backbone.stage1.1.main_conv.conv_(0, 32)_32': 23, + 'backbone.stage1.1.blocks.0.conv1.conv_(0, 32)_32': 25, + 'backbone.stage1.1.final_conv.conv_(0, 64)_64': 25, + 'backbone.stage2.0.conv_(0, 128)_128': 71, + 'backbone.stage2.1.short_conv.conv_(0, 64)_64': 61, + 'backbone.stage2.1.main_conv.conv_(0, 64)_64': 62, + 'backbone.stage2.1.blocks.0.conv1.conv_(0, 64)_64': 57, + 'backbone.stage2.1.blocks.1.conv1.conv_(0, 64)_64': 59, + 'backbone.stage2.1.final_conv.conv_(0, 128)_128': 69, + 'backbone.stage3.0.conv_(0, 256)_256': 177, + 'backbone.stage3.1.short_conv.conv_(0, 128)_128': 122, + 'backbone.stage3.1.main_conv.conv_(0, 128)_128': 123, + 'backbone.stage3.1.blocks.0.conv1.conv_(0, 128)_128': 125, + 'backbone.stage3.1.blocks.1.conv1.conv_(0, 128)_128': 123, + 'backbone.stage3.1.final_conv.conv_(0, 256)_256': 171, + 'backbone.stage4.0.conv_(0, 512)_512': 351, + 'backbone.stage4.1.conv1.conv_(0, 256)_256': 256, + 'backbone.stage4.1.conv2.conv_(0, 512)_512': 367, + 'backbone.stage4.2.short_conv.conv_(0, 256)_256': 183, + 'backbone.stage4.2.main_conv.conv_(0, 256)_256': 216, + 'backbone.stage4.2.blocks.0.conv1.conv_(0, 256)_256': 238, + 'backbone.stage4.2.blocks.0.conv2.pointwise_conv.conv_(0, 256)_256': 195, + 'backbone.stage4.2.final_conv.conv_(0, 512)_512': 187 +} +divisor = 16 +############################################################################## + +architecture = _base_.model + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherDeploySubModel', + architecture=architecture, + fix_subnet=fix_subnet, + divisor=divisor, +) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.py new file mode 100755 index 000000000..b4fb4f827 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.py @@ -0,0 +1,32 @@ +############################################################################# +"""# You have to fill these args. + +_base_(str): The path to your pruning config file. +pruned_path (str): The path to the checkpoint of the pruned model. +finetune_lr (float): The lr rate to finetune. Usually, we directly use the lr + rate of the pretrain. +""" + +_base_ = './group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.py' # noqa +pruned_path = 'https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.pth' # noqa +finetune_lr = 4e-3 +############################################################################## + +algorithm = _base_.model +algorithm.init_cfg = dict(type='Pretrained', checkpoint=pruned_path) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherSubModel', + algorithm=algorithm, +) + +# restore lr +optim_wrapper = dict(optimizer=dict(lr=finetune_lr)) + +# remove pruning related hooks +custom_hooks = _base_.custom_hooks[:-2] + +# delete ddp +model_wrapper_cfg = None diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.py new file mode 100755 index 000000000..5cc6db15e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.py @@ -0,0 +1,33 @@ +############################################################################# +"""# You have to fill these args. + +_base_(str): The path to your pruning config file. +pruned_path (str): The path to the checkpoint of the pruned model. +finetune_lr (float): The lr rate to finetune. Usually, we directly use the lr + rate of the pretrain. +""" + +_base_ = './group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.py' +pruned_path = 'https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.pth' # noqa +finetune_lr = 4e-3 +############################################################################## + +algorithm = _base_.model +algorithm.init_cfg = dict(type='Pretrained', checkpoint=pruned_path) +# algorithm.update(dict(architecture=dict(test_cfg=dict(flip_test=False), ))) # disable flip test # noqa + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherSubModel', + algorithm=algorithm, +) + +# restore lr +optim_wrapper = dict(optimizer=dict(lr=finetune_lr)) + +# remove pruning related hooks +custom_hooks = _base_.custom_hooks[:-2] + +# delete ddp +model_wrapper_cfg = None diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.py new file mode 100755 index 000000000..14bdc96f5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.py @@ -0,0 +1,75 @@ +############################################################################# +"""You have to fill these args. + +_base_ (str): The path to your pretrained model checkpoint. +pretrained_path (str): The path to your pretrained model checkpoint. + +interval (int): Interval between pruning two channels. You should ensure you + can reach your target pruning ratio when the training ends. +normalization_type (str): GroupFisher uses two methods to normlized the channel + importance, including ['flops','act']. The former uses flops, while the + latter uses the memory occupation of activation feature maps. +lr_ratio (float): Ratio to decrease lr rate. As pruning progress is unstable, + you need to decrease the original lr rate until the pruning training work + steadly without getting nan. + +target_flop_ratio (float): The target flop ratio to prune your model. +input_shape (Tuple): input shape to measure the flops. +""" + +_base_ = 'mmpose::body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_aic-coco-256x192.py' # noqa +pretrained_path = 'https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth' # noqa + +interval = 10 +normalization_type = 'act' +lr_ratio = 0.1 + +target_flop_ratio = 0.51 +input_shape = (1, 3, 256, 192) +############################################################################## + +architecture = _base_.model + +if hasattr(_base_, 'data_preprocessor'): + architecture.update({'data_preprocessor': _base_.data_preprocessor}) + data_preprocessor = None + +architecture.init_cfg = dict(type='Pretrained', checkpoint=pretrained_path) +architecture['_scope_'] = _base_.default_scope + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherAlgorithm', + architecture=architecture, + interval=interval, + mutator=dict( + type='GroupFisherChannelMutator', + parse_cfg=dict(type='ChannelAnalyzer', tracer_type='FxTracer'), + channel_unit_cfg=dict( + type='GroupFisherChannelUnit', + default_args=dict(normalization_type=normalization_type, ), + ), + ), +) + +model_wrapper_cfg = dict( + type='mmrazor.GroupFisherDDP', + broadcast_buffers=False, +) + +optim_wrapper = dict( + optimizer=dict(lr=_base_.optim_wrapper.optimizer.lr * lr_ratio)) + +custom_hooks = getattr(_base_, 'custom_hooks', []) + [ + dict(type='mmrazor.PruningStructureHook'), + dict( + type='mmrazor.ResourceInfoHook', + interval=interval, + demo_input=dict( + type='mmrazor.DefaultDemoInput', + input_shape=input_shape, + ), + save_ckpt_thr=[target_flop_ratio], + ), +] diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.py new file mode 100755 index 000000000..5a998e593 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.py @@ -0,0 +1,75 @@ +############################################################################# +"""You have to fill these args. + +_base_ (str): The path to your pretrained model checkpoint. +pretrained_path (str): The path to your pretrained model checkpoint. + +interval (int): Interval between pruning two channels. You should ensure you + can reach your target pruning ratio when the training ends. +normalization_type (str): GroupFisher uses two methods to normlized the channel + importance, including ['flops','act']. The former uses flops, while the + latter uses the memory occupation of activation feature maps. +lr_ratio (float): Ratio to decrease lr rate. As pruning progress is unstable, + you need to decrease the original lr rate until the pruning training work + steadly without getting nan. + +target_flop_ratio (float): The target flop ratio to prune your model. +input_shape (Tuple): input shape to measure the flops. +""" + +_base_ = 'mmpose::body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_coco-256x192.py' # noqa +pretrained_path = 'https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.pth' # noqa + +interval = 10 +normalization_type = 'act' +lr_ratio = 0.1 + +target_flop_ratio = 0.51 +input_shape = (1, 3, 256, 192) +############################################################################## + +architecture = _base_.model + +if hasattr(_base_, 'data_preprocessor'): + architecture.update({'data_preprocessor': _base_.data_preprocessor}) + data_preprocessor = None + +architecture.init_cfg = dict(type='Pretrained', checkpoint=pretrained_path) +architecture['_scope_'] = _base_.default_scope + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='GroupFisherAlgorithm', + architecture=architecture, + interval=interval, + mutator=dict( + type='GroupFisherChannelMutator', + parse_cfg=dict(type='ChannelAnalyzer', tracer_type='FxTracer'), + channel_unit_cfg=dict( + type='GroupFisherChannelUnit', + default_args=dict(normalization_type=normalization_type, ), + ), + ), +) + +model_wrapper_cfg = dict( + type='mmrazor.GroupFisherDDP', + broadcast_buffers=False, +) + +optim_wrapper = dict( + optimizer=dict(lr=_base_.optim_wrapper.optimizer.lr * lr_ratio)) + +custom_hooks = getattr(_base_, 'custom_hooks', []) + [ + dict(type='mmrazor.PruningStructureHook'), + dict( + type='mmrazor.ResourceInfoHook', + interval=interval, + demo_input=dict( + type='mmrazor.DefaultDemoInput', + input_shape=input_shape, + ), + save_ckpt_thr=[target_flop_ratio], + ), +] diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/script.sh b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/script.sh new file mode 100755 index 000000000..897cd3ac1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/script.sh @@ -0,0 +1,39 @@ +# deploy rtmpose-s_pruned_act + +razor_config=configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_coco-256x192.py +deploy_config=mmdeploy/configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py + +python mmdeploy/tools/deploy.py $deploy_config \ + $razor_config \ + https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.pth \ + mmdeploy/tests/data/tiger.jpeg \ + --work-dir ./work_dirs/mmdeploy + +python mmdeploy/tools/profiler.py $deploy_config \ + $razor_config \ + mmdeploy/demo/resources \ + --model ./work_dirs/mmdeploy/end2end.onnx \ + --shape 256x192 \ + --device cpu \ + --num-iter 1000 \ + --warmup 100 + +# deploy rtmpose-s-aic-coco_pruned_act + +razor_config=configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_aic-coco-256x192.py +deploy_config=mmdeploy/configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py + +python mmdeploy/tools/deploy.py $deploy_config \ + $razor_config \ + https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.pth \ + mmdeploy/tests/data/tiger.jpeg \ + --work-dir ./work_dirs/mmdeploy + +python mmdeploy/tools/profiler.py $deploy_config \ + $razor_config \ + mmdeploy/demo/resources \ + --model ./work_dirs/mmdeploy/end2end.onnx \ + --shape 256x192 \ + --device cpu \ + --num-iter 1000 \ + --warmup 100 diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/README.md b/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/README.md new file mode 100755 index 000000000..fd00eb898 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/README.md @@ -0,0 +1,82 @@ +# Training Compact CNNs for Image Classification using Dynamic-coded Filter Fusion + +## Abstract + +The mainstream approach for filter pruning is usually either to force a hard-coded importance estimation upon a computation-heavy pretrained model to select “important†filters, or to impose a hyperparameter-sensitive sparse constraint on the loss objective to regularize the network training. In this paper, we present a novel filter pruning method, dubbed dynamic-coded filter fusion (DCFF), to derive compact CNNs in a computationeconomical and regularization-free manner for efficient image classification. Each filter in our DCFF is firstly given an intersimilarity distribution with a temperature parameter as a filter proxy, on top of which, a fresh Kullback-Leibler divergence based dynamic-coded criterion is proposed to evaluate the filter importance. In contrast to simply keeping high-score filters in other methods, we propose the concept of filter fusion, i.e., the weighted averages using the assigned proxies, as our preserved filters. We obtain a one-hot inter-similarity distribution as the temperature parameter approaches infinity. Thus, the relative importance of each filter can vary along with the training of the compact CNN, leading to dynamically changeable fused filters without both the dependency on the pretrained model and the introduction of sparse constraints. Extensive experiments on classification benchmarks demonstrate the superiority of our DCFF over the compared counterparts. For example, our DCFF derives a compact VGGNet-16 with only 72.77M FLOPs and 1.06M parameters while reaching top-1 accuracy of 93.47% on CIFAR-10. A compact ResNet-50 is obtained with 63.8% FLOPs and 58.6% parameter reductions, retaining 75.60% top1 accuracy on ILSVRC-2012. + +![pipeline](https://user-images.githubusercontent.com/31244134/189286581-722853ba-c6d7-4a39-b902-37995b444c71.jpg) + +## Results and models + +### 1. Classification + +| Dataset | Backbone | Params(M) | FLOPs(M) | lr_type | Top-1 (%) | Top-5 (%) | CPrate | Config | Download | +| :------: | :----------: | :-------: | :------: | :-----: | :-------: | :-------: | :---------------------------------------------: | :--------------------------------------------------: | :--------------------------: | +| ImageNet | DCFFResNet50 | 15.16 | 2260 | step | 73.96 | 91.66 | \[0.0\]+\[0.35,0.4,0.1\]\*10+\[0.3,0.3,0.1\]\*6 | [config](../../mmcls/dcff/dcff_resnet_8xb32_in1k.py) | [model](<>) \| \[log\] (\<>) | + +### 2. Detection + +| Dataset | Method | Backbone | Style | Lr schd | Params(M) | FLOPs(M) | bbox AP | CPrate | Config | Download | +| :-----: | :---------: | :----------: | :-----: | :-----: | :-------: | :------: | :-----: | :---------------------------------------------: | :---------------------------------------------------------------: | :--------------------------: | +| COCO | Faster_RCNN | DCFFResNet50 | pytorch | step | 33.31 | 168320 | 35.8 | \[0.0\]+\[0.35,0.4,0.1\]\*10+\[0.3,0.3,0.1\]\*6 | [config](../../mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py) | [model](<>) \| \[log\] (\<>) | + +### 3. Segmentation + +| Dataset | Method | Backbone | crop size | Lr schd | Params(M) | FLOPs(M) | mIoU | CPrate | Config | Download | +| :--------: | :-------: | :-------------: | :-------: | :-----: | :-------: | :------: | :---: | :-----------------------------------------------------------------: | :-------------------------------------------------------------------: | :--------------------------: | +| Cityscapes | PointRend | DCFFResNetV1c50 | 512x1024 | 160k | 18.43 | 74410 | 76.75 | \[0.0, 0.0, 0.0\] + \[0.35, 0.4, 0.1\] * 10 + \[0.3, 0.3, 0.1\] * 6 | [config](../../mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py) | [model](<>) \| \[log\] (\<>) | + +### 4. Pose + +| Dataset | Method | Backbone | crop size | total epochs | Params(M) | FLOPs(M) | AP | CPrate | Config | Download | +| :-----: | :-------------: | :----------: | :-------: | :----------: | :-------: | :------: | :--: | :--------------------------------------------------------: | :---------------------------------------------------------------: | :--------------------------: | +| COCO | TopDown HeatMap | DCFFResNet50 | 256x192 | 300 | 26.95 | 4290 | 68.3 | \[0.0\] + \[0.2, 0.2, 0.1\] * 10 + \[0.15, 0.15, 0.1\] * 6 | [config](../../mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py) | [model](<>) \| \[log\] (\<>) | + +## Citation + +```latex +@article{lin2021training, + title={Training Compact CNNs for Image Classification using Dynamic-coded Filter Fusion}, + author={Lin, Mingbao and Ji, Rongrong and Chen, Bohong and Chao, Fei and Liu, Jianzhuang and Zeng, Wei and Tian, Yonghong and Tian, Qi}, + journal={arXiv preprint arXiv:2107.06916}, + year={2021} +} +``` + +## Get Started + +### Generate channel_config file + +Generate `resnet_seg.json` with `tools/pruning/get_channel_units.py`. + +```bash +python tools/pruning/get_channel_units.py + configs/pruning/mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py \ + -c -i --output-path=configs/pruning/mmseg/dcff/resnet_seg.json +``` + +Then set layers' pruning rates `target_pruning_ratio` by `resnet_seg.json`. + +### Train DCFF + +#### Segmentation + +##### Citpscapes + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_train.sh \ + configs/pruning/mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py 4 \ + --work-dir $WORK_DIR +``` + +### Test DCFF + +#### Segmentation + +##### Citpscapes + +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 ./tools/dist_test.sh \ + configs/pruning/mmseg/dcff/dcff_compact_pointrend_resnet50_8xb2_cityscapes.py \ + $CKPT 1 --work-dir $WORK_DIR +``` diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_compact_pointrend_resnet50_8xb2_cityscapes.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_compact_pointrend_resnet50_8xb2_cityscapes.py new file mode 100755 index 000000000..e6c1eb031 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_compact_pointrend_resnet50_8xb2_cityscapes.py @@ -0,0 +1,12 @@ +_base_ = ['dcff_pointrend_resnet50_8xb2_cityscapes.py'] + +# model settings +_base_.model = dict( + _scope_='mmrazor', + type='sub_model', + cfg=_base_.architecture, + fix_subnet='configs/pruning/mmseg/dcff/fix_subnet.json', + mode='mutator', + init_cfg=dict( + type='Pretrained', + checkpoint='configs/pruning/mmseg/dcff/fix_subnet_weight.pth')) diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py new file mode 100755 index 000000000..d552e23e9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py @@ -0,0 +1,99 @@ +_base_ = [ + # TODO: use autoaug pipeline. + 'mmseg::_base_/datasets/cityscapes.py', + 'mmseg::_base_/schedules/schedule_160k.py', + 'mmseg::_base_/default_runtime.py', + './pointrend_resnet50.py' +] + +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='SGD', lr=0.01, momentum=0.9, weight_decay=0.0005), + clip_grad=dict(max_norm=25, norm_type=2), + _delete_=True) +train_cfg = dict(type='IterBasedTrainLoop', max_iters=160000, val_interval=800) + +param_scheduler = [ + # warm up + dict(type='LinearLR', by_epoch=False, start_factor=0.1, begin=0, end=200), + dict( + type='PolyLR', + eta_min=1e-4, + power=0.9, + begin=200, + end=80000, + by_epoch=False, + ) +] + +stage_ratio_1 = 0.65 +stage_ratio_2 = 0.6 +stage_ratio_3 = 0.9 +stage_ratio_4 = 0.7 + +# the config template of target_pruning_ratio can be got by +# python ./tools/pruning/get_channel_units.py {config_file} --choice +target_pruning_ratio = { + 'backbone.layer1.0.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.0.conv2_(0, 64)_64': stage_ratio_2, + 'backbone.layer1.0.conv3_(0, 256)_256': stage_ratio_3, + 'backbone.layer1.1.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.1.conv2_(0, 64)_64': stage_ratio_2, + 'backbone.layer1.2.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.2.conv2_(0, 64)_64': stage_ratio_2, + # block 1 [0.8, 0.8] downsample=[0.9] + 'backbone.layer2.0.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.0.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.0.conv3_(0, 512)_512': stage_ratio_3, + 'backbone.layer2.1.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.1.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.2.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.2.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.3.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.3.conv2_(0, 128)_128': stage_ratio_2, + # block 2 [0.8, 0.8] downsample=[0.9] + 'backbone.layer3.0.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.0.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.0.conv3_(0, 1024)_1024': stage_ratio_3, + 'backbone.layer3.1.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.1.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.2.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.2.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.3.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.3.conv2_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.4.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.4.conv2_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.5.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.5.conv2_(0, 256)_256': stage_ratio_4, + # block 3 [0.8, 0.8]*2+[0.8, 0.85]*2 downsample=[0.9] + 'backbone.layer4.0.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv2_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv3_(0, 2048)_2048': stage_ratio_3, + 'backbone.layer4.1.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.1.conv2_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv2_(0, 512)_512': stage_ratio_4 + # block 4 [0.85, 0.85] downsample=[0.9] +} + +# model settings +model = dict( + _scope_='mmrazor', + type='DCFF', + architecture=_base_.architecture, + mutator_cfg=dict( + type='DCFFChannelMutator', + channel_unit_cfg=dict( + type='DCFFChannelUnit', default_args=dict(choice_mode='ratio')), + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer')), + target_pruning_ratio=target_pruning_ratio, + step_freq=200, + linear_schedule=False) + +model_wrapper = dict( + type='mmcv.MMDistributedDataParallel', find_unused_parameters=True) + +val_cfg = dict(_delete_=True, type='mmrazor.ItePruneValLoop') diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/fix_subnet.json b/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/fix_subnet.json new file mode 100755 index 000000000..dfdcea758 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/fix_subnet.json @@ -0,0 +1,141 @@ +{ + "type":"DCFFChannelMutator", + "channel_unit_cfg":{ + "type":"DCFFChannelUnit", + "default_args":{ + "choice_mode":"ratio" + }, + "units":{ + "backbone.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":1.0 + }, + "backbone.layer1.0.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.640625 + }, + "backbone.layer1.1.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.640625 + }, + "backbone.layer2.0.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer2.0.conv2_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.59375 + }, + "backbone.layer2.1.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer3.0.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer3.0.conv2_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.59765625 + }, + "backbone.layer3.1.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer4.0.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + }, + "backbone.layer4.0.conv2_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + }, + "backbone.layer4.1.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + } + } + }, + "parse_cfg":{ + "type":"ChannelAnalyzer", + "demo_input":[ + 1, + 3, + 224, + 224 + ], + "tracer_type":"BackwardTracer" + } +} diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/pointrend_resnet50.py b/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/pointrend_resnet50.py new file mode 100755 index 000000000..816ec8386 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/pointrend_resnet50.py @@ -0,0 +1,63 @@ +data_preprocessor = dict( + _scope_='mmseg', + type='SegDataPreProcessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True, + size=(512, 1024), + pad_val=0, + seg_pad_val=255) +architecture = dict( + _scope_='mmseg', + type='CascadeEncoderDecoder', + data_preprocessor=data_preprocessor, + num_stages=2, + pretrained=None, + backbone=dict( + type='ResNetV1c', + depth=50, + num_stages=4, + out_indices=(0, 1, 2, 3), + dilations=(1, 1, 1, 1), + strides=(1, 2, 2, 2), + norm_eval=False, + style='pytorch', + contract_dilation=True), + neck=dict( + type='FPN', + in_channels=[256, 512, 1024, 2048], + out_channels=256, + num_outs=4), + decode_head=[ + dict( + type='FPNHead', + in_channels=[256, 256, 256, 256], + in_index=[0, 1, 2, 3], + feature_strides=[4, 8, 16, 32], + channels=128, + dropout_ratio=-1, + num_classes=19, + align_corners=False, + loss_decode=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0)), + dict( + type='PointHead', + in_channels=[256], + in_index=[0], + channels=256, + num_fcs=3, + coarse_pred_each_layer=True, + dropout_ratio=-1, + num_classes=19, + align_corners=False, + loss_decode=dict( + type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0)) + ], + # model training and testing settings + train_cfg=dict( + num_points=2048, oversample_ratio=3, importance_sample_ratio=0.75), + test_cfg=dict( + mode='whole', + subdivision_steps=2, + subdivision_num_points=8196, + scale_factor=2)) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py b/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py new file mode 100755 index 000000000..d1fc673c5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py @@ -0,0 +1,30 @@ +deploy_cfg = dict( + onnx_config=dict( + type='onnx', + export_params=True, + keep_initializers_as_inputs=False, + opset_version=11, + save_file='end2end.onnx', + input_names=['input'], + output_names=['output'], + input_shape=None, + optimize=True, + dynamic_axes={ + 'input': { + 0: 'batch', + 2: 'height', + 3: 'width' + }, + 'output': { + 0: 'batch' + } + }), + backend_config=dict( + type='openvino', + model_inputs=[dict(opt_shapes=dict(input=[1, 3, 224, 224]))]), + codebase_config=dict(type='mmcls', task='Classification'), + function_record_to_pop=[ + 'mmcls.models.classifiers.ImageClassifier.forward', + 'mmcls.models.classifiers.BaseClassifier.forward' + ], +) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py b/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py new file mode 100755 index 000000000..a562c370b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py @@ -0,0 +1,39 @@ +deploy_cfg = dict( + onnx_config=dict( + type='onnx', + export_params=True, + keep_initializers_as_inputs=False, + opset_version=11, + save_file='end2end.onnx', + input_names=['input'], + output_names=['output'], + input_shape=[224, 224], + optimize=True, + dynamic_axes=dict( + input=dict({ + 0: 'batch', + 2: 'height', + 3: 'width' + }), + output=dict({0: 'batch'}))), + codebase_config=dict(type='mmcls', task='Classification'), + backend_config=dict( + type='tensorrt', + common_config=dict( + fp16_mode=False, + max_workspace_size=1073741824, + int8_mode=True, + explicit_quant_mode=True), + model_inputs=[ + dict( + input_shapes=dict( + input=dict( + min_shape=[1, 3, 224, 224], + opt_shape=[4, 3, 224, 224], + max_shape=[8, 3, 224, 224]))) + ]), + function_record_to_pop=[ + 'mmcls.models.classifiers.ImageClassifier.forward', + 'mmcls.models.classifiers.BaseClassifier.forward', 'torch.cat' + ], +) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_openvino_dynamic-800x1344.py b/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_openvino_dynamic-800x1344.py new file mode 100755 index 000000000..c76898d0b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_openvino_dynamic-800x1344.py @@ -0,0 +1,47 @@ +deploy_cfg = dict( + onnx_config=dict( + type='onnx', + export_params=True, + keep_initializers_as_inputs=False, + opset_version=11, + save_file='end2end.onnx', + input_shape=None, + input_names=['input'], + output_names=['dets', 'labels'], + optimize=True, + dynamic_axes={ + 'input': { + 0: 'batch', + 2: 'height', + 3: 'width' + }, + 'dets': { + 0: 'batch', + 1: 'num_dets', + }, + 'labels': { + 0: 'batch', + 1: 'num_dets', + }, + }), + backend_config=dict( + type='openvino', + model_inputs=[dict(opt_shapes=dict(input=[1, 3, 800, 1344]))]), + codebase_config=dict( + type='mmdet', + task='ObjectDetection', + model_type='end2end', + post_processing=dict( + score_threshold=0.05, + confidence_threshold=0.005, # for YOLOv3 + iou_threshold=0.5, + max_output_boxes_per_class=200, + pre_top_k=5000, + keep_top_k=100, + background_label_id=-1, + )), + function_record_to_pop=[ + 'mmdet.models.detectors.single_stage.SingleStageDetector.forward', + 'mmdet.models.detectors.two_stage.TwoStageDetector.forward', + 'mmdet.models.detectors.single_stage_instance_seg.SingleStageInstanceSegmentor.forward' # noqa: E501 + ]) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_tensorrt-int8-explicit_dynamic-320x320-1344x1344.py b/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_tensorrt-int8-explicit_dynamic-320x320-1344x1344.py new file mode 100755 index 000000000..1061d6bd6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_tensorrt-int8-explicit_dynamic-320x320-1344x1344.py @@ -0,0 +1,58 @@ +deploy_cfg = dict( + onnx_config=dict( + type='onnx', + export_params=True, + keep_initializers_as_inputs=False, + opset_version=11, + save_file='end2end.onnx', + input_names=['input'], + output_names=['dets', 'labels'], + input_shape=None, + optimize=True, + dynamic_axes=dict( + input=dict({ + 0: 'batch', + 2: 'height', + 3: 'width' + }), + dets=dict({ + 0: 'batch', + 1: 'num_dets' + }), + labels=dict({ + 0: 'batch', + 1: 'num_dets' + }))), + codebase_config=dict( + type='mmdet', + task='ObjectDetection', + model_type='end2end', + post_processing=dict( + score_threshold=0.05, + confidence_threshold=0.005, + iou_threshold=0.5, + max_output_boxes_per_class=200, + pre_top_k=5000, + keep_top_k=100, + background_label_id=-1)), + backend_config=dict( + type='tensorrt', + common_config=dict( + fp16_mode=False, + max_workspace_size=1073741824, + int8_mode=True, + explicit_quant_mode=True), + model_inputs=[ + dict( + input_shapes=dict( + input=dict( + min_shape=[1, 3, 320, 320], + opt_shape=[1, 3, 800, 1344], + max_shape=[1, 3, 1344, 1344]))) + ]), + function_record_to_pop=[ + 'mmdet.models.detectors.single_stage.SingleStageDetector.forward', + 'mmdet.models.detectors.two_stage.TwoStageDetector.forward', + 'mmdet.models.detectors.single_stage_instance_seg.SingleStageInstanceSegmentor.forward', # noqa: E501 + 'torch.cat' + ]) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/README.md b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/README.md new file mode 100755 index 000000000..1a9f53519 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/README.md @@ -0,0 +1,59 @@ +# Post-Training Quantization (PTQ) + +> [A White Paper on Neural Network Quantization](https://arxiv.org/abs/2106.08295) + + + +## Abstract + +While neural networks have advanced the frontiers in many applications, they often come at a high computational cost. Reducing the power and latency of neural network inference is key if we want to integrate modern networks into edge devices with strict power and compute requirements. Neural network quantization is one of the most effective ways of achieving these savings but the additional noise it induces can lead to accuracy degradation. In this white paper, we introduce state-of-the-art algorithms for mitigating the impact of quantization noise on the network's performance while maintaining low-bit weights and activations. We start with a hardware motivated introduction to quantization and then consider two main classes of algorithms: Post-Training Quantization (PTQ) and Quantization-Aware-Training (QAT). PTQ requires no re-training or labelled data and is thus a lightweight push-button approach to quantization. In most cases, PTQ is sufficient for achieving 8-bit quantization with close to floating-point accuracy. QAT requires fine-tuning and access to labeled training data but enables lower bit quantization with competitive results. For both solutions, we provide tested pipelines based on existing literature and extensive experimentation that lead to state-of-the-art performance for common deep learning models and tasks. + +## Results and models + +### Classification + +| Model | Dataset | Backend | Top 1 Acc(fp32) | Top 1 Acc(int8) | Top 1 Acc(deployed) | Config | Download | +| ------------ | -------- | -------- | --------------- | --------------- | ------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| resnet18 | ImageNet | openvino | 69.90 | 69.742 | 69.74 | [config](./ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py) | [model](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/openvino/ptq_openvino_resnet18_8xb32_in1k_calib32xb32_20230330_163655-2386d965.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/openvino/ptq_openvino_resnet18_8xb32_in1k_calib32xb32_20230330_163655-2386d965.log) | +| resnet50 | ImageNet | openvino | 76.55 | 76.374 | 76.378 | [config](./ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py) | [model](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/openvino/ptq_openvino_resnet50_8xb32_in1k_calib32xb32_20230330_170115-2acd6014.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/openvino/ptq_openvino_resnet50_8xb32_in1k_calib32xb32_20230330_170115-2acd6014.log) | +| mobilenet_v2 | ImageNet | openvino | 71.86 | 70.224 | 70.292 | [config](./ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py) | [model](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/openvino/ptq_openvino_mbv2_8xb32_in1k_calib32xb32_20230330_170909-364822ad.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/openvino/ptq_openvino_mbv2_8xb32_in1k_calib32xb32_20230330_170909-364822ad.log) | +| resnet18 | ImageNet | tensorrt | 69.90 | 69.762 | 69.85 | [config](./ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py) | [model](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/tensorrt/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32_20230331_144323-640b272e.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/tensorrt/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32_20230331_144323-640b272e.log) | +| resnet50 | ImageNet | tensorrt | 76.55 | 76.372 | 76.374 | [config](./ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py) | [model](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/tensorrt/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32_20230331_145011-d2da300f.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/tensorrt/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32_20230331_145011-d2da300f.log) | +| mobilenet_v2 | ImageNet | tensorrt | 71.86 | 70.324 | 70.548 | [config](./ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py) | [model](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/tensorrt/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32_20230331_153131-335988e4.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/quantization/ptq/tensorrt/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32_20230331_153131-335988e4.log) | + +### Detection + +| Model | Dataset | Backend | box AP(fp32) | box AP(int8) | box AP(deployed) | Config | Download | +| -------------- | ------- | -------- | ------------ | ------------ | ---------------- | -------------------------------------------------------------- | ------------------------ | +| retina_r50_fpn | COCO | openvino | 36.5 | 36.3 | 36.3 | [config](./ptq_openvino_retina_r50_1x_coco_calib32xb32.py) | [model](<>) \| [log](<>) | +| yolox_s | COCO | openvino | 40.5 | 38.5 | 38.5 | [config](./ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py) | [model](<>) \| [log](<>) | +| retina_r50_fpn | COCO | tensorrt | 36.5 | 36.2 | 36.3 | [config](./ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py) | [model](<>) \| [log](<>) | +| yolox_s | COCO | tensorrt | 40.5 | 38.8 | 39.3 | [config](./ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py) | [model](<>) \| [log](<>) | + +## Citation + +```latex + @misc{Nagel_Fournarakis_Amjad_Bondarenko_Baalen_Blankevoort_2021, + title={A White Paper on Neural Network Quantization}, + journal={Cornell University - arXiv}, + author={Nagel, Markus and Fournarakis, Marios and Amjad, RanaAli and Bondarenko, Yelysei and Baalen, Martvan and Blankevoort, Tijmen}, + year={2021}, + month={Jun} + } +``` + +## Getting Started + +**PTQ for pretrain model** + +``` +python tools/ptq.py ${CONFIG} +``` + +**Test for quantized model** + +``` +python tools/test.py ${CONFIG} ${CKPT} +``` + +For more details, please refer to [Quantization User Guide](https://mmrazor.readthedocs.io/en/main/user_guides/quantization_user_guide.html) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/metafile.yml b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/metafile.yml new file mode 100755 index 000000000..1ebceab4b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/metafile.yml @@ -0,0 +1,164 @@ +Collections: + - Name: PTQ + README: configs/quantization/ptq/base/README.md +Models: + - Name: ptq_openvino_mbv2_8xb32_in1k_calib32xb32 + In Collection: PTQ + Metadata: + Backend: openvino + Float Model: + Config: mmcls::mobilenet_v2/mobilenet-v2_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/mobilenet_v2/mobilenet_v2_batch256_imagenet_20200708-3b2dc3af.pth + Metrics: + Top 1 Accuracy: 71.86 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 70.224 + Config: configs/quantization/ptq/base/ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/ptq/openvino/ptq_openvino_mbv2_8xb32_in1k_calib32xb32_20230330_170909-364822ad.pth + - Name: ptq_openvino_resnet18_8xb32_in1k_calib32xb32 + In Collection: PTQ + Metadata: + Backend: openvino + Float Model: + Config: mmcls::resnet/resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth + Metrics: + Top 1 Accuracy: 69.90 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 69.742 + Config: configs/quantization/ptq/base/ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/ptq/openvino/ptq_openvino_resnet18_8xb32_in1k_calib32xb32_20230330_163655-2386d965.pth + - Name: ptq_openvino_resnet50_8xb32_in1k_calib32xb32 + In Collection: PTQ + Metadata: + Backend: openvino + Float Model: + Config: mmcls::resnet/resnet50_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth + Metrics: + Top 1 Accuracy: 76.55 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 76.374 + Config: configs/quantization/ptq/base/ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/ptq/openvino/ptq_openvino_resnet50_8xb32_in1k_calib32xb32_20230330_170115-2acd6014.pth + - Name: ptq_openvino_retina_r50_1x_coco_calib32xb32 + In Collection: PTQ + Metadata: + Backend: openvino + Float Model: + Config: mmdet::retinanet/retinanet_r50_fpn_1x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_1x_coco/retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth + Metrics: + box AP: 36.5 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.3 + Config: configs/quantization/ptq/base/ptq_openvino_retina_r50_1x_coco_calib32xb32.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/ptq/openvino/ptq_openvino_retina_r50_1x_coco_calib32xb32_20230330_172645-80eea5b6.pth + - Name: ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32 + In Collection: PTQ + Metadata: + Backend: openvino + Float Model: + Config: mmdet::yolox/yolox_s_8xb8-300e_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/yolox/yolox_s_8x8_300e_coco/yolox_s_8x8_300e_coco_20211121_095711-4592a793.pth + Metrics: + box AP: 40.5 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.5 + Config: configs/quantization/ptq/base/ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/ptq/openvino/ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32_20230330_175747-f1a0a2f4.pth + - Name: ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32 + In Collection: PTQ + Metadata: + Backend: tensorrt + Float Model: + Config: mmcls::mobilenet_v2/mobilenet-v2_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/mobilenet_v2/mobilenet_v2_batch256_imagenet_20200708-3b2dc3af.pth + Metrics: + Top 1 Accuracy: 71.86 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 70.324 + Config: configs/quantization/ptq/base/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/ptq/tensorrt/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32_20230331_153131-335988e4.pth + - Name: ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32 + In Collection: PTQ + Metadata: + Backend: tensorrt + Float Model: + Config: mmcls::resnet/resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth + Metrics: + Top 1 Accuracy: 69.90 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 69.762 + Config: configs/quantization/ptq/base/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/ptq/tensorrt/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32_20230331_144323-640b272e.pth + - Name: ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32 + In Collection: PTQ + Metadata: + Backend: tensorrt + Float Model: + Config: mmcls::resnet/resnet50_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth + Metrics: + Top 1 Accuracy: 76.55 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 76.372 + Config: configs/quantization/ptq/base/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/ptq/tensorrt/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32_20230331_145011-d2da300f.pth + - Name: ptq_tensorrt_retina_r50_1x_coco_calib32xb32 + In Collection: PTQ + Metadata: + Backend: tensorrt + Float Model: + Config: mmdet::retinanet/retinanet_r50_fpn_1x_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_1x_coco/retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth + Metrics: + box AP: 36.5 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 36.2 + Config: configs/quantization/ptq/base/ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/ptq/tensorrt/ptq_tensorrt_retina_r50_1x_coco_calib32xb32_20230330_205741-4c5c10c4.pth + - Name: ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32 + In Collection: PTQ + Metadata: + Backend: tensorrt + Float Model: + Config: mmdet::yolox/yolox_s_8xb8-300e_coco.py + Weights: https://download.openmmlab.com/mmdetection/v2.0/yolox/yolox_s_8x8_300e_coco/yolox_s_8x8_300e_coco_20211121_095711-4592a793.pth + Metrics: + box AP: 40.5 + Results: + - Task: Object Detection + Dataset: COCO + Metrics: + box AP: 38.8 + Config: configs/quantization/ptq/base/ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/ptq/tensorrt/ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32_20230331_155139-f2021e57.pth diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py new file mode 100755 index 000000000..efa2a75dd --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py @@ -0,0 +1,54 @@ +_base_ = [ + 'mmcls::mobilenet_v2/mobilenet-v2_8xb32_in1k.py', + '../../deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py' +] + +_base_.val_dataloader.batch_size = 32 + +test_cfg = dict( + type='mmrazor.PTQLoop', + calibrate_dataloader=_base_.val_dataloader, + calibrate_steps=32, +) + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict( + qdtype='quint8', bit=8, is_symmetry=True, averaging_constant=0.1), +) + +float_checkpoint = 'https://download.openmmlab.com/mmclassification/v0/mobilenet_v2/mobilenet_v2_batch256_imagenet_20200708-3b2dc3af.pth' # noqa: E501 + +model = dict( + _delete_=True, + type='mmrazor.MMArchitectureQuant', + data_preprocessor=dict( + type='mmcls.ClsDataPreprocessor', + num_classes=1000, + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True), + architecture=_base_.model, + deploy_cfg=_base_.deploy_cfg, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.OpenVINOQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmcls.models.heads.ClsHead._get_loss', + 'mmcls.models.heads.ClsHead._get_predictions' + ]))) + +model_wrapper_cfg = dict( + type='mmrazor.MMArchitectureQuantDDP', + broadcast_buffers=False, + find_unused_parameters=True) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py new file mode 100755 index 000000000..b548b15f5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py @@ -0,0 +1,51 @@ +_base_ = [ + 'mmcls::resnet/resnet18_8xb32_in1k.py', + '../../deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py' +] + +_base_.val_dataloader.batch_size = 32 + +test_cfg = dict( + type='mmrazor.PTQLoop', + calibrate_dataloader=_base_.val_dataloader, + calibrate_steps=32, +) + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict( + qdtype='quint8', bit=8, is_symmetry=True, averaging_constant=0.1), +) + +float_checkpoint = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth' # noqa: E501 + +model = dict( + _delete_=True, + type='mmrazor.MMArchitectureQuant', + data_preprocessor=dict( + type='mmcls.ClsDataPreprocessor', + num_classes=1000, + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True), + architecture=_base_.model, + deploy_cfg=_base_.deploy_cfg, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.OpenVINOQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmcls.models.heads.ClsHead._get_loss', + 'mmcls.models.heads.ClsHead._get_predictions' + ]))) + +model_wrapper_cfg = dict(type='mmrazor.MMArchitectureQuantDDP', ) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py new file mode 100755 index 000000000..14802a442 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py @@ -0,0 +1,50 @@ +_base_ = [ + 'mmcls::resnet/resnet50_8xb32_in1k.py', + '../../deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py' +] + +_base_.val_dataloader.batch_size = 32 + +test_cfg = dict( + type='mmrazor.PTQLoop', + calibrate_dataloader=_base_.val_dataloader, + calibrate_steps=32, +) + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict( + qdtype='quint8', bit=8, is_symmetry=True, averaging_constant=0.1), +) + +float_checkpoint = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth' # noqa: E501 + +model = dict( + _delete_=True, + type='mmrazor.MMArchitectureQuant', + data_preprocessor=dict( + type='mmcls.ClsDataPreprocessor', + num_classes=1000, + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True), + architecture=_base_.model, + deploy_cfg=_base_.deploy_cfg, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.OpenVINOQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmcls.models.heads.ClsHead._get_loss', + 'mmcls.models.heads.ClsHead._get_predictions' + ]))) +model_wrapper_cfg = dict(type='mmrazor.MMArchitectureQuantDDP', ) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_retina_r50_1x_coco_calib32xb32.py b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_retina_r50_1x_coco_calib32xb32.py new file mode 100755 index 000000000..e35e6270e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_retina_r50_1x_coco_calib32xb32.py @@ -0,0 +1,52 @@ +_base_ = [ + 'mmdet::retinanet/retinanet_r50_fpn_1x_coco.py', + '../../deploy_cfgs/mmdet/detection_openvino_dynamic-800x1344.py' +] + +_base_.val_dataloader.batch_size = 32 + +test_cfg = dict( + type='mmrazor.PTQLoop', + calibrate_dataloader=_base_.val_dataloader, + calibrate_steps=32, +) + +float_checkpoint = 'https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_1x_coco/retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth' # noqa: E501 + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict(qdtype='quint8', bit=8, is_symmetry=True), +) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='MMArchitectureQuant', + data_preprocessor=dict( + type='mmdet.DetDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True, + pad_size_divisor=32), + architecture=_base_.model, + deploy_cfg=_base_.deploy_cfg, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.OpenVINOQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmdet.models.dense_heads.base_dense_head.BaseDenseHead.predict_by_feat', # noqa: E501 + 'mmdet.models.dense_heads.anchor_head.AnchorHead.loss_by_feat', + ]))) + +model_wrapper_cfg = dict( + type='mmrazor.MMArchitectureQuantDDP', + broadcast_buffers=False, + find_unused_parameters=True) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py new file mode 100755 index 000000000..bab9ed021 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py @@ -0,0 +1,57 @@ +_base_ = [ + 'mmdet::yolox/yolox_s_8xb8-300e_coco.py', + '../../deploy_cfgs/mmdet/detection_openvino_dynamic-800x1344.py' +] + +_base_.val_dataloader.batch_size = 32 + +test_cfg = dict( + type='mmrazor.PTQLoop', + calibrate_dataloader=_base_.val_dataloader, + calibrate_steps=32, +) + +float_checkpoint = 'https://download.openmmlab.com/mmdetection/v2.0/yolox/yolox_s_8x8_300e_coco/yolox_s_8x8_300e_coco_20211121_095711-4592a793.pth' # noqa: E501 + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict(qdtype='quint8', bit=8, is_symmetry=True), +) + +model = dict( + _delete_=True, + type='mmrazor.MMArchitectureQuant', + data_preprocessor=dict( + type='mmdet.DetDataPreprocessor', + pad_size_divisor=32, + batch_augments=[ + dict( + type='mmdet.BatchSyncRandomResize', + random_size_range=(480, 800), + size_divisor=32, + interval=10) + ]), + architecture=_base_.model, + deploy_cfg=_base_.deploy_cfg, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.OpenVINOQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmdet.models.dense_heads.yolox_head.YOLOXHead.predict_by_feat', # noqa: E501 + 'mmdet.models.dense_heads.yolox_head.YOLOXHead.loss_by_feat', + ]))) + +model_wrapper_cfg = dict( + type='mmrazor.MMArchitectureQuantDDP', + broadcast_buffers=False, + find_unused_parameters=True) + +custom_hooks = [] diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py new file mode 100755 index 000000000..68b6d4f97 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py @@ -0,0 +1,54 @@ +_base_ = [ + 'mmcls::mobilenet_v2/mobilenet-v2_8xb32_in1k.py', + '../../deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py' # noqa: E501 +] + +_base_.val_dataloader.batch_size = 32 + +test_cfg = dict( + type='mmrazor.PTQLoop', + calibrate_dataloader=_base_.val_dataloader, + calibrate_steps=32, +) + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, averaging_constant=0.1), +) + +float_checkpoint = 'https://download.openmmlab.com/mmclassification/v0/mobilenet_v2/mobilenet_v2_batch256_imagenet_20200708-3b2dc3af.pth' # noqa: E501 + +model = dict( + _delete_=True, + type='mmrazor.MMArchitectureQuant', + data_preprocessor=dict( + type='mmcls.ClsDataPreprocessor', + num_classes=1000, + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True), + architecture=_base_.model, + deploy_cfg=_base_.deploy_cfg, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.TensorRTQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmcls.models.heads.ClsHead._get_loss', + 'mmcls.models.heads.ClsHead._get_predictions' + ]))) + +model_wrapper_cfg = dict( + type='mmrazor.MMArchitectureQuantDDP', + broadcast_buffers=False, + find_unused_parameters=True) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py new file mode 100755 index 000000000..41d08812c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py @@ -0,0 +1,51 @@ +_base_ = [ + 'mmcls::resnet/resnet18_8xb32_in1k.py', + '../../deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py' # noqa: E501 +] + +_base_.val_dataloader.batch_size = 32 + +test_cfg = dict( + type='mmrazor.PTQLoop', + calibrate_dataloader=_base_.val_dataloader, + calibrate_steps=32, +) + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, averaging_constant=0.1), +) + +float_checkpoint = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth' # noqa: E501 + +model = dict( + _delete_=True, + type='mmrazor.MMArchitectureQuant', + data_preprocessor=dict( + type='mmcls.ClsDataPreprocessor', + num_classes=1000, + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True), + architecture=_base_.model, + deploy_cfg=_base_.deploy_cfg, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.TensorRTQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmcls.models.heads.ClsHead._get_loss', + 'mmcls.models.heads.ClsHead._get_predictions' + ]))) + +model_wrapper_cfg = dict(type='mmrazor.MMArchitectureQuantDDP', ) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py new file mode 100755 index 000000000..e4fa955dc --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py @@ -0,0 +1,51 @@ +_base_ = [ + 'mmcls::resnet/resnet50_8xb32_in1k.py', + '../../deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py' # noqa: E501 +] + +_base_.val_dataloader.batch_size = 32 + +test_cfg = dict( + type='mmrazor.PTQLoop', + calibrate_dataloader=_base_.val_dataloader, + calibrate_steps=32, +) + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, averaging_constant=0.1), +) + +float_checkpoint = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet50_8xb32_in1k_20210831-ea4938fc.pth' # noqa: E501 + +model = dict( + _delete_=True, + type='mmrazor.MMArchitectureQuant', + data_preprocessor=dict( + type='mmcls.ClsDataPreprocessor', + num_classes=1000, + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True), + architecture=_base_.model, + deploy_cfg=_base_.deploy_cfg, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.TensorRTQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmcls.models.heads.ClsHead._get_loss', + 'mmcls.models.heads.ClsHead._get_predictions' + ]))) + +model_wrapper_cfg = dict(type='mmrazor.MMArchitectureQuantDDP', ) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py new file mode 100755 index 000000000..4ca81a920 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py @@ -0,0 +1,53 @@ +_base_ = [ + 'mmdet::retinanet/retinanet_r50_fpn_1x_coco.py', + '../../deploy_cfgs/mmdet/detection_tensorrt-int8-explicit_dynamic-320x320-1344x1344.py' # noqa: E501 +] + +_base_.val_dataloader.batch_size = 32 + +test_cfg = dict( + type='mmrazor.PTQLoop', + calibrate_dataloader=_base_.val_dataloader, + calibrate_steps=32, +) + +float_checkpoint = 'https://download.openmmlab.com/mmdetection/v2.0/retinanet/retinanet_r50_fpn_1x_coco/retinanet_r50_fpn_1x_coco_20200130-c2398f9e.pth' # noqa: E501 + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, averaging_constant=0.1), +) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='MMArchitectureQuant', + data_preprocessor=dict( + type='mmdet.DetDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True, + pad_size_divisor=32), + architecture=_base_.model, + deploy_cfg=_base_.deploy_cfg, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.TensorRTQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmdet.models.dense_heads.base_dense_head.BaseDenseHead.predict_by_feat', # noqa: E501 + 'mmdet.models.dense_heads.anchor_head.AnchorHead.loss_by_feat', + ]))) + +model_wrapper_cfg = dict( + type='mmrazor.MMArchitectureQuantDDP', + broadcast_buffers=False, + find_unused_parameters=True) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py new file mode 100755 index 000000000..51e4f8f11 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py @@ -0,0 +1,58 @@ +_base_ = [ + 'mmdet::yolox/yolox_s_8xb8-300e_coco.py', + '../../deploy_cfgs/mmdet/detection_tensorrt-int8-explicit_dynamic-320x320-1344x1344.py' # noqa: E501 +] + +_base_.val_dataloader.batch_size = 32 + +test_cfg = dict( + type='mmrazor.PTQLoop', + calibrate_dataloader=_base_.val_dataloader, + calibrate_steps=32, +) + +float_checkpoint = 'https://download.openmmlab.com/mmdetection/v2.0/yolox/yolox_s_8x8_300e_coco/yolox_s_8x8_300e_coco_20211121_095711-4592a793.pth' # noqa: E501 + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, averaging_constant=0.1), +) + +model = dict( + _delete_=True, + type='mmrazor.MMArchitectureQuant', + data_preprocessor=dict( + type='mmdet.DetDataPreprocessor', + pad_size_divisor=32, + batch_augments=[ + dict( + type='mmdet.BatchSyncRandomResize', + random_size_range=(480, 800), + size_divisor=32, + interval=10) + ]), + architecture=_base_.model, + deploy_cfg=_base_.deploy_cfg, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.TensorRTQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmdet.models.dense_heads.yolox_head.YOLOXHead.predict_by_feat', # noqa: E501 + 'mmdet.models.dense_heads.yolox_head.YOLOXHead.loss_by_feat', + ]))) + +model_wrapper_cfg = dict( + type='mmrazor.MMArchitectureQuantDDP', + broadcast_buffers=False, + find_unused_parameters=True) + +custom_hooks = [] diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/README.md b/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/README.md new file mode 100755 index 000000000..ec4541eb4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/README.md @@ -0,0 +1,45 @@ +# Quantization-Aware-Training (QAT) + +> [A White Paper on Neural Network Quantization](https://arxiv.org/abs/2106.08295) + + + +## Abstract + +While neural networks have advanced the frontiers in many applications, they often come at a high computational cost. Reducing the power and latency of neural network inference is key if we want to integrate modern networks into edge devices with strict power and compute requirements. Neural network quantization is one of the most effective ways of achieving these savings but the additional noise it induces can lead to accuracy degradation. In this white paper, we introduce state-of-the-art algorithms for mitigating the impact of quantization noise on the network's performance while maintaining low-bit weights and activations. We start with a hardware motivated introduction to quantization and then consider two main classes of algorithms: Post-Training Quantization (PTQ) and Quantization-Aware-Training (QAT). PTQ requires no re-training or labelled data and is thus a lightweight push-button approach to quantization. In most cases, PTQ is sufficient for achieving 8-bit quantization with close to floating-point accuracy. QAT requires fine-tuning and access to labeled training data but enables lower bit quantization with competitive results. For both solutions, we provide tested pipelines based on existing literature and extensive experimentation that lead to state-of-the-art performance for common deep learning models and tasks. + +## Results and models + +### Classification + +| Model | Dataset | Backend | Top 1 Acc(fp32) | Top 1 Acc(int8) | Config | Download | +| -------- | -------- | -------- | --------------- | --------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| resnet18 | ImageNet | openvino | 69.90 | 69.98 | [config](./qat_openvino_resnet18_10e_8xb32_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/quantization/qat/openvino/qat_openvino_resnet18_8xb32_10e_in1k_20230413_172732-5b9ff01d.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/quantization/qat/openvino/qat_openvino_resnet18_8xb32_10e_in1k_20230413_172732-5b9ff01d.log) | + +## Citation + +```latex + @misc{Nagel_Fournarakis_Amjad_Bondarenko_Baalen_Blankevoort_2021, + title={A White Paper on Neural Network Quantization}, + journal={Cornell University - arXiv}, + author={Nagel, Markus and Fournarakis, Marios and Amjad, RanaAli and Bondarenko, Yelysei and Baalen, Martvan and Blankevoort, Tijmen}, + year={2021}, + month={Jun} + } +``` + +## Getting Started + +**QAT for pretrain model** + +``` +python tools/train.py ${CONFIG} +``` + +**Test for quantized model** + +``` +python tools/test.py ${CONFIG} ${CKPT} +``` + +For more details, please refer to [Quantization User Guide](https://mmrazor.readthedocs.io/en/main/user_guides/quantization_user_guide.html) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/metafile.yml b/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/metafile.yml new file mode 100755 index 000000000..bd4015a50 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/metafile.yml @@ -0,0 +1,20 @@ +Collections: + - Name: QAT + README: configs/quantization/qat/base/README.md +Models: + - Name: qat_openvino_resnet18_10e_8xb32_in1k.py + In Collection: QAT + Metadata: + Backend: openvino + Float Model: + Config: mmcls::resnet/resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth + Metrics: + Top 1 Accuracy: 69.90 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 69.98 + Config: configs/quantization/qat/base/qat_openvino_resnet18_10e_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/qat/openvino/qat_openvino_resnet18_8xb32_10e_in1k_20230413_172732-5b9ff01d.pth diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/qat_openvino_resnet18_10e_8xb32_in1k.py b/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/qat_openvino_resnet18_10e_8xb32_in1k.py new file mode 100755 index 000000000..261af7abb --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/qat_openvino_resnet18_10e_8xb32_in1k.py @@ -0,0 +1,62 @@ +_base_ = ['mmcls::resnet/resnet18_8xb32_in1k.py'] + +resnet = _base_.model +float_checkpoint = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth' # noqa: E501 + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict(qdtype='quint8', bit=8, is_symmetry=True), +) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='MMArchitectureQuant', + data_preprocessor=dict( + type='mmcls.ClsDataPreprocessor', + num_classes=1000, + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True), + architecture=resnet, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.OpenVINOQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmcls.models.heads.ClsHead._get_loss', + 'mmcls.models.heads.ClsHead._get_predictions' + ]))) + +optim_wrapper = dict( + optimizer=dict(type='SGD', lr=0.0001, momentum=0.9, weight_decay=0.0001)) + +# learning policy +param_scheduler = dict( + _delete_=True, type='ConstantLR', factor=1.0, by_epoch=True) + +model_wrapper_cfg = dict( + type='mmrazor.MMArchitectureQuantDDP', + broadcast_buffers=False, + find_unused_parameters=False) + +# train, val, test setting +train_cfg = dict( + _delete_=True, + type='mmrazor.QATEpochBasedLoop', + max_epochs=10, + val_interval=1) +val_cfg = dict(_delete_=True, type='mmrazor.QATValLoop') + +# Make sure the buffer such as min_val/max_val in saved checkpoint is the same +# among different rank. +default_hooks = dict(sync=dict(type='SyncBuffersHook')) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/README.md b/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/README.md new file mode 100755 index 000000000..7babfa96e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/README.md @@ -0,0 +1,46 @@ +# Learned Step Size Quantization (LSQ) + +> [Learned Step Size Quantization](https://arxiv.org/abs/1902.08153) + + + +## Abstract + +Deep networks run with low precision operations at inference time offer power and space advantages over high precision alternatives, but need to overcome the challenge of maintaining high accuracy as precision decreases. Here, we present a method for training such networks, Learned Step Size Quantization, that achieves the highest accuracy to date on the ImageNet dataset when using models, from a variety of architectures, with weights and activations quantized to 2-, 3- or 4-bits of precision, and that can train 3-bit models that reach full precision baseline accuracy. Our approach builds upon existing methods for learning weights in quantized networks by improving how the quantizer itself is configured. Specifically, we introduce a novel means to estimate and scale the task loss gradient at each weight and activation layer's quantizer step size, such that it can be learned in conjunction with other network parameters. This approach works using different levels of precision as needed for a given system and requires only a simple modification of existing training code. + +## Results and models + +### Classification + +| Model | Dataset | Backend | Top 1 Acc(fp32) | Top 1 Acc(int8) | Max Epochs | Config | Download | +| -------- | -------- | -------- | --------------- | --------------- | ---------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| resnet18 | ImageNet | openvino | 69.90 | 69.418 | 10 | [config](./lsq_openvino_resnet18_8xb32_10e_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/quantization/qat/openvino/lsq_openvino_resnet18_8xb32_10e_in1k_20230413_224237-36eac1f1.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/quantization/qat/openvino/lsq_openvino_resnet18_8xb32_10e_in1k_20230413_224237-36eac1f1.log) | +| resnet18 | ImageNet | openvino | 69.90 | 69.992 | 100 | [config](./lsq_openvino_resnet18_8xb32_100e_in1k.py) | [model](https://download.openmmlab.com/mmrazor/v1/quantization/qat/openvino/lsq_openvino_resnet18_8xb32_100e_in1k_20230402_173316-ca5993bf.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/quantization/qat/openvino/lsq_openvino_resnet18_8xb32_100e_in1k_20230402_173316-ca5993bf.log) | + +## Citation + +```latex + @misc{Esser_McKinstry_Bablani_Appuswamy_Modha_2019, + title={Learned Step Size Quantization}, + journal={arXiv: Learning}, + author={Esser, StevenK. and McKinstry, JeffreyL. and Bablani, Deepika and Appuswamy, Rathinakumar and Modha, DharmendraS.}, + year={2019}, + month={Feb} + } +``` + +## Getting Started + +**QAT for pretrain model** + +``` +python tools/train.py ${CONFIG} +``` + +**Test for quantized model** + +``` +python tools/test.py ${CONFIG} ${CKPT} +``` + +For more details, please refer to [Quantization User Guide](https://mmrazor.readthedocs.io/en/main/user_guides/quantization_user_guide.html) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_100e_in1k.py b/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_100e_in1k.py new file mode 100755 index 000000000..00e424141 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_100e_in1k.py @@ -0,0 +1,68 @@ +_base_ = ['mmcls::resnet/resnet18_8xb32_in1k.py'] + +resnet = _base_.model +float_checkpoint = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth' # noqa: E501 + +global_qconfig = dict( + w_observer=dict(type='mmrazor.LSQPerChannelObserver'), + a_observer=dict(type='mmrazor.LSQObserver'), + w_fake_quant=dict(type='mmrazor.LearnableFakeQuantize'), + a_fake_quant=dict(type='mmrazor.LearnableFakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict(qdtype='quint8', bit=8, is_symmetry=True), +) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='MMArchitectureQuant', + data_preprocessor=dict( + type='mmcls.ClsDataPreprocessor', + num_classes=1000, + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True), + architecture=resnet, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.OpenVINOQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmcls.models.heads.ClsHead._get_loss', + 'mmcls.models.heads.ClsHead._get_predictions' + ]))) + +optim_wrapper = dict( + optimizer=dict(type='SGD', lr=0.0001, momentum=0.9, weight_decay=0.0001)) + +# learning policy +param_scheduler = dict( + _delete_=True, + type='CosineAnnealingLR', + T_max=100, + by_epoch=True, + begin=0, + end=100) + +model_wrapper_cfg = dict( + type='mmrazor.MMArchitectureQuantDDP', + broadcast_buffers=False, + find_unused_parameters=True) + +# train, val, test setting +train_cfg = dict( + _delete_=True, + type='mmrazor.LSQEpochBasedLoop', + max_epochs=100, + val_interval=1, + freeze_bn_begin=1) +val_cfg = dict(_delete_=True, type='mmrazor.QATValLoop') + +# Make sure the buffer such as min_val/max_val in saved checkpoint is the same +# among different rank. +default_hooks = dict(sync=dict(type='SyncBuffersHook')) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_10e_in1k.py b/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_10e_in1k.py new file mode 100755 index 000000000..f931ddaf5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_10e_in1k.py @@ -0,0 +1,63 @@ +_base_ = ['mmcls::resnet/resnet18_8xb32_in1k.py'] + +resnet = _base_.model +float_checkpoint = 'https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth' # noqa: E501 + +global_qconfig = dict( + w_observer=dict(type='mmrazor.LSQPerChannelObserver'), + a_observer=dict(type='mmrazor.LSQObserver'), + w_fake_quant=dict(type='mmrazor.LearnableFakeQuantize'), + a_fake_quant=dict(type='mmrazor.LearnableFakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict(qdtype='quint8', bit=8, is_symmetry=True), +) + +model = dict( + _delete_=True, + _scope_='mmrazor', + type='MMArchitectureQuant', + data_preprocessor=dict( + type='mmcls.ClsDataPreprocessor', + num_classes=1000, + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True), + architecture=resnet, + float_checkpoint=float_checkpoint, + quantizer=dict( + type='mmrazor.OpenVINOQuantizer', + global_qconfig=global_qconfig, + tracer=dict( + type='mmrazor.CustomTracer', + skipped_methods=[ + 'mmcls.models.heads.ClsHead._get_loss', + 'mmcls.models.heads.ClsHead._get_predictions' + ]))) + +optim_wrapper = dict( + optimizer=dict(type='SGD', lr=0.0001, momentum=0.9, weight_decay=0.0001)) + +# learning policy +param_scheduler = dict( + _delete_=True, type='ConstantLR', factor=1.0, by_epoch=True) + +model_wrapper_cfg = dict( + type='mmrazor.MMArchitectureQuantDDP', + broadcast_buffers=False, + find_unused_parameters=True) + +# train, val, test setting +train_cfg = dict( + _delete_=True, + type='mmrazor.LSQEpochBasedLoop', + max_epochs=10, + val_interval=1, + freeze_bn_begin=1) +val_cfg = dict(_delete_=True, type='mmrazor.QATValLoop') + +# Make sure the buffer such as min_val/max_val in saved checkpoint is the same +# among different rank. +default_hooks = dict(sync=dict(type='SyncBuffersHook')) diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/metafile.yml b/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/metafile.yml new file mode 100755 index 000000000..89308d333 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/metafile.yml @@ -0,0 +1,36 @@ +Collections: + - Name: LSQ + README: configs/quantization/qat/lsq/README.md +Models: + - Name: lsq_openvino_resnet18_8xb32_10e_in1k.py + In Collection: LSQ + Metadata: + Backend: openvino + Float Model: + Config: mmcls::resnet/resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth + Metrics: + Top 1 Accuracy: 69.90 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 69.418 + Config: configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_10e_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/qat/openvino/lsq_openvino_resnet18_8xb32_10e_in1k_20230413_224237-36eac1f1.pth + - Name: lsq_openvino_resnet18_8xb32_100e_in1k.py + In Collection: LSQ + Metadata: + Backend: openvino + Float Model: + Config: mmcls::resnet/resnet18_8xb32_in1k.py + Weights: https://download.openmmlab.com/mmclassification/v0/resnet/resnet18_8xb32_in1k_20210831-fbbb1da6.pth + Metrics: + Top 1 Accuracy: 69.90 + Results: + - Task: Image Classification + Dataset: ImageNet-1k + Metrics: + Top 1 Accuracy: 69.992 + Config: configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_100e_in1k.py + Weights: https://download.openmmlab.com/mmrazor/v1/quantization/qat/openvino/lsq_openvino_resnet18_8xb32_100e_in1k_20230402_173316-ca5993bf.pth diff --git a/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/README.md b/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/README.md new file mode 100755 index 000000000..b32008e7f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/README.md @@ -0,0 +1,34 @@ +# Wide-ResNet + +> [Wide Residual Networks](https://arxiv.org/abs/1605.07146) + + + +## Abstract + +Deep residual networks were shown to be able to scale up to thousands of layers and still have improving performance. However, each fraction of a percent of improved accuracy costs nearly doubling the number of layers, and so training very deep residual networks has a problem of diminishing feature reuse, which makes these networks very slow to train. To tackle these problems, in this paper we conduct a detailed experimental study on the architecture of ResNet blocks, based on which we propose a novel architecture where we decrease depth and increase width of residual networks. We call the resulting network structures wide residual networks (WRNs) and show that these are far superior over their commonly used thin and very deep counterparts. For example, we demonstrate that even a simple 16-layer-deep wide residual network outperforms in accuracy and efficiency all previous deep residual networks, including thousand-layer-deep networks, achieving new state-of-the-art results on CIFAR, SVHN, COCO, and significant improvements on ImageNet. + +
    + +
    + +## Results and models + +### Cifar10 + +| Model | Top-1 (%) | Config | Download | +| :----: | :-------: | :-----------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| WRN-16 | 93.04 | [config](./wrn16-w2_b16x8_cifar10.py) | [model](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/wide_resnet/wrn16_2_b16x8_cifar10_20220831_204709-446b466e.pth) \| [log](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/wide_resnet/wrn16_2_b16x8_cifar10_20220831_204709-446b466e.json) | +| WRN-22 | 94.8700 | [config](./wrn22-w4_b16x8_cifar10.py) | [model](https://download.openmmlab.com/mmrazor/v1/wide_resnet/wrn22-w4_b16x8_cifar10/wrn22-w4_b16x8_cifar10_20221201_170638-1d044c6f.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/wide_resnet/wrn22-w4_b16x8_cifar10/wrn22-w4_b16x8_cifar10_20221201_170638-1d044c6f.json) | +| WRN-28 | 95.41 | [config](./wrn28-w4_b16x8_cifar10.py) | [model](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/wide_resnet/wrn28_4_b16x8_cifar10_20220831_173536-d6f8725c.pth) \| [log](https://openmmlab-share.oss-cn-hangzhou.aliyuncs.com/mmrazor/v1/wide_resnet/wrn28_4_b16x8_cifar10_20220831_173536-d6f8725c.json) | +| WRN-40 | 94.6700 | [config](./wrn40-w2_b16x8_cifar10.py) | [model](https://download.openmmlab.com/mmrazor/v1/wide_resnet/wrn40-w2_b16x8_cifar10/wrn40-w2_b16x8_cifar10_20221201_170318-761c8c55.pth) \| [log](https://download.openmmlab.com/mmrazor/v1/wide_resnet/wrn40-w2_b16x8_cifar10/wrn40-w2_b16x8_cifar10_20221201_170318-761c8c55.json) | + +## Citation + +```bibtex +@INPROCEEDINGS{Zagoruyko2016WRN, + author = {Sergey Zagoruyko and Nikos Komodakis}, + title = {Wide Residual Networks}, + booktitle = {BMVC}, + year = {2016}} +``` diff --git a/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py b/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py new file mode 100755 index 000000000..8a518df4f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py @@ -0,0 +1,7 @@ +_base_ = [ + 'mmcls::_base_/datasets/cifar10_bs16.py', + '../../../_base_/vanilla_models/wrn16_2_cifar10.py', + 'mmcls::_base_/schedules/cifar10_bs128.py', + 'mmcls::_base_/default_runtime.py', +] +test_evaluator = dict(topk=(1, 5)) diff --git a/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn22-w4_b16x8_cifar10.py b/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn22-w4_b16x8_cifar10.py new file mode 100755 index 000000000..7c4888796 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn22-w4_b16x8_cifar10.py @@ -0,0 +1,3 @@ +_base_ = ['wrn16-w2_b16x8_cifar10.py'] +model = dict( + backbone=dict(depth=22, widen_factor=4), head=dict(in_channels=256, )) diff --git a/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py b/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py new file mode 100755 index 000000000..83f0f8153 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py @@ -0,0 +1,3 @@ +_base_ = ['wrn16-w2_b16x8_cifar10.py'] +model = dict( + backbone=dict(depth=28, widen_factor=4), head=dict(in_channels=256, )) diff --git a/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn40-w2_b16x8_cifar10.py b/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn40-w2_b16x8_cifar10.py new file mode 100755 index 000000000..de44e9191 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn40-w2_b16x8_cifar10.py @@ -0,0 +1,3 @@ +_base_ = ['wrn16-w2_b16x8_cifar10.py'] +model = dict( + backbone=dict(depth=40, widen_factor=2), head=dict(in_channels=128, )) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/__init__.py new file mode 100755 index 000000000..fc5acaaeb --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/__init__.py @@ -0,0 +1,27 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import mmcv +import mmengine +from mmengine.utils import digit_version + +from .version import __version__ + +mmcv_minimum_version = '2.0.0rc1' +mmcv_maximum_version = '2.1.0' +mmcv_version = digit_version(mmcv.__version__) + +mmengine_minimum_version = '0.1.0' +mmengine_maximum_version = '1.0.0' +mmengine_version = digit_version(mmengine.__version__) + +assert (mmcv_version >= digit_version(mmcv_minimum_version) + and mmcv_version <= digit_version(mmcv_maximum_version)), \ + f'MMCV=={mmcv.__version__} is used but incompatible. ' \ + f'Please install mmcv>={mmcv_minimum_version}, <={mmcv_maximum_version}.' + +assert (mmengine_version >= digit_version(mmengine_minimum_version) + and mmengine_version < digit_version(mmengine_maximum_version)), \ + f'MMEngine=={mmengine.__version__} is used but incompatible. ' \ + f'Please install mmengine>={mmengine_minimum_version}, ' \ + f'<{mmengine_maximum_version}.' + +__all__ = ['__version__', 'digit_version'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/datasets/__init__.py new file mode 100755 index 000000000..f6eab05e8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/datasets/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .crd_dataset_wrapper import CRDDataset +from .transforms import AutoAugment, AutoAugmentV2, PackCRDClsInputs + +__all__ = ['AutoAugment', 'AutoAugmentV2', 'PackCRDClsInputs', 'CRDDataset'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/crd_dataset_wrapper.py b/cv/distiller/CWD/mmrazor/mmrazor/datasets/crd_dataset_wrapper.py new file mode 100755 index 000000000..aa62f383b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/datasets/crd_dataset_wrapper.py @@ -0,0 +1,254 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import warnings +from typing import Any, Dict, List, Union + +import numpy as np +from mmengine.dataset.base_dataset import BaseDataset, force_full_init + +from mmrazor.registry import DATASETS + + +@DATASETS.register_module() +class CRDDataset: + """A wrapper of `CRD` dataset. + + Suitable for image classification datasets like CIFAR. Following + the sampling strategy in the `paper `_, + in each epoch, each data sample has contrast information. + Contrast information for an image is indices of negetive data samples. + Note: + ``CRDDataset`` should not inherit from ``BaseDataset`` + since ``get_subset`` and ``get_subset_`` could produce ambiguous + meaning sub-dataset which conflicts with original dataset. If you + want to use a sub-dataset of ``CRDDataset``, you should set + ``indices`` arguments for wrapped dataset which inherit from + ``BaseDataset``. + Args: + dataset (BaseDataset or dict): The dataset to be repeated. + neg_num (int): number of negetive data samples. + percent (float): sampling percentage. + lazy_init (bool, optional): whether to load annotation during + instantiation. Defaults to False + num_classes (int, optional): Number of classes. Defaults to None. + sample_mode (str, optional): Data sampling mode. Defaults to 'exact'. + """ + + def __init__(self, + dataset: Union[BaseDataset, dict], + neg_num: int, + percent: float, + lazy_init: bool = False, + num_classes: int = None, + sample_mode: str = 'exact') -> None: + if isinstance(dataset, dict): + self.dataset = DATASETS.build(dataset) + elif isinstance(dataset, BaseDataset): + self.dataset = dataset + else: + raise TypeError( + 'elements in datasets sequence should be config or ' + f'`BaseDataset` instance, but got {type(dataset)}') + self._metainfo = self.dataset.metainfo + + self._fully_initialized = False + + # CRD unique attributes. + self.num_classes = num_classes + self.neg_num = neg_num + self.sample_mode = sample_mode + self.percent = percent + + if not lazy_init: + self.full_init() + + def _parse_fullset_contrast_info(self) -> None: + """parse contrast information of the whole dataset.""" + assert self.sample_mode in [ + 'exact', 'random' + ], ('`sample_mode` must in [`exact`, `random`], ' + f'but get `{self.sample_mode}`') + + # Handle special occasion: + # if dataset's ``CLASSES`` is not list of consecutive integers, + # e.g. [2, 3, 5]. + num_classes: int = self.num_classes # type: ignore + if num_classes is None: + num_classes = max(self.dataset.get_gt_labels()) + 1 + + if not self.dataset.test_mode: # type: ignore + # Parse info. + self.gt_labels = self.dataset.get_gt_labels() + self.num_samples: int = self.dataset.__len__() + + self.cls_positive: List[List[int]] = [[] + for _ in range(num_classes) + ] # type: ignore + for i in range(self.num_samples): + self.cls_positive[self.gt_labels[i]].append(i) + + self.cls_negative: List[List[int]] = [[] + for i in range(num_classes) + ] # type: ignore + for i in range(num_classes): # type: ignore + for j in range(num_classes): # type: ignore + if j == i: + continue + self.cls_negative[i].extend(self.cls_positive[j]) + + self.cls_positive = [ + np.asarray(self.cls_positive[i]) + for i in range(num_classes) # type: ignore + ] + self.cls_negative = [ + np.asarray(self.cls_negative[i]) + for i in range(num_classes) # type: ignore + ] + + if 0 < self.percent < 1: + n = int(len(self.cls_negative[0]) * self.percent) + self.cls_negative = [ + np.random.permutation(self.cls_negative[i])[0:n] + for i in range(num_classes) # type: ignore + ] + + self.cls_positive = np.asarray(self.cls_positive) + self.cls_negative = np.asarray(self.cls_negative) + + @property + def metainfo(self) -> dict: + """Get the meta information of the repeated dataset. + + Returns: + dict: The meta information of repeated dataset. + """ + return copy.deepcopy(self._metainfo) + + def _get_contrast_info(self, data: Dict, idx: int) -> Dict: + """Get contrast information for each data sample.""" + if self.sample_mode == 'exact': + pos_idx = idx + elif self.sample_mode == 'random': + pos_idx = np.random.choice(self.cls_positive[self.gt_labels[idx]], + 1) + pos_idx = pos_idx[0] # type: ignore + else: + raise NotImplementedError(self.sample_mode) + replace = True if self.neg_num > \ + len(self.cls_negative[self.gt_labels[idx]]) else False + neg_idx = np.random.choice( + self.cls_negative[self.gt_labels[idx]], + self.neg_num, + replace=replace) + contrast_sample_idxs = np.hstack((np.asarray([pos_idx]), neg_idx)) + data['contrast_sample_idxs'] = contrast_sample_idxs + return data + + def full_init(self): + """Loop to ``full_init`` each dataset.""" + if self._fully_initialized: + return + + self.dataset.full_init() + self._parse_fullset_contrast_info() + + self._fully_initialized = True + + @force_full_init + def get_data_info(self, idx: int) -> Dict: + """Get annotation by index. + + Args: + idx (int): Global index of ``ConcatDataset``. + Returns: + dict: The idx-th annotation of the dataset. + """ + data_info = self.dataset.get_data_info(idx) # type: ignore + if not self.dataset.test_mode: # type: ignore + data_info = self._get_contrast_info(data_info, idx) + return data_info + + def prepare_data(self, idx) -> Any: + """Get data processed by ``self.pipeline``. + + Args: + idx (int): The index of ``data_info``. + + Returns: + Any: Depends on ``self.pipeline``. + """ + data_info = self.get_data_info(idx) + return self.dataset.pipeline(data_info) + + def __getitem__(self, idx: int) -> dict: + """Get the idx-th image and data information of dataset after + ``self.pipeline``, and ``full_init`` will be called if the dataset has + not been fully initialized. + + During training phase, if ``self.pipeline`` get ``None``, + ``self._rand_another`` will be called until a valid image is fetched or + the maximum limit of refetech is reached. + + Args: + idx (int): The index of self.data_list. + + Returns: + dict: The idx-th image and data information of dataset after + ``self.pipeline``. + """ + # Performing full initialization by calling `__getitem__` will consume + # extra memory. If a dataset is not fully initialized by setting + # `lazy_init=True` and then fed into the dataloader. Different workers + # will simultaneously read and parse the annotation. It will cost more + # time and memory, although this may work. Therefore, it is recommended + # to manually call `full_init` before dataset fed into dataloader to + # ensure all workers use shared RAM from master process. + if not self._fully_initialized: + warnings.warn( + 'Please call `full_init()` method manually to accelerate ' + 'the speed.') + self.full_init() + + if self.dataset.test_mode: + data = self.prepare_data(idx) + if data is None: + raise Exception('Test time pipline should not get `None` ' + 'data_sample') + return data + + for _ in range(self.dataset.max_refetch + 1): + data = self.prepare_data(idx) + # Broken images or random augmentations may cause the returned data + # to be None + if data is None: + idx = self.dataset._rand_another() + continue + return data + + raise Exception( + f'Cannot find valid image after {self.dataset.max_refetch}! ' + 'Please check your image path and pipeline') + + @force_full_init + def __len__(self): + return len(self.dataset) + + def get_subset_(self, indices: Union[List[int], int]) -> None: + """Not supported in ``ClassBalancedDataset`` for the ambiguous meaning + of sub-dataset.""" + raise NotImplementedError( + '`ClassBalancedDataset` dose not support `get_subset` and ' + '`get_subset_` interfaces because this will lead to ambiguous ' + 'implementation of some methods. If you want to use `get_subset` ' + 'or `get_subset_` interfaces, please use them in the wrapped ' + 'dataset first and then use `ClassBalancedDataset`.') + + def get_subset(self, indices: Union[List[int], int]) -> 'BaseDataset': + """Not supported in ``ClassBalancedDataset`` for the ambiguous meaning + of sub-dataset.""" + raise NotImplementedError( + '`ClassBalancedDataset` dose not support `get_subset` and ' + '`get_subset_` interfaces because this will lead to ambiguous ' + 'implementation of some methods. If you want to use `get_subset` ' + 'or `get_subset_` interfaces, please use them in the wrapped ' + 'dataset first and then use `ClassBalancedDataset`.') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/__init__.py new file mode 100755 index 000000000..cf32d3638 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .auto_augment import AutoAugment +from .auto_augmentv2 import AutoAugmentV2 +from .formatting import PackCRDClsInputs + +__all__ = ['AutoAugment', 'AutoAugmentV2', 'PackCRDClsInputs'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augment.py b/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augment.py new file mode 100755 index 000000000..0d2726454 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augment.py @@ -0,0 +1,415 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import math +import random +from typing import Optional + +import numpy as np +import PIL +from mmcv.transforms import BaseTransform +from PIL import Image, ImageEnhance, ImageOps + +from mmrazor.registry import TRANSFORMS + +_PIL_VER = tuple([int(x) for x in PIL.__version__.split('.')[:2]]) + +_FILL = (128, 128, 128) + +# This signifies the max integer that the controller RNN could predict for the +# augmentation scheme. +_MAX_LEVEL = 10. + +_HPARAMS_DEFAULT = dict( + translate_const=250, + img_mean=_FILL, +) + +_RANDOM_INTERPOLATION = (Image.NEAREST, Image.BILINEAR, Image.BICUBIC) + + +def _interpolation(kwargs): + interpolation = kwargs.pop('resample', Image.NEAREST) + if isinstance(interpolation, (list, tuple)): + return random.choice(interpolation) + else: + return interpolation + + +def _check_args_tf(kwargs): + if 'fillcolor' in kwargs and _PIL_VER < (5, 0): + kwargs.pop('fillcolor') + kwargs['resample'] = _interpolation(kwargs) + + +def shear_x(img, factor, **kwargs): + """ShearX images.""" + + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, factor, 0, 0, 1, 0), + **kwargs) + + +def shear_y(img, factor, **kwargs): + """ShearY images.""" + + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, 0, factor, 1, 0), + **kwargs) + + +def translate_x_rel(img, pct, **kwargs): + """TranslateXRel images.""" + + pixels = pct * img.size[0] + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, pixels, 0, 1, 0), + **kwargs) + + +def translate_y_rel(img, pct, **kwargs): + """TranslateYRel images.""" + + pixels = pct * img.size[1] + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, 0, 0, 1, pixels), + **kwargs) + + +def translate_x_abs(img, pixels, **kwargs): + """TranslateX images.""" + + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, pixels, 0, 1, 0), + **kwargs) + + +def translate_y_abs(img, pixels, **kwargs): + """TranslateY images.""" + + _check_args_tf(kwargs) + return img.transform(img.size, Image.AFFINE, (1, 0, 0, 0, 1, pixels), + **kwargs) + + +def rotate(img, degrees, **kwargs): + """Rotate images.""" + + _check_args_tf(kwargs) + if _PIL_VER >= (5, 2): + return img.rotate(degrees, **kwargs) + elif _PIL_VER >= (5, 0): + w, h = img.size + post_trans = (0, 0) + rotn_center = (w / 2.0, h / 2.0) + angle = -math.radians(degrees) + matrix = [ + round(math.cos(angle), 15), + round(math.sin(angle), 15), + 0.0, + round(-math.sin(angle), 15), + round(math.cos(angle), 15), + 0.0, + ] + + def transform(x, y, matrix): + (a, b, c, d, e, f) = matrix + return a * x + b * y + c, d * x + e * y + f + + matrix[2], matrix[5] = transform(-rotn_center[0] - post_trans[0], + -rotn_center[1] - post_trans[1], + matrix) + matrix[2] += rotn_center[0] + matrix[5] += rotn_center[1] + return img.transform(img.size, Image.AFFINE, matrix, **kwargs) + else: + return img.rotate(degrees, resample=kwargs['resample']) + + +def auto_contrast(img, **__): + """AutoContrast images.""" + + return ImageOps.autocontrast(img) + + +def invert(img, **__): + """Invert images.""" + + return ImageOps.invert(img) + + +def equalize(img, **__): + """Equalize images.""" + + return ImageOps.equalize(img) + + +def solarize(img, thresh, **__): + """Solarize images.""" + + return ImageOps.solarize(img, thresh) + + +def solarize_add(img, add, thresh=128, **__): + """SolarizeAdd images.""" + + lut = [] + for i in range(256): + if i < thresh: + lut.append(min(255, i + add)) + else: + lut.append(i) + if img.mode in ('L', 'RGB'): + if img.mode == 'RGB' and len(lut) == 256: + lut = lut + lut + lut + return img.point(lut) + else: + return img + + +def posterize(img, bits_to_keep, **__): + """Posterize images.""" + + if bits_to_keep >= 8: + return img + bits_to_keep = max(1, bits_to_keep) # prevent all 0 images + return ImageOps.posterize(img, bits_to_keep) + + +def contrast(img, factor, **__): + """Contrast images.""" + + return ImageEnhance.Contrast(img).enhance(factor) + + +def color(img, factor, **__): + """Color images.""" + + return ImageEnhance.Color(img).enhance(factor) + + +def brightness(img, factor, **__): + """Brightness images.""" + + return ImageEnhance.Brightness(img).enhance(factor) + + +def sharpness(img, factor, **__): + """Sharpness images.""" + + return ImageEnhance.Sharpness(img).enhance(factor) + + +def _randomly_negate(v): + """With 50% prob, negate the value.""" + return -v if random.random() > 0.5 else v + + +class AutoAugmentOp(BaseTransform): + + def __init__(self, name, prob, magnitude, hparams={}): + NAME_TO_OP = { + 'AutoContrast': auto_contrast, + 'Equalize': equalize, + 'Invert': invert, + 'Rotate': rotate, + 'Posterize': posterize, + 'Posterize2': posterize, + 'Solarize': solarize, + 'SolarizeAdd': solarize_add, + 'Color': color, + 'Contrast': contrast, + 'Brightness': brightness, + 'Sharpness': sharpness, + 'ShearX': shear_x, + 'ShearY': shear_y, + 'TranslateX': translate_x_abs, + 'TranslateY': translate_y_abs, + 'TranslateXRel': translate_x_rel, + 'TranslateYRel': translate_y_rel, + } + self.aug_fn = NAME_TO_OP[name] + self.prob = prob + self.magnitude = magnitude + # If std deviation of magnitude is > 0, we introduce some randomness + # in the usually fixed policy and sample magnitude from normal dist + # with mean magnitude and std-dev of magnitude_std. + # NOTE This is being tested as it's not in paper or reference impl. + self.magnitude_std = 0.5 # FIXME add arg/hparam + self.kwargs = { + 'fillcolor': + hparams['img_mean'] if 'img_mean' in hparams else _FILL, + 'resample': + hparams['interpolation'] + if 'interpolation' in hparams else _RANDOM_INTERPOLATION + } + + self._get_magnitude(name) + + def _get_magnitude(self, name): + if name == 'AutoContrast' or name == 'Equalize' or name == 'Invert': + self.level_fn = self.pass_fn + elif name == 'Rotate': + self.level_fn = self._rotate_level_to_arg + elif name == 'Posterize': + self.level_fn = self._conversion0 + elif name == 'Posterize2': + self.level_fn = self._conversion1 + elif name == 'Solarize': + self.level_fn = self._conversion2 + elif name == 'SolarizeAdd': + self.level_fn = self._conversion3 + elif name in ['Color', 'Contrast', 'Brightness', 'Sharpness']: + self.level_fn = self._enhance_level_to_arg + elif name == 'ShearX' or name == 'ShearY': + self.level_fn = self._shear_level_to_arg + elif name == 'TranslateX' or name == 'TranslateY': + self.level_fn = self._translate_abs_level_to_arg2 + elif name == 'TranslateXRel' or name == 'TranslateYRel': + self.level_fn = self._translate_rel_level_to_arg + else: + print('{} not recognized'.format({})) + + magnitude = self.magnitude + if self.magnitude_std and self.magnitude_std > 0: + magnitude = random.gauss(magnitude, self.magnitude_std) + magnitude = min(_MAX_LEVEL, max(0, magnitude)) + self.level_args = self.level_fn(magnitude) + + def _rotate_level_to_arg(self, level): + # range [-30, 30] + level = (level / _MAX_LEVEL) * 30. + level = _randomly_negate(level) + return (level, ) + + def _enhance_level_to_arg(self, level): + # range [0.1, 1.9] + return ((level / _MAX_LEVEL) * 1.8 + 0.1, ) + + def _shear_level_to_arg(self, level): + # range [-0.3, 0.3] + level = (level / _MAX_LEVEL) * 0.3 + level = _randomly_negate(level) + return (level, ) + + def _translate_abs_level_to_arg2(self, level): + level = (level / _MAX_LEVEL) * float( + _HPARAMS_DEFAULT['translate_const']) + level = _randomly_negate(level) + return (level, ) + + def _translate_rel_level_to_arg(self, level): + # range [-0.45, 0.45] + level = (level / _MAX_LEVEL) * 0.45 + level = _randomly_negate(level) + return (level, ) + + def pass_fn(self, input): + return () + + def _conversion0(self, input): + return (int((input / _MAX_LEVEL) * 4) + 4, ) + + def _conversion1(self, input): + return (4 - int((input / _MAX_LEVEL) * 4), ) + + def _conversion2(self, input): + return (int((input / _MAX_LEVEL) * 256), ) + + def _conversion3(self, input): + return (int((input / _MAX_LEVEL) * 110), ) + + def transform(self, results): + if self.prob < random.random(): + return results + + for key in results.get('img_fields', ['img']): + img = Image.fromarray(results[key]) + img = self.aug_fn(img, *self.level_args, **self.kwargs) + results[key] = np.array(img) + return results + + +@TRANSFORMS.register_module() +class AutoAugment(BaseTransform): + """Auto Augment Implementation adapted from timm: ImageNet + auto_augment_policy is 'original': From TPU EfficientNet impl + https://github.com/rwightman/pytorch-image-models. + + ImageNet auto_augment_policy is 'v0': + A PyTorch implementation of : `AutoAugment: Learning Augmentation + Policies from Data `_ + """ + auto_augment_policy = { + 'original': [ + [('Equalize', 0.8, 1), ('ShearY', 0.8, 4)], + [('Color', 0.4, 9), ('Equalize', 0.6, 3)], + [('Color', 0.4, 1), ('Rotate', 0.6, 8)], + [('Solarize', 0.8, 3), ('Equalize', 0.4, 7)], + [('Solarize', 0.4, 2), ('Solarize', 0.6, 2)], + [('Color', 0.2, 0), ('Equalize', 0.8, 8)], + [('Equalize', 0.4, 8), ('SolarizeAdd', 0.8, 3)], + [('ShearX', 0.2, 9), ('Rotate', 0.6, 8)], + [('Color', 0.6, 1), ('Equalize', 1.0, 2)], + [('Invert', 0.4, 9), ('Rotate', 0.6, 0)], + [('Equalize', 1.0, 9), ('ShearY', 0.6, 3)], + [('Color', 0.4, 7), ('Equalize', 0.6, 0)], + [('Posterize', 0.4, 6), ('AutoContrast', 0.4, 7)], + [('Solarize', 0.6, 8), ('Color', 0.6, 9)], + [('Solarize', 0.2, 4), ('Rotate', 0.8, 9)], + [('Rotate', 1.0, 7), ('TranslateYRel', 0.8, 9)], + [('ShearX', 0.0, 0), ('Solarize', 0.8, 4)], + [('ShearY', 0.8, 0), ('Color', 0.6, 4)], + [('Color', 1.0, 0), ('Rotate', 0.6, 2)], + [('Equalize', 0.8, 4), ('Equalize', 0.0, 8)], + [('Equalize', 1.0, 4), ('AutoContrast', 0.6, 2)], + [('ShearY', 0.4, 7), ('SolarizeAdd', 0.6, 7)], + [('Posterize', 0.8, 2), ('Solarize', 0.6, 10)], + [('Solarize', 0.6, 8), ('Equalize', 0.6, 1)], + [('Color', 0.8, 6), ('Rotate', 0.4, 5)], + ], + 'v0': [ + [('Posterize', 0.4, 8), ('Rotate', 0.6, 9)], + [('Solarize', 0.6, 5), ('AutoContrast', 0.6, 5)], + [('Equalize', 0.8, 8), ('Equalize', 0.6, 3)], + [('Posterize', 0.6, 7), ('Posterize', 0.6, 6)], + [('Equalize', 0.4, 7), ('Solarize', 0.2, 4)], + [('Equalize', 0.4, 4), ('Rotate', 0.8, 8)], + [('Solarize', 0.6, 3), ('Equalize', 0.6, 7)], + [('Posterize', 0.8, 5), ('Equalize', 1.0, 2)], + [('Rotate', 0.2, 3), ('Solarize', 0.6, 8)], + [('Equalize', 0.6, 8), ('Posterize', 0.4, 6)], + [('Rotate', 0.8, 8), ('Color', 0.4, 0)], + [('Rotate', 0.4, 9), ('Equalize', 0.6, 2)], + [('Equalize', 0.0, 7), ('Equalize', 0.8, 8)], + [('Invert', 0.6, 4), ('Equalize', 1.0, 8)], + [('Color', 0.6, 4), ('Contrast', 1.0, 8)], + [('Rotate', 0.8, 8), ('Color', 1.0, 2)], + [('Color', 0.8, 8), ('Solarize', 0.8, 7)], + [('Sharpness', 0.4, 7), ('Invert', 0.6, 8)], + [('ShearX', 0.6, 5), ('Equalize', 1.0, 9)], + [('Color', 0.4, 0), ('Equalize', 0.6, 3)], + [('Equalize', 0.4, 7), ('Solarize', 0.2, 4)], + [('Solarize', 0.6, 5), ('AutoContrast', 0.6, 5)], + [('Invert', 0.6, 4), ('Equalize', 1.0, 8)], + [('Color', 0.6, 4), ('Contrast', 1.0, 8)], + [('Equalize', 0.8, 8), ('Equalize', 0.6, 3)], + ] + } + + def __init__(self, policies: str = 'original', extra_params: dict = None): + self.policies = copy.deepcopy(self.auto_augment_policy[policies]) + extra_params = extra_params if extra_params else dict( + translate_const=250, img_mean=_FILL) + self.sub_policy = [[AutoAugmentOp(*a, extra_params) for a in sp] + for sp in self.policies] + + def transform(self, results: dict) -> Optional[dict]: + sub_policy = random.choice(self.sub_policy) + for op in sub_policy: + results = op(results) + return results + + def __repr__(self) -> str: + repr_str = self.__class__.__name__ + repr_str += f'(policies={self.policies})' + return repr_str diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augmentv2.py b/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augmentv2.py new file mode 100755 index 000000000..60d5647ed --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augmentv2.py @@ -0,0 +1,540 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import math +import random + +import numpy as np +import PIL +from mmcv.transforms import Compose +from PIL import Image, ImageEnhance, ImageOps + +from mmrazor.registry import TRANSFORMS + +_PIL_VER = tuple([int(x) for x in PIL.__version__.split('.')[:2]]) + +_FILL = (128, 128, 128) + +# This signifies the max integer that the controller RNN could predict for the +# augmentation scheme. +_MAX_LEVEL = 10. + +_HPARAMS_DEFAULT = dict( + translate_const=250, + img_mean=_FILL, +) + +_interpolation_name_to_pil = { + 'bilinear': Image.BILINEAR, + 'bicubic': Image.BICUBIC, + 'nearest': Image.NEAREST, +} + + +@TRANSFORMS.register_module() +class AutoAugmentOp(object): + """Base class for ops of autoaugment.""" + + def __init__(self, prob, magnitude, extra_params: dict): + self.prob = prob + self.magnitude = magnitude + self.magnitude_std = 0.5 + + self.kwargs = { + 'fillcolor': + extra_params['img_mean'] + if 'img_mean' in extra_params else _FILL, # noqa: E501 + 'resample': + extra_params['interpolation'] if 'interpolation' in extra_params + else _interpolation_name_to_pil.values() # noqa: E501,E131 + } + self._get_magnitude() + + def __call__(self, results): + return results + + def _interpolation(self, kwargs): + interpolation = kwargs.pop('resample', Image.NEAREST) + if isinstance(interpolation, (list, tuple)): + return random.choice(interpolation) + else: + return interpolation + + def _check_args_tf(self, kwargs): + if 'fillcolor' in kwargs and _PIL_VER < (5, 0): + kwargs.pop('fillcolor') + kwargs['resample'] = self._interpolation(kwargs) + + def _get_magnitude(self): + magnitude = self.magnitude + if self.magnitude_std and self.magnitude_std > 0: + magnitude = random.gauss(magnitude, self.magnitude_std) + magnitude = min(_MAX_LEVEL, max(0, magnitude)) + self.magnitude = magnitude + + def _randomly_negate(self, v): + """With 50% prob, negate the value.""" + return -v if random.random() > 0.5 else v + + def _rotate_level_to_arg(self, level): + # range [-30, 30] + level = (level / _MAX_LEVEL) * 30. + level = self._randomly_negate(level) + return (level, ) + + def _enhance_level_to_arg(self, level): + # range [0.1, 1.9] + return ((level / _MAX_LEVEL) * 1.8 + 0.1, ) + + def _shear_level_to_arg(self, level): + # range [-0.3, 0.3] + level = (level / _MAX_LEVEL) * 0.3 + level = self._randomly_negate(level) + return (level, ) + + def _translate_abs_level_to_arg(self, level): + level = (level / _MAX_LEVEL) * \ + float(_HPARAMS_DEFAULT['translate_const']) + level = self._randomly_negate(level) + return (level, ) + + def _translate_rel_level_to_arg(self, level): + # range [-0.45, 0.45] + level = (level / _MAX_LEVEL) * 0.45 + level = self._randomly_negate(level) + return (level, ) + + +@TRANSFORMS.register_module() +class ShearX(AutoAugmentOp): + """ShearX images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_fn = self._shear_level_to_arg + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **kwargs): + if self.prob < random.random(): + return results + factor = self.level_args[0] + self._check_args_tf(kwargs) + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + img = img.transform(img.size, Image.AFFINE, + (1, factor, 0, 0, 1, 0), **kwargs) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class ShearY(AutoAugmentOp): + """ShearY images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_fn = self._shear_level_to_arg + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **kwargs): + if self.prob < random.random(): + return results + factor = self.level_args[0] + self._check_args_tf(kwargs) + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + img = img.transform(img.size, Image.AFFINE, + (1, 0, 0, factor, 1, 0), **kwargs) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class TranslateXRel(AutoAugmentOp): + """TranslateXRel images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_fn = self._translate_rel_level_to_arg + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **kwargs): + if self.prob < random.random(): + return results + self._check_args_tf(kwargs) + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + pixels = self.level_args[0] * img.size[0] + img = img.transform(img.size, Image.AFFINE, + (1, 0, pixels, 0, 1, 0), **kwargs) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class TranslateYRel(AutoAugmentOp): + """TranslateYRel images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_fn = self._translate_rel_level_to_arg + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **kwargs): + if self.prob < random.random(): + return results + self._check_args_tf(kwargs) + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + pixels = self.level_args[0] * img.size[1] + img = img.transform(img.size, Image.AFFINE, + (1, 0, 0, 0, 1, pixels), **kwargs) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class TranslateX(AutoAugmentOp): + """TranslateX images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_fn = self._translate_abs_level_to_arg + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **kwargs): + if self.prob < random.random(): + return results + self._check_args_tf(kwargs) + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + pixels = self.level_args[0] + img = img.transform(img.size, Image.AFFINE, + (1, 0, pixels, 0, 1, 0), **kwargs) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class TranslateY(AutoAugmentOp): + """TranslateY images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_fn = self._translate_abs_level_to_arg + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **kwargs): + if self.prob < random.random(): + return results + self._check_args_tf(kwargs) + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + pixels = self.level_args[0] + img = img.transform(img.size, Image.AFFINE, + (1, 0, 0, 0, 1, pixels), **kwargs) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class RotateV2(AutoAugmentOp): + """Rotate images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_fn = self._rotate_level_to_arg + self.level_args = self.level_fn(self.magnitude) + + def transform(self, x, y, matrix): + (a, b, c, d, e, f) = matrix + return a * x + b * y + c, d * x + e * y + f + + def __call__(self, results, **kwargs): + if self.prob < random.random(): + return results + degrees = self.level_args[0] + self._check_args_tf(kwargs) + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + if _PIL_VER >= (5, 2): + img = img.rotate(degrees, **kwargs) + elif _PIL_VER >= (5, 0): + w, h = img.size + post_trans = (0, 0) + rotn_center = (w / 2.0, h / 2.0) + angle = -math.radians(degrees) + matrix = [ + round(math.cos(angle), 15), + round(math.sin(angle), 15), + 0.0, + round(-math.sin(angle), 15), + round(math.cos(angle), 15), + 0.0, + ] + matrix[2], matrix[5] = self.transform( + -rotn_center[0] - post_trans[0], + -rotn_center[1] - post_trans[1], matrix) + matrix[2] += rotn_center[0] + matrix[5] += rotn_center[1] + img = img.transform(img.size, Image.AFFINE, matrix, **kwargs) + else: + img = img.rotate(degrees, resample=kwargs['resample']) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class AutoContrastV2(AutoAugmentOp): + """AutoContrast images.""" + + def __call__(self, results, **__): + if self.prob < random.random(): + return results + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + img = ImageOps.autocontrast(img) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class InvertV2(AutoAugmentOp): + """Invert images.""" + + def __call__(self, results, **__): + if self.prob < random.random(): + return results + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + img = ImageOps.invert(img) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class EqualizeV2(AutoAugmentOp): + """Equalize images.""" + + def __call__(self, results, **__): + if self.prob < random.random(): + return results + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + img = ImageOps.equalize(img) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class SolarizeV2(AutoAugmentOp): + """Solarize images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **__): + if self.prob < random.random(): + return results + thresh = self.level_args[0] + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + img = ImageOps.solarize(img, thresh) + img = np.array(img) + results[key] = img + return results + + def level_fn(self, input): + return (int((input / _MAX_LEVEL) * 256), ) + + +@TRANSFORMS.register_module() +class SolarizeAddV2(AutoAugmentOp): + """SolarizeAdd images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **__): + if self.prob < random.random(): + return results + thresh = 128 + add = self.level_args[0] + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + lut = [] + for i in range(256): + if i < thresh: + lut.append(min(255, i + add)) + else: + lut.append(i) + if img.mode in ('L', 'RGB'): + if img.mode == 'RGB' and len(lut) == 256: + lut = lut + lut + lut + img = img.point(lut) + img = np.array(img) + results[key] = img + return results + + def level_fn(self, input): + return (int((input / _MAX_LEVEL) * 110), ) + + +@TRANSFORMS.register_module() +class PosterizeV2(AutoAugmentOp): + """Posterize images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **__): + if self.prob < random.random(): + return results + bits_to_keep = self.level_args[0] + if bits_to_keep >= 8: + return results + bits_to_keep = max(1, bits_to_keep) # prevent all 0 images + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + img = ImageOps.posterize(img, bits_to_keep) + img = np.array(img) + results[key] = img + return results + + def level_fn(self, input): + return (int((input / _MAX_LEVEL) * 4) + 4, ) + + +@TRANSFORMS.register_module() +class ContrastV2(AutoAugmentOp): + """Contrast images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_fn = self._enhance_level_to_arg + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **__): + if self.prob < random.random(): + return results + factor = self.level_args[0] + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + img = ImageEnhance.Contrast(img).enhance(factor) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class Color(AutoAugmentOp): + """Color images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_fn = self._enhance_level_to_arg + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **__): + if self.prob < random.random(): + return results + factor = self.level_args[0] + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + img = ImageEnhance.Color(img).enhance(factor) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class BrightnessV2(AutoAugmentOp): + """Brightness images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_fn = self._enhance_level_to_arg + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **__): + if self.prob < random.random(): + return results + factor = self.level_args[0] + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + img = ImageEnhance.Brightness(img).enhance(factor) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class SharpnessV2(AutoAugmentOp): + """Sharpness images.""" + + def __init__(self, prob, magnitude, extra_params: dict): + super().__init__(prob, magnitude, extra_params) + self.level_fn = self._enhance_level_to_arg + self.level_args = self.level_fn(self.magnitude) + + def __call__(self, results, **__): + if self.prob < random.random(): + return results + factor = self.level_args[0] + for key in results.get('img_fields', ['img']): + img = results[key] + img = Image.fromarray(img) + img = ImageEnhance.Sharpness(img).enhance(factor) + img = np.array(img) + results[key] = img + return results + + +@TRANSFORMS.register_module() +class AutoAugmentV2(object): + """Auto Augment Implementation adapted from timm: + + https://github.com/rwightman/pytorch-image-models + """ + + def __init__(self, policies): + self.policies = copy.deepcopy(policies) + self.sub_policy = [Compose(policy) for policy in self.policies] + + def __call__(self, results): + sub_policy = random.choice(self.sub_policy) + results = sub_policy(results) + return results + + def __repr__(self) -> str: + repr_str = self.__class__.__name__ + repr_str += f'(policies={self.policies})' + return repr_str diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/formatting.py b/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/formatting.py new file mode 100755 index 000000000..d2ba63ddc --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/formatting.py @@ -0,0 +1,73 @@ +# Copyright (c) OpenMMLab. All rights reserved. +try: + from mmcls.datasets.transforms.formatting import PackClsInputs, to_tensor + from mmcls.structures import ClsDataSample +except ImportError: + from mmrazor.utils import get_placeholder + PackClsInputs = get_placeholder('mmcls') + to_tensor = get_placeholder('mmcls') + ClsDataSample = get_placeholder('mmcls') + +import warnings +from typing import Any, Dict, Generator + +import numpy as np +import torch + +from mmrazor.registry import TRANSFORMS + + +@TRANSFORMS.register_module() +class PackCRDClsInputs(PackClsInputs): + + def transform(self, results: Dict) -> Dict: + """Method to pack the input data. + + Args: + results (dict): Result dict from the data pipeline. + + Returns: + dict: + - 'inputs' (obj:`torch.Tensor`): The forward data of models. + - 'data_sample' (obj:`ClsDataSample`): The annotation info of the + sample. + """ + packed_results = dict() + if 'img' in results: + img = results['img'] + if len(img.shape) < 3: + img = np.expand_dims(img, -1) + img = np.ascontiguousarray(img.transpose(2, 0, 1)) + packed_results['inputs'] = to_tensor(img) + else: + warnings.warn( + 'Cannot get "img" in the input dict of `PackClsInputs`,' + 'please make sure `LoadImageFromFile` has been added ' + 'in the data pipeline or images have been loaded in ' + 'the dataset.') + + data_sample = ClsDataSample() + if 'gt_label' in results: + gt_label = results['gt_label'] + data_sample.set_gt_label(gt_label) + + if 'sample_idx' in results: + # transfer `sample_idx` to Tensor + self.meta_keys: Generator[Any, None, None] = ( + key for key in self.meta_keys if key != 'sample_idx') + value = results['sample_idx'] + if isinstance(value, int): + value = torch.tensor(value).to(torch.long) + data_sample.set_data(dict(sample_idx=value)) + + if 'contrast_sample_idxs' in results: + value = results['contrast_sample_idxs'] + if isinstance(value, np.ndarray): + value = torch.from_numpy(value).to(torch.long) + data_sample.set_data(dict(contrast_sample_idxs=value)) + + img_meta = {k: results[k] for k in self.meta_keys if k in results} + data_sample.set_metainfo(img_meta) + packed_results['data_samples'] = data_sample + + return packed_results diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/__init__.py new file mode 100755 index 000000000..8b0d4a692 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/__init__.py @@ -0,0 +1,19 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .hooks import (DMCPSubnetHook, DumpSubnetHook, EstimateResourcesHook, + StopDistillHook) +from .optimizers import SeparateOptimWrapperConstructor +from .runner import (AutoSlimGreedySearchLoop, DartsEpochBasedTrainLoop, + DartsIterBasedTrainLoop, EvolutionSearchLoop, + GreedySamplerTrainLoop, LSQEpochBasedLoop, PTQLoop, + QATEpochBasedLoop, QATValLoop, SelfDistillValLoop, + SingleTeacherDistillValLoop, SlimmableValLoop, + SubnetValLoop) + +__all__ = [ + 'DMCPSubnetHook', 'StopDistillHook', 'SeparateOptimWrapperConstructor', + 'DumpSubnetHook', 'SingleTeacherDistillValLoop', + 'DartsEpochBasedTrainLoop', 'DartsIterBasedTrainLoop', 'SlimmableValLoop', + 'EvolutionSearchLoop', 'GreedySamplerTrainLoop', 'EstimateResourcesHook', + 'SelfDistillValLoop', 'AutoSlimGreedySearchLoop', 'SubnetValLoop', + 'PTQLoop', 'QATEpochBasedLoop', 'LSQEpochBasedLoop', 'QATValLoop' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/__init__.py new file mode 100755 index 000000000..ce8e8348a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/__init__.py @@ -0,0 +1,11 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .dmcp_subnet_hook import DMCPSubnetHook +from .dump_subnet_hook import DumpSubnetHook +from .estimate_resources_hook import EstimateResourcesHook +from .stop_distillation_hook import StopDistillHook +from .visualization_hook import RazorVisualizationHook + +__all__ = [ + 'DumpSubnetHook', 'EstimateResourcesHook', 'RazorVisualizationHook', + 'DMCPSubnetHook', 'StopDistillHook' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dmcp_subnet_hook.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dmcp_subnet_hook.py new file mode 100755 index 000000000..5c3186fca --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dmcp_subnet_hook.py @@ -0,0 +1,74 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import json +import os + +from mmengine.hooks import Hook +from mmengine.registry import HOOKS + +from mmrazor.structures import export_fix_subnet + + +@HOOKS.register_module() +class DMCPSubnetHook(Hook): + """Dump subnet periodically. + + Args: + subnet_sample_num (int):The number of networks sampled, + the last of which is the sub-network sampled in ``expected`` + mode and the others are sampled in ``direct`` mode. + Defaults to 10. + """ + + priority = 'VERY_LOW' + + def __init__(self, subnet_sample_num: int = 10, **kwargs) -> None: + self.subnet_sample_num = subnet_sample_num + + def _save_subnet(self, model, runner, save_path): + """Save the sampled sub-network config.""" + fix_subnet, _ = export_fix_subnet( + model, + export_subnet_mode='mutator', + slice_weight=True, + ) + fix_subnet = json.dumps(fix_subnet, indent=4, separators=(',', ':')) + with open(save_path, 'w') as file: + file.write(fix_subnet) + + runner.logger.info('export finished and ' + f'{save_path} saved in {runner.work_dir}.') + + def after_run(self, runner): + """Save the sampled subnet under target FLOPs. + + Args: + runner (Runner): The runner of the training process. + """ + model = getattr(runner.model, 'module', runner.model) + runner.logger.info('Sampling...') + + num_sample = self.subnet_sample_num + root_dir = os.path.join(runner.work_dir, 'model_sample') + target_flops = model.target_flops * 1e6 + + if not os.path.exists(root_dir): + os.makedirs(root_dir) + + for i in range(num_sample + 1): + cur_flops = target_flops * 10 + while cur_flops > target_flops * 1.05 or \ + cur_flops < target_flops * 0.95: + model.set_subnet(mode='direct', arch_train=False) + cur_flops = model.calc_current_flops() + + if i == num_sample: + model.set_subnet(mode='expected', arch_train=False) + save_path = os.path.join(root_dir, 'excepted_ch.json') + runner.logger.info( + f'Excepted sample(ES) arch with FlOP(MB):{cur_flops}') + else: + save_path = os.path.join(root_dir, + 'subnet_{}.json'.format(i + 1)) + runner.logger.info( + f'Driect sample(DS) arch with FlOP(MB): {cur_flops/1e6}') + self._save_subnet(model, runner, save_path) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dump_subnet_hook.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dump_subnet_hook.py new file mode 100755 index 000000000..1aaeaba0f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dump_subnet_hook.py @@ -0,0 +1,169 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os.path as osp +from pathlib import Path +from typing import Optional, Sequence, Union + +from mmengine.dist import master_only +from mmengine.fileio import FileClient, dump +from mmengine.hooks import Hook +from mmengine.registry import HOOKS + +from mmrazor.models.mutables.base_mutable import BaseMutable +from mmrazor.structures import convert_fix_subnet, export_fix_subnet + +DATA_BATCH = Optional[Sequence[dict]] + + +@HOOKS.register_module() +class DumpSubnetHook(Hook): + """Dump subnet periodically. + + Args: + interval (int): The saving period. If ``by_epoch=True``, interval + indicates epochs, otherwise it indicates iterations. + Defaults to -1, which means "never". + by_epoch (bool): Saving checkpoints by epoch or by iteration. + Default: True. + out_dir (str, optional | Path): The root directory to save checkpoints. + If not specified, ``runner.work_dir`` will be used by default. If + specified, the ``out_dir`` will be the concatenation of ``out_dir`` + and the last level directory of ``runner.work_dir``. For example, + if the input ``our_dir`` is ``./tmp`` and ``runner.work_dir`` is + ``./work_dir/cur_exp``, then the ckpt will be saved in + ``./tmp/cur_exp``. Defaults to None. + max_keep_subnets (int): The maximum subnets to keep. + In some cases we want only the latest few subnets and would + like to delete old ones to save the disk space. + Defaults to -1, which means unlimited. + save_last (bool): Whether to force the last checkpoint to be + saved regardless of interval. Defaults to True. + file_client_args (dict, optional): Arguments to instantiate a + FileClient. See :class:`mmcv.fileio.FileClient` for details. + Defaults to None. + """ + out_dir: str + + priority = 'VERY_LOW' + + def __init__(self, + interval: int = -1, + by_epoch: bool = True, + out_dir: Optional[Union[str, Path]] = None, + max_keep_subnets: int = -1, + save_last: bool = True, + file_client_args: Optional[dict] = None, + **kwargs) -> None: + self.interval = interval + self.by_epoch = by_epoch + self.out_dir = out_dir # type: ignore + self.max_keep_subnets = max_keep_subnets + self.save_last = save_last + self.args = kwargs + self.file_client_args = file_client_args + + def before_train(self, runner) -> None: + """Finish all operations, related to checkpoint. + + This function will get the appropriate file client, and the directory + to save these checkpoints of the model. + + Args: + runner (Runner): The runner of the training process. + """ + if self.out_dir is None: + self.out_dir = runner.work_dir + + self.file_client = FileClient.infer_client(self.file_client_args, + self.out_dir) + # if `self.out_dir` is not equal to `runner.work_dir`, it means that + # `self.out_dir` is set so the final `self.out_dir` is the + # concatenation of `self.out_dir` and the last level directory of + # `runner.work_dir` + if self.out_dir != runner.work_dir: + basename = osp.basename(runner.work_dir.rstrip(osp.sep)) + self.out_dir = self.file_client.join_path( + self.out_dir, basename) # type: ignore # noqa: E501 + + runner.logger.info(f'Subnets will be saved to {self.out_dir} by ' + f'{self.file_client.name}.') + + def after_train_epoch(self, runner) -> None: + """Save the checkpoint and synchronize buffers after each epoch. + + Args: + runner (Runner): The runner of the training process. + """ + if not self.by_epoch: + return + + # save subnet for following cases: + # 1. every ``self.interval`` epochs + # 2. reach the last epoch of training + if self.every_n_epochs(runner, self.interval) or ( + self.save_last and self.is_last_train_epoch(runner)): + runner.logger.info(f'Saving subnet at {runner.epoch + 1} epochs') + self._save_subnet(runner) + + @master_only + def _save_subnet(self, runner) -> None: + """Save the current best subnet. + + Args: + runner (Runner): The runner of the training process. + """ + model = runner.model.module if runner.distributed else runner.model + + # delete non-leaf tensor to get deepcopy(model). + # TODO solve the hard case. + for module in model.architecture.modules(): + if isinstance(module, BaseMutable): + if hasattr(module, 'arch_weights'): + delattr(module, 'arch_weights') + + copied_model = copy.deepcopy(model) + copied_model.mutator.set_choices(copied_model.mutator.sample_choices()) + + subnet_dict = export_fix_subnet(copied_model)[0] + subnet_dict = convert_fix_subnet(subnet_dict) + + if self.by_epoch: + subnet_filename = self.args.get( + 'filename_tmpl', + 'subnet_epoch_{}.yaml').format(runner.epoch + 1) + else: + subnet_filename = self.args.get( + 'filename_tmpl', 'subnet_iter_{}.yaml').format(runner.iter + 1) + + file_client = FileClient.infer_client(self.file_client_args, + self.out_dir) + filepath = file_client.join_path(self.out_dir, subnet_filename) + + dump(subnet_dict, filepath, file_format='yaml') + + def after_train_iter(self, + runner, + batch_idx: int, + data_batch: DATA_BATCH = None, + outputs=Optional[dict]) -> None: + """Save the subnet after each iteration. + + Args: + runner (Runner): The runner of the training process. + batch_idx (int): The index of the current batch in the train loop. + data_batch (Sequence[dict], optional): Data from dataloader. + Defaults to None. + outputs (dict, optional): Outputs from model. Defaults to None. + """ + if self.by_epoch: + return + + # save checkpoint for following cases: + # 1. every ``self.interval`` iterations + # 2. reach the last iteration of training + if self.every_n_train_iters(runner, self.interval) or \ + (self.save_last and + self.is_last_train_iter(runner)): + runner.logger.info( + f'Saving subnet at {runner.iter + 1} iterations') + self._save_subnet(runner) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/estimate_resources_hook.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/estimate_resources_hook.py new file mode 100755 index 000000000..28f381a3c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/estimate_resources_hook.py @@ -0,0 +1,122 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Any, Dict, Optional, Sequence + +import torch +from mmengine.hooks import Hook +from mmengine.registry import HOOKS +from mmengine.structures import BaseDataElement + +from mmrazor.registry import TASK_UTILS + +DATA_BATCH = Optional[Sequence[dict]] + + +@HOOKS.register_module() +class EstimateResourcesHook(Hook): + """Estimate model resources periodically. + + Args: + interval (int): The saving period. If ``by_epoch=True``, interval + indicates epochs, otherwise it indicates iterations. + Defaults to -1, which means "never". + by_epoch (bool): Saving checkpoints by epoch or by iteration. + Default to True. + estimator_cfg (Dict[str, Any]): Used for building a resource estimator. + Default to None. + + Example: + >>> add the `EstimatorResourcesHook` in custom_hooks as follows: + custom_hooks = [ + dict(type='mmrazor.EstimateResourcesHook', + interval=1, + by_epoch=True, + estimator_cfg=dict(input_shape=(1, 3, 64, 64))) + ] + """ + out_dir: str + + priority = 'VERY_LOW' + + def __init__(self, + interval: int = -1, + by_epoch: bool = True, + estimator_cfg: Dict[str, Any] = None, + **kwargs) -> None: + self.interval = interval + self.by_epoch = by_epoch + estimator_cfg = dict() if estimator_cfg is None else estimator_cfg + if 'type' not in estimator_cfg: + estimator_cfg['type'] = 'mmrazor.ResourceEstimator' + self.estimator = TASK_UTILS.build(estimator_cfg) + + def after_val_epoch(self, + runner, + metrics: Optional[Dict[str, float]] = None) -> None: + """Estimate model resources after every n val epochs. + + Args: + runner (Runner): The runner of the training process. + """ + if not self.by_epoch: + return + + if self.every_n_epochs(runner, self.interval): + self.estimate_resources(runner) + + def after_val_iter(self, + runner, + batch_idx: int, + data_batch: DATA_BATCH = None, + outputs: Optional[Sequence[BaseDataElement]] = None) \ + -> None: + """Estimate model resources after every n val iters. + + Args: + runner (Runner): The runner of the training process. + """ + if self.by_epoch: + return + + if self.every_n_train_iters(runner, self.interval): + self.estimate_resources(runner) + + def estimate_resources(self, runner) -> None: + """Estimate model resources: latency/flops/params.""" + model = runner.model.module if runner.distributed else runner.model + + # TODO confirm the state judgement. + if hasattr(model, 'is_supernet') and model.is_supernet: + model = self.export_subnet(model) + + resource_metrics = self.estimator.estimate(model) + runner.logger.info(f'Estimate model resources: {resource_metrics}') + + def export_subnet(self, model) -> torch.nn.Module: + """Export current best subnet. + + NOTE: This method is called when it comes to those NAS algorithms that + require building a supernet for training. + + For those algorithms, measuring subnet resources is more meaningful + than supernet during validation, therefore this method is required to + get the current searched subnet from the supernet. + """ + # Avoid circular import + from mmrazor.models.mutables.base_mutable import BaseMutable + from mmrazor.structures import export_fix_subnet, load_fix_subnet + + # delete non-leaf tensor to get deepcopy(model). + # TODO solve the hard case. + for module in model.architecture.modules(): + if isinstance(module, BaseMutable): + if hasattr(module, 'arch_weights'): + delattr(module, 'arch_weights') + + copied_model = copy.deepcopy(model) + copied_model.mutator.set_choices(copied_model.mutator.sample_choices()) + + subnet_dict = export_fix_subnet(copied_model)[0] + load_fix_subnet(copied_model, subnet_dict) + + return copied_model diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/group_fisher_hooks.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/group_fisher_hooks.py new file mode 100755 index 000000000..3ce8631b7 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/group_fisher_hooks.py @@ -0,0 +1,9 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This file includes the modules in the impl folder. + +As it only records impl modules, it is not initialized automatically. +""" +from mmrazor.implementations.pruning.group_fisher import \ + PruningStructureHook # noqa +from mmrazor.implementations.pruning.group_fisher import \ + ResourceInfoHook # noqa diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/stop_distillation_hook.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/stop_distillation_hook.py new file mode 100755 index 000000000..3b907dc61 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/stop_distillation_hook.py @@ -0,0 +1,31 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmengine.hooks import Hook +from mmengine.model import is_model_wrapper + +from mmrazor.registry import HOOKS + + +@HOOKS.register_module() +class StopDistillHook(Hook): + """Stop distilling at a certain time. + + Args: + stop_epoch (int): Stop distillation at this epoch. + """ + + priority = 'LOW' + + def __init__(self, stop_epoch: int) -> None: + self.stop_epoch = stop_epoch + + def before_train_epoch(self, runner) -> None: + """Stop distillation.""" + if runner.epoch >= self.stop_epoch: + model = runner.model + # TODO: refactor after mmengine using model wrapper + if is_model_wrapper(model): + model = model.module + assert hasattr(model, 'distillation_stopped') + + runner.logger.info('Distillation has been stopped!') + model.distillation_stopped = True diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/visualization_hook.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/visualization_hook.py new file mode 100755 index 000000000..a52145b10 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/visualization_hook.py @@ -0,0 +1,205 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os.path as osp +import warnings +from typing import List, Optional, Union + +import mmcv +import torch +from mmcv.transforms import Compose +from mmengine.dist import master_only +from mmengine.fileio import FileClient +from mmengine.hooks import Hook +from mmengine.model import is_model_wrapper +from mmengine.utils import mkdir_or_exist +from mmengine.visualization import Visualizer + +from mmrazor.models.task_modules import RecorderManager +from mmrazor.registry import HOOKS +from mmrazor.visualization.local_visualizer import modify + + +def norm(feat): + assert len(feat.shape) == 4 + N, C, H, W = feat.shape + feat = feat.permute(1, 0, 2, 3).reshape(C, -1) + mean = feat.mean(dim=-1, keepdim=True) + std = feat.std(dim=-1, keepdim=True) + centered = (feat - mean) / (std + 1e-6) + centered = centered.reshape(C, N, H, W).permute(1, 0, 2, 3) + return centered + + +@HOOKS.register_module() +class RazorVisualizationHook(Hook): + """Razor Visualization Hook. Used to visualize training process immediate + feature maps. + + 1. If ``show`` is True, it means that only the immediate feature maps are + visualized without storing data, so ``vis_backends`` needs to + be excluded. + 2. If ``out_dir`` is specified, it means that the immediate feature maps + need to be saved to ``out_dir``. In order to avoid vis_backends + also storing data, so ``vis_backends`` needs to be excluded. + 3. ``vis_backends`` takes effect if the user does not specify ``show`` + and `out_dir``. You can set ``vis_backends`` to WandbVisBackend or + TensorboardVisBackend to store the immediate feature maps in Wandb or + Tensorboard. + + Args: + recorders (dict): All recorders' config. + mappings: (Dict[str, Dict]): The mapping between feature names and + records. + enabled (bool): Whether to draw immediate feature maps. If it is False, + it means that no drawing will be done. Defaults to False. + interval (int): The interval of visualization. Defaults to 1. + show (bool): Whether to display the drawn image. Default to False. + wait_time (float): The interval of show (s). Defaults to 0. + out_dir (str, optional): directory where painted images + will be saved in testing process. + file_client_args (dict): Arguments to instantiate a FileClient. + See :class:`mmengine.fileio.FileClient` for details. + Defaults to ``dict(backend='disk')``. + is_overlaid (bool): If `is_overlaid` is True, the final output image + will be the weighted sum of img and featmap. Defaults to True. + visualization_cfg (dict): Configs for visualization. + use_norm (bool): Whether to apply Batch Normalization over the + feature map. Defaults to False. + """ + + def __init__(self, + recorders: dict, + mappings: dict, + enabled: bool = False, + data_idx: Union[int, List] = 0, + interval: int = 1, + show: bool = False, + wait_time: float = 0.1, + out_dir: Optional[str] = None, + file_client_args: dict = dict(backend='disk'), + is_overlaid: bool = True, + visualization_cfg=dict( + channel_reduction='pixel_wise_max', + topk=20, + arrangement=(4, 5), + resize_shape=None, + alpha=0.5), + use_norm: bool = False): + self.enabled = enabled + self._visualizer: Visualizer = Visualizer.get_current_instance() + self._visualizer.draw_featmap = modify + if isinstance(data_idx, int): + data_idx = [data_idx] + self.data_idx = data_idx + self.show = show + if self.show: + # No need to think about vis backends. + self._visualizer._vis_backends = {} + warnings.warn('The show is True, it means that only ' + 'the prediction results are visualized ' + 'without storing data, so vis_backends ' + 'needs to be excluded.') + + self.wait_time = wait_time + self.file_client_args = file_client_args.copy() + self.file_client = None + self.out_dir = out_dir + self.interval = interval + + self.is_overlaid = is_overlaid + self.visualization_cfg = visualization_cfg + self.use_norm = use_norm + + self.recorder_manager = RecorderManager(recorders) + self.mappings = mappings + + self._step = 0 # Global step value to record + + @master_only + def before_run(self, runner) -> None: + model = runner.model + if is_model_wrapper(model): + self.recorder_manager.initialize(model.module) + else: + self.recorder_manager.initialize(model) + + @master_only + def before_train(self, runner): + if not self.enabled or runner.epoch % self.interval != 0: + return + self._visualize(runner, 'before_run') + + @master_only + def after_train_epoch(self, runner) -> None: + if not self.enabled or runner.epoch % self.interval != 0: + return + self._visualize(runner, f'epoch_{runner.epoch}') + + def _visualize(self, runner, stage): + if self.out_dir is not None: + self.out_dir = osp.join(runner.work_dir, runner.timestamp, + self.out_dir) + mkdir_or_exist(self.out_dir) + + if self.file_client is None: + self.file_client = FileClient(**self.file_client_args) + + cfg = runner.cfg.copy() + test_pipeline = cfg.test_dataloader.dataset.pipeline + new_test_pipeline = [] + for pipeline in test_pipeline: + if pipeline['type'] != 'LoadAnnotations' and pipeline[ + 'type'] != 'LoadPanopticAnnotations': + new_test_pipeline.append(pipeline) + + test_pipeline = Compose(new_test_pipeline) + dataset = runner.val_loop.dataloader.dataset + + for idx in self.data_idx: + data_info = dataset.get_data_info(idx) + img_path = data_info['img_path'] + data_ = dict(img_path=img_path, img_id=0) + data_ = test_pipeline(data_) + + data_['inputs'] = [data_['inputs']] + data_['data_samples'] = [data_['data_samples']] + + with torch.no_grad(), self.recorder_manager: + runner.model.test_step(data_) + + if self.is_overlaid: + img_bytes = self.file_client.get(img_path) + overlaid_image = mmcv.imfrombytes( + img_bytes, channel_order='rgb') + else: + overlaid_image = None + + for name, record in self.mappings.items(): + recorder = self.recorder_manager.get_recorder(record.recorder) + record_idx = getattr(record, 'record_idx', 0) + data_idx = getattr(record, 'data_idx', None) + feats = recorder.get_record_data(record_idx, data_idx) + if isinstance(feats, torch.Tensor): + feats = (feats, ) + + for i, feat in enumerate(feats): + if self.use_norm: + feat = norm(feat) + drawn_img = self._visualizer.draw_featmap( + feat[0], overlaid_image, **self.visualization_cfg) + + out_file = None + if self.out_dir is not None: + out_file = f'{stage}_data_idx_{idx}_{name}_{i}.jpg' + out_file = osp.join(self.out_dir, out_file) + + self._visualizer.add_datasample( + f'{stage}_data_idx_{idx}_{name}_{i}', + drawn_img, + draw_gt=False, + draw_pred=False, + show=self.show, + wait_time=0.1, + # TODO: Supported in mmengine's Viusalizer. + out_file=out_file, + step=self._step) + self._step += 1 diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/__init__.py new file mode 100755 index 000000000..9fb003224 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .optimizer_constructor import SeparateOptimWrapperConstructor + +__all__ = ['SeparateOptimWrapperConstructor'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/optimizer_constructor.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/optimizer_constructor.py new file mode 100755 index 000000000..09889dcbf --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/optimizer_constructor.py @@ -0,0 +1,71 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +from typing import Optional + +import torch.nn as nn +from mmengine.optim import DefaultOptimWrapperConstructor, OptimWrapperDict + +from mmrazor.registry import OPTIM_WRAPPER_CONSTRUCTORS + + +@OPTIM_WRAPPER_CONSTRUCTORS.register_module() +class SeparateOptimWrapperConstructor: + """OptimizerConstructor for Darts. This class construct optimizer for + the submodules (generator and discriminator for GAN most models) of the + model separately, and return a :class:~`mmengine.optim.OptimWrapperDict`. + Example: + >>> # build GAN model + >>> model = dict( + >>> type='SAGAN', + >>> num_classes=10, + >>> generator=dict(type='SAGANGenerator'), + >>> discriminator=dict(type='ProjDiscriminator')) + >>> gan_model = MODELS.build(model) + >>> # build constructor + >>> optim_wrapper = dict( + >>> constructor='GANOptimWrapperConstructor', + >>> generator=dict( + >>> type='OptimWrapper', + >>> accumulative_counts=1, + >>> optimizer=dict(type='Adam', lr=0.0002, + >>> betas=(0.5, 0.999))), + >>> discriminator=dict( + >>> optimizer=dict( + >>> type='OptimWrapper', + >>> accumulative_counts=1, + >>> optimizer=dict(type='Adam', lr=0.0002, + >>> betas=(0.5, 0.999)), + >>> ))) + >>> optim_wrapper_dict_builder = GenOptimConstructor(optim_wrapper) + >>> # build optim wrapper dict + >>> optim_wrapper_dict = optim_wrapper_dict_builder(gan_model) + Args: + optim_wrapper_cfg (dict): Config of the optimizer wrapper. + paramwise_cfg (Optional[dict]): Parameter-wise options. + """ + + def __init__(self, + optim_wrapper_cfg: dict, + paramwise_cfg: Optional[dict] = None): + if not isinstance(optim_wrapper_cfg, dict): + raise TypeError('optimizer_cfg should be a dict', + f'but got {type(optim_wrapper_cfg)}') + assert paramwise_cfg is None, ( + 'parawise_cfg should be set in each optimizer separately') + self.optim_cfg = optim_wrapper_cfg + self.constructors = {} + for key, cfg in self.optim_cfg.items(): + cfg_ = cfg.copy() + paramwise_cfg_ = cfg_.pop('paramwise_cfg', None) + + self.constructors[key] = DefaultOptimWrapperConstructor( + cfg_, paramwise_cfg_) + + def __call__(self, module: nn.Module) -> OptimWrapperDict: + """Build optimizer and return a optimizerwrapperdict.""" + optimizers = {} + if hasattr(module, 'module'): + module = module.module + for key, constructor in self.constructors.items(): + optimizers[key] = constructor(module._modules[key]) + return OptimWrapperDict(**optimizers) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/__init__.py new file mode 100755 index 000000000..5fe2fd524 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/__init__.py @@ -0,0 +1,19 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .autoslim_greedy_search_loop import AutoSlimGreedySearchLoop +from .darts_loop import DartsEpochBasedTrainLoop, DartsIterBasedTrainLoop +from .distill_val_loop import SelfDistillValLoop, SingleTeacherDistillValLoop +from .evolution_search_loop import EvolutionSearchLoop +from .iteprune_val_loop import ItePruneValLoop +from .quantization_loops import (LSQEpochBasedLoop, PTQLoop, QATEpochBasedLoop, + QATValLoop) +from .slimmable_val_loop import SlimmableValLoop +from .subnet_sampler_loop import GreedySamplerTrainLoop +from .subnet_val_loop import SubnetValLoop + +__all__ = [ + 'SingleTeacherDistillValLoop', 'DartsEpochBasedTrainLoop', + 'DartsIterBasedTrainLoop', 'SlimmableValLoop', 'EvolutionSearchLoop', + 'GreedySamplerTrainLoop', 'SubnetValLoop', 'SelfDistillValLoop', + 'ItePruneValLoop', 'AutoSlimGreedySearchLoop', 'QATEpochBasedLoop', + 'PTQLoop', 'LSQEpochBasedLoop', 'QATValLoop' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/autoslim_greedy_search_loop.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/autoslim_greedy_search_loop.py new file mode 100755 index 000000000..cf9752ce0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/autoslim_greedy_search_loop.py @@ -0,0 +1,223 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os.path as osp +import warnings +from typing import Any, Dict, List, Optional, Tuple, Union + +import torch +from mmengine import fileio +from mmengine.evaluator import Evaluator +from mmengine.runner import TestLoop +from torch.utils.data import DataLoader + +from mmrazor.registry import LOOPS, TASK_UTILS +from mmrazor.structures import convert_fix_subnet, export_fix_subnet +from .utils import check_subnet_resources + + +@LOOPS.register_module() +class AutoSlimGreedySearchLoop(TestLoop): + """Loop for Greedy searching in AutoSlim. Please refer to + https://arxiv.org/abs/1903.11728 for more details. + + Args: + runner (Runner): A reference of runner. + dataloader (Dataloader or dict): A dataloader object or a dict to + build a dataloader. + evaluator (Evaluator or dict or list): Used for computing metrics. + target_flops (Tuple[float]): The FLOPs limitation of target subnets. + estimator_cfg (dict, Optional): Used for building a resource estimator. + Defaults to None. + score_key (str): Specify one metric in evaluation results to score + candidates. Defaults to 'accuracy_top-1'. + resume_from (str, optional): Specify the path of saved .pkl file for + resuming searching. + """ + + def __init__(self, + runner, + dataloader: Union[DataLoader, Dict], + evaluator: Union[Evaluator, Dict, List], + target_flops: Tuple[float], + estimator_cfg: Dict[str, Any] = dict(), + score_key: str = 'accuracy/top1', + resume_from: Optional[str] = None): + super().__init__(runner, dataloader, evaluator) + + if hasattr(self.dataloader.dataset, 'metainfo'): + self.evaluator.dataset_meta = self.dataloader.dataset.metainfo + else: + warnings.warn( + f'Dataset {self.dataloader.dataset.__class__.__name__} has no ' + 'metainfo. ``dataset_meta`` in evaluator, metric and ' + 'visualizer will be None.') + + self.target_flops = sorted(target_flops, reverse=True) + self.score_key = score_key + self.resume_from = resume_from + + # initialize estimator + estimator_cfg = dict() if estimator_cfg is None else estimator_cfg + if 'type' not in estimator_cfg: + estimator_cfg['type'] = 'mmrazor.ResourceEstimator' + self.estimator = TASK_UTILS.build(estimator_cfg) + + if self.runner.distributed: + self.model = runner.model.module + else: + self.model = runner.model + + assert hasattr(self.model, 'mutator') + units = self.model.mutator.mutable_units + + self.candidate_choices = {} + for unit in units: + self.candidate_choices[unit.alias] = unit.candidate_choices + + self.max_subnet = {} + for name, candidate_choices in self.candidate_choices.items(): + self.max_subnet[name] = len(candidate_choices) + self.current_subnet = self.max_subnet + + current_subnet_choices = self._channel_bins2choices( + self.current_subnet) + _, results = check_subnet_resources(self.model, current_subnet_choices, + self.estimator) + self.current_flops = results['flops'] + + self.searched_subnet: List[Dict[str, int]] = [] + self.searched_subnet_flops: List[float] = [] + + def run(self) -> None: + """Launch searching.""" + self.runner.call_hook('before_test') + + if self.resume_from: + self._resume() + + for target in self.target_flops: + if self.resume_from and self.current_flops <= target: + continue + + if self.current_flops <= target: + self.searched_subnet.append(self.current_subnet) + self.searched_subnet_flops.append(self.current_flops) + self.runner.logger.info( + f'Find model flops {self.current_flops} <= {target}') + continue + + while self.current_flops > target: + best_score, best_subnet = None, None + + for unit_name in sorted(self.current_subnet.keys()): + if self.current_subnet[unit_name] == 1: + # The number of channel_bin has reached the minimum + # value + continue + pruned_subnet = copy.deepcopy(self.current_subnet) + pruned_subnet[unit_name] -= 1 + pruned_subnet_choices = self._channel_bins2choices( + pruned_subnet) + self.model.mutator.set_choices(pruned_subnet_choices) + metrics = self._val_subnet() + score = metrics[self.score_key] \ + if len(metrics) != 0 else 0. + self.runner.logger.info( + f'Slimming unit {unit_name}, {self.score_key}: {score}' + ) + if best_score is None or score > best_score: + best_score = score + best_subnet = pruned_subnet + + if best_subnet is None: + raise RuntimeError( + 'Cannot find any valid model, check your ' + 'configurations.') + + self.current_subnet = best_subnet + current_subnet_choices = self._channel_bins2choices( + self.current_subnet) + _, results = check_subnet_resources(self.model, + current_subnet_choices, + self.estimator) + self.current_flops = results['flops'] + self.runner.logger.info( + f'Greedily find model, score: {best_score}, ' + f'{self.current_subnet}, FLOPS: {self.current_flops}') + self._save_searcher_ckpt() + + self.searched_subnet.append(self.current_subnet) + self.searched_subnet_flops.append(self.current_flops) + self.runner.logger.info( + f'Find model flops {self.current_flops} <= {target}') + + self._save_searched_subnet() + self.runner.call_hook('after_test') + + def _channel_bins2choices(self, subnet_channel_bins): + """Convert the channel bin number of a channel unit to the choice + (ratio when choice_mode='ratio' and channel number when + choice_mode='number').""" + choices = {} + for unit_name, bins in subnet_channel_bins.items(): + # `bins` is in range [1, max_bins] + choices[unit_name] = self.candidate_choices[unit_name][bins - 1] + return choices + + @torch.no_grad() + def _val_subnet(self) -> Dict: + """Run validation.""" + self.runner.model.eval() + for data_batch in self.dataloader: + outputs = self.runner.model.val_step(data_batch) + self.evaluator.process(data_samples=outputs, data_batch=data_batch) + metrics = self.evaluator.evaluate(len(self.dataloader.dataset)) + return metrics + + def _save_searcher_ckpt(self) -> None: + """Save searcher ckpt, which is different from common ckpt. + + It mainly contains the candicate pool, the top-k candicates with scores + and the current epoch. + """ + if self.runner.rank != 0: + return + save_for_resume = dict() + for k in [ + 'current_subnet', 'current_flops', 'searched_subnet', + 'searched_subnet_flops' + ]: + save_for_resume[k] = getattr(self, k) + fileio.dump(save_for_resume, + osp.join(self.runner.work_dir, 'latest.pkl')) + self.runner.logger.info( + f'{len(self.searched_subnet)} subnets have been searched, ' + f'FLOPs are {self.searched_subnet_flops}') + + def _save_searched_subnet(self): + """Save the final searched subnet dict.""" + if self.runner.rank != 0: + return + self.runner.logger.info('Search finished:') + for subnet, flops in zip(self.searched_subnet, + self.searched_subnet_flops): + subnet_choice = self._channel_bins2choices(subnet) + self.model.mutator.set_choices(subnet_choice) + fixed_subnet, _ = export_fix_subnet(self.model) + save_name = 'FLOPS_{:.2f}M.yaml'.format(flops) + fixed_subnet = convert_fix_subnet(fixed_subnet) + fileio.dump(fixed_subnet, osp.join(self.runner.work_dir, + save_name)) + self.runner.logger.info( + f'{save_name} is saved in {self.runner.work_dir}.') + + def _resume(self): + """Resume searching.""" + searcher_resume = fileio.load(self.resume_from) + for key, val in searcher_resume.items(): + setattr(self, key, val) + self.runner.logger.info('#' * 100) + self.runner.logger.info(f'Current channel_bins dict: ' + f'{self.current_subnet}, \n' + f'Current flops: {self.current_flops}') + self.runner.logger.info('#' * 100) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/darts_loop.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/darts_loop.py new file mode 100755 index 000000000..65e4611df --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/darts_loop.py @@ -0,0 +1,181 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Union + +from mmengine.runner import EpochBasedTrainLoop, IterBasedTrainLoop +from torch.utils.data import DataLoader + +from mmrazor.registry import LOOPS + + +@LOOPS.register_module() +class DartsEpochBasedTrainLoop(EpochBasedTrainLoop): + """EpochBasedTrainLoop for `Darts `_ + + In Darts, Two dataloaders are needed in the training stage. One + (`dataloader`) is used to train the supernet and update its weights, + another(`mutator_dataloader`) is only used to train and update the + parameters of the supernet's architecture setting. In + `DartsEpochBasedTrainLoop`, these dataloaders will be combined as a + special dataloader, whose `data_batch` will contain both of the + dataloaders' `data_batch`. + + Args: + runner (Runner): A reference of runner. + dataloader (Dataloader or Dict): + A dataloader object or a dict to build a dataloader for + training the model. + mutator_dataloader (Dataloader or Dict): + A dataloader object or a dict to build a dataloader for + training the parameters of model architecture. + max_epochs (int): Total training epochs. + val_begin (int): The epoch that begins validating. + Defaults to 1. + val_interval (int): Validation interval. Defaults to 1. + """ + + def __init__(self, + runner, + dataloader: Union[Dict, DataLoader], + mutator_dataloader: Union[Dict, DataLoader], + max_epochs: int, + val_begin: int = 1, + val_interval: int = 1) -> None: + super().__init__(runner, dataloader, max_epochs, val_begin, + val_interval) + if isinstance(mutator_dataloader, dict): + self.mutator_dataloader = runner.build_dataloader( + mutator_dataloader, seed=runner.seed) + else: + self.mutator_dataloader = mutator_dataloader + self.multi_loaders = [self.dataloader, self.mutator_dataloader] + + def run_epoch(self) -> None: + """Iterate one epoch.""" + self.runner.call_hook('before_train_epoch') + self.runner.model.train() + + for idx, data_batch in enumerate(EpochMultiLoader(self.multi_loaders)): + self.run_iter(idx, data_batch) + + self.runner.call_hook('after_train_epoch') + self._epoch += 1 + + +@LOOPS.register_module() +class DartsIterBasedTrainLoop(IterBasedTrainLoop): + """IterBasedTrainLoop for `Darts `_ + + Args: + runner (Runner): A reference of runner. + dataloader (Dataloader or Dict): + A dataloader object or a dict to build a dataloader. + mutator_dataloader (Dataloader or Dict): + A dataloader object or a dict to build a dataloader for + training the parameters of model architecture. + max_iter (int): Total training iterations. + val_begin (int): The iteration that begins validating. + Defaults to 1. + val_interval (int): Validation interval. Defaults to 1000. + """ + + def __init__(self, + runner, + dataloader: Union[Dict, DataLoader], + mutator_dataloader: Union[Dict, DataLoader], + max_iters: int, + val_begin: int = 1, + val_interval: int = 1000) -> None: + super().__init__(runner, dataloader, max_iters, val_begin, + val_interval) + if isinstance(mutator_dataloader, dict): + self.mutator_dataloader = runner.build_dataloader( + mutator_dataloader, seed=runner.seed) + else: + self.mutator_dataloader = mutator_dataloader + multi_loaders = [self.dataloader, self.mutator_dataloader] + self.multi_loaders = IterMultiLoader(multi_loaders) + + def run(self) -> None: + """Launch training.""" + self.runner.call_hook('before_train') + # In iteration-based training loop, we treat the whole training process + # as a big epoch and execute the corresponding hook. + self.runner.call_hook('before_train_epoch') + while self._iter < self._max_iters: + self.runner.model.train() + + data_batch = next(self.multi_loaders) # type: ignore + self.run_iter(data_batch) + + if (self.runner.val_loop is not None + and self._iter >= self.val_begin + and self._iter % self.val_interval == 0): + self.runner.val_loop.run() + + self.runner.call_hook('after_train_epoch') + self.runner.call_hook('after_train') + + +class EpochMultiLoader: + """Multi loaders based on epoch.""" + + def __init__(self, dataloaders: List[DataLoader]): + self._dataloaders = dataloaders + self.iter_loaders = [iter(loader) for loader in self._dataloaders] + + @property + def num_loaders(self): + """The number of dataloaders.""" + return len(self._dataloaders) + + def __iter__(self): + """Return self when executing __iter__.""" + return self + + def __next__(self): + """Get the next iter's data of multiple loaders.""" + data = tuple([next(loader) for loader in self.iter_loaders]) + + return data + + def __len__(self): + """Get the length of loader.""" + return min([len(loader) for loader in self._dataloaders]) + + +class IterMultiLoader: + """Multi loaders based on iter.""" + + def __init__(self, dataloaders: Union[List[DataLoader], DataLoader]): + self._dataloaders = dataloaders if isinstance(dataloaders, + list) else [dataloaders] + self.iter_loaders = [iter(loader) for loader in self._dataloaders] + self._epoch = 0 + + @property + def epoch(self): + """The property of the class.""" + return self._epoch + + @property + def num_loaders(self): + """The number of dataloaders.""" + return len(self._dataloaders) + + def __next__(self): + """Get the next iter's data of multiple loaders.""" + try: + data = tuple([next(loader) for loader in self.iter_loaders]) + except StopIteration: + self._epoch += 1 + for loader in self._dataloaders: + if hasattr(loader.sampler, 'set_epoch'): + loader.sampler.set_epoch(self._epoch) + self.iter_loader = [iter(loader) for loader in self._dataloaders] + data = tuple([next(loader) for loader in self.iter_loaders]) + + return data + + def __len__(self): + """Get the length of loader.""" + return min([len(loader) for loader in self._dataloaders]) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/distill_val_loop.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/distill_val_loop.py new file mode 100755 index 000000000..0a86bbf4e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/distill_val_loop.py @@ -0,0 +1,127 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Sequence, Union + +import torch +from mmengine.evaluator import Evaluator +from mmengine.runner import ValLoop, autocast +from torch.utils.data import DataLoader + +from mmrazor.registry import LOOPS + + +@LOOPS.register_module() +class SingleTeacherDistillValLoop(ValLoop): + """Knowledge Distill loop for validation. It is not only validate student, + but also validate teacher with the same dataloader. + + Args: + runner (Runner): A reference of runner. + dataloader (Dataloader or dict): A dataloader object or a dict to + build a dataloader. + evaluator (Evaluator or dict or list): Used for computing metrics. + fp16 (bool): Whether to enable fp16 validation. Defaults to + False. + """ + + def __init__(self, + runner, + dataloader: Union[DataLoader, Dict], + evaluator: Union[Evaluator, Dict, List], + fp16: bool = False) -> None: + super().__init__(runner, dataloader, evaluator, fp16) + if self.runner.distributed: + assert hasattr(self.runner.model.module, 'teacher') + # TODO: remove hard code after mmcls add data_preprocessor + data_preprocessor = self.runner.model.module.data_preprocessor + self.teacher = self.runner.model.module.teacher + self.teacher.data_preprocessor = data_preprocessor + + else: + assert hasattr(self.runner.model, 'teacher') + # TODO: remove hard code after mmcls add data_preprocessor + data_preprocessor = self.runner.model.data_preprocessor + self.teacher = self.runner.model.teacher + self.teacher.data_preprocessor = data_preprocessor + + def run(self): + """Launch validation.""" + self.runner.call_hook('before_val') + self.runner.call_hook('before_val_epoch') + self.runner.model.eval() + for idx, data_batch in enumerate(self.dataloader): + self.run_iter(idx, data_batch) + # compute student metrics + metrics = self.evaluator.evaluate(len(self.dataloader.dataset)) + + self.runner.call_hook('before_val_epoch') + for idx, data_batch in enumerate(self.dataloader): + self.run_iter_teacher(idx, data_batch) + # compute teacher metrics + teacher_metrics = self.evaluator.evaluate(len(self.dataloader.dataset)) + for key, value in teacher_metrics.items(): + teacher_key = 'teacher.' + key + metrics[teacher_key] = value + + self.runner.call_hook('after_val_epoch', metrics=metrics) + self.runner.call_hook('after_val') + + @torch.no_grad() + def run_iter_teacher(self, idx, data_batch: Sequence[dict]): + """Iterate one mini-batch. + + Args: + data_batch (Sequence[dict]): Batch of data + from dataloader. + """ + self.runner.call_hook( + 'before_val_iter', batch_idx=idx, data_batch=data_batch) + + with autocast(enabled=self.fp16): + # outputs should be sequence of BaseDataElement + outputs = self.teacher.val_step(data_batch) + + self.evaluator.process(data_samples=outputs, data_batch=data_batch) + self.runner.call_hook( + 'after_val_iter', + batch_idx=idx, + data_batch=data_batch, + outputs=outputs) + + +@LOOPS.register_module() +class SelfDistillValLoop(ValLoop): + """Knowledge Distill loop for validation. Only validate student. + + Args: + runner (Runner): A reference of runner. + dataloader (Dataloader or dict): A dataloader object or a dict to + build a dataloader. + evaluator (Evaluator or dict or list): Used for computing metrics. + fp16 (bool): Whether to enable fp16 validation. Defaults to + False. + """ + + def __init__(self, + runner, + dataloader: Union[DataLoader, Dict], + evaluator: Union[Evaluator, Dict, List], + fp16: bool = False) -> None: + super().__init__(runner, dataloader, evaluator, fp16) + + def run(self): + """Launch validation.""" + self.runner.call_hook('before_val') + self.runner.call_hook('before_val_epoch') + self.runner.model.eval() + + for idx, data_batch in enumerate(self.dataloader): + self.run_iter(idx, data_batch) + # compute student metrics + metrics = self.evaluator.evaluate(len(self.dataloader.dataset)) + student_metrics = dict() + for key, value in metrics.items(): + student_key = 'student.' + key + student_metrics[student_key] = value + + self.runner.call_hook('after_val_epoch', metrics=student_metrics) + self.runner.call_hook('after_val') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/evolution_search_loop.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/evolution_search_loop.py new file mode 100755 index 000000000..644385e2f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/evolution_search_loop.py @@ -0,0 +1,443 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import os.path as osp +import random +import time +import warnings +from typing import Any, Dict, List, Optional, Tuple, Union + +import numpy as np +import torch +from mmengine import fileio +from mmengine.dist import broadcast_object_list +from mmengine.evaluator import Evaluator +from mmengine.runner import EpochBasedTrainLoop +from mmengine.utils import is_list_of +from torch.utils.data import DataLoader + +from mmrazor.registry import LOOPS, TASK_UTILS +from mmrazor.structures import (Candidates, convert_fix_subnet, + export_fix_subnet) +from mmrazor.utils import SupportRandomSubnet +from .utils import CalibrateBNMixin, check_subnet_resources, crossover + + +@LOOPS.register_module() +class EvolutionSearchLoop(EpochBasedTrainLoop, CalibrateBNMixin): + """Loop for evolution searching. + + Args: + runner (Runner): A reference of runner. + dataloader (Dataloader or dict): A dataloader object or a dict to + build a dataloader. + evaluator (Evaluator or dict or list): Used for computing metrics. + max_epochs (int): Total searching epochs. Defaults to 20. + max_keep_ckpts (int): The maximum checkpoints of searcher to keep. + Defaults to 3. + resume_from (str, optional): Specify the path of saved .pkl file for + resuming searching. + num_candidates (int): The length of candidate pool. Defaults to 50. + top_k (int): Specify top k candidates based on scores. Defaults to 10. + num_mutation (int): The number of candidates got by mutation. + Defaults to 25. + num_crossover (int): The number of candidates got by crossover. + Defaults to 25. + mutate_prob (float): The probability of mutation. Defaults to 0.1. + crossover_prob (float): The probability of crossover. Defaults to 0.5. + calibrate_sample_num (int): The number of images to compute the true + average of per-batch mean/variance instead of the running average. + Defaults to -1. + constraints_range (Dict[str, Any]): Constraints to be used for + screening candidates. Defaults to dict(flops=(0, 330)). + estimator_cfg (dict, Optional): Used for building a resource estimator. + Defaults to None. + predictor_cfg (dict, Optional): Used for building a metric predictor. + Defaults to None. + score_key (str): Specify one metric in evaluation results to score + candidates. Defaults to 'accuracy_top-1'. + init_candidates (str, optional): The candidates file path, which is + used to init `self.candidates`. Its format is usually in .yaml + format. Defaults to None. + """ + + def __init__(self, + runner, + dataloader: Union[DataLoader, Dict], + evaluator: Union[Evaluator, Dict, List], + max_epochs: int = 20, + max_keep_ckpts: int = 3, + resume_from: Optional[str] = None, + num_candidates: int = 50, + top_k: int = 10, + num_mutation: int = 25, + num_crossover: int = 25, + mutate_prob: float = 0.1, + crossover_prob: float = 0.5, + calibrate_sample_num: int = -1, + constraints_range: Dict[str, Any] = dict(flops=(0., 330.)), + estimator_cfg: Optional[Dict] = None, + predictor_cfg: Optional[Dict] = None, + score_key: str = 'accuracy/top1', + init_candidates: Optional[str] = None) -> None: + super().__init__(runner, dataloader, max_epochs) + if isinstance(evaluator, dict) or is_list_of(evaluator, dict): + self.evaluator = runner.build_evaluator(evaluator) # type: ignore + else: + self.evaluator = evaluator # type: ignore + if hasattr(self.dataloader.dataset, 'metainfo'): + self.evaluator.dataset_meta = self.dataloader.dataset.metainfo + else: + warnings.warn( + f'Dataset {self.dataloader.dataset.__class__.__name__} has no ' + 'metainfo. ``dataset_meta`` in evaluator, metric and ' + 'visualizer will be None.') + + self.num_candidates = num_candidates + self.top_k = top_k + self.constraints_range = constraints_range + self.calibrate_sample_num = calibrate_sample_num + self.score_key = score_key + self.num_mutation = num_mutation + self.num_crossover = num_crossover + self.mutate_prob = mutate_prob + self.crossover_prob = crossover_prob + self.max_keep_ckpts = max_keep_ckpts + self.resume_from = resume_from + self.fp16 = False + + if init_candidates is None: + self.candidates = Candidates() + else: + self.candidates = fileio.load(init_candidates) + assert isinstance(self.candidates, Candidates), 'please use the \ + correct init candidates file' + + self.top_k_candidates = Candidates() + + if self.runner.distributed: + self.model = runner.model.module + else: + self.model = runner.model + + # initialize estimator + estimator_cfg = dict() if estimator_cfg is None else estimator_cfg + if 'type' not in estimator_cfg: + estimator_cfg['type'] = 'mmrazor.ResourceEstimator' + self.estimator = TASK_UTILS.build(estimator_cfg) + + # initialize predictor + self.use_predictor = False + self.predictor_cfg = predictor_cfg + if self.predictor_cfg is not None: + self.predictor_cfg['score_key'] = self.score_key + self.predictor_cfg['search_groups'] = \ + self.model.mutator.search_groups + self.predictor = TASK_UTILS.build(self.predictor_cfg) + + def run(self) -> None: + """Launch searching.""" + self.runner.call_hook('before_train') + + if self.predictor_cfg is not None: + self._init_predictor() + + if self.resume_from: + self._resume() + + while self._epoch < self._max_epochs: + self.run_epoch() + self._save_searcher_ckpt() + + self._save_best_fix_subnet() + + self.runner.call_hook('after_train') + + def run_epoch(self) -> None: + """Iterate one epoch. + + Steps: + 1. Sample some new candidates from the supernet. Then Append them + to the candidates, Thus make its number equal to the specified + number. + 2. Validate these candidates(step 1) and update their scores. + 3. Pick the top k candidates based on the scores(step 2), which + will be used in mutation and crossover. + 4. Implement Mutation and crossover, generate better candidates. + """ + self.sample_candidates() + self.update_candidates_scores() + + scores_before = self.top_k_candidates.scores + self.runner.logger.info(f'top k scores before update: ' + f'{scores_before}') + + self.candidates.extend(self.top_k_candidates) + self.candidates.sort_by(key_indicator='score', reverse=True) + self.top_k_candidates = Candidates(self.candidates.data[:self.top_k]) + + scores_after = self.top_k_candidates.scores + self.runner.logger.info(f'top k scores after update: ' + f'{scores_after}') + + mutation_candidates = self.gen_mutation_candidates() + self.candidates_mutator_crossover = Candidates(mutation_candidates) + crossover_candidates = self.gen_crossover_candidates() + self.candidates_mutator_crossover.extend(crossover_candidates) + + assert len(self.candidates_mutator_crossover + ) <= self.num_candidates, 'Total of mutation and \ + crossover should be less than the number of candidates.' + + self.candidates = self.candidates_mutator_crossover + self._epoch += 1 + + def sample_candidates(self) -> None: + """Update candidate pool contains specified number of candicates.""" + candidates_resources = [] + init_candidates = len(self.candidates) + if self.runner.rank == 0: + while len(self.candidates) < self.num_candidates: + candidate = self.model.mutator.sample_choices() + is_pass, result = self._check_constraints( + random_subnet=candidate) + if is_pass: + self.candidates.append(candidate) + candidates_resources.append(result) + self.candidates = Candidates(self.candidates.data) + else: + self.candidates = Candidates([dict(a=0)] * self.num_candidates) + + if len(candidates_resources) > 0: + self.candidates.update_resources( + candidates_resources, + start=len(self.candidates.data) - len(candidates_resources)) + assert init_candidates + len( + candidates_resources) == self.num_candidates + + # broadcast candidates to val with multi-GPUs. + broadcast_object_list(self.candidates.data) + + def update_candidates_scores(self) -> None: + """Validate candicate one by one from the candicate pool, and update + top-k candicates.""" + for i, candidate in enumerate(self.candidates.subnets): + self.model.mutator.set_choices(candidate) + metrics = self._val_candidate(use_predictor=self.use_predictor) + score = round(metrics[self.score_key], 2) \ + if len(metrics) != 0 else 0. + self.candidates.set_resource(i, score, 'score') + self.runner.logger.info( + f'Epoch:[{self._epoch}/{self._max_epochs}] ' + f'Candidate:[{i + 1}/{self.num_candidates}] ' + f'Flops: {self.candidates.resources("flops")[i]} ' + f'Params: {self.candidates.resources("params")[i]} ' + f'Latency: {self.candidates.resources("latency")[i]} ' + f'Score: {self.candidates.scores[i]} ') + + def gen_mutation_candidates(self): + """Generate specified number of mutation candicates.""" + mutation_resources = [] + mutation_candidates: List = [] + max_mutate_iters = self.num_mutation * 10 + mutate_iter = 0 + while len(mutation_candidates) < self.num_mutation: + mutate_iter += 1 + if mutate_iter > max_mutate_iters: + break + + mutation_candidate = self._mutation() + + is_pass, result = self._check_constraints( + random_subnet=mutation_candidate) + if is_pass: + mutation_candidates.append(mutation_candidate) + mutation_resources.append(result) + + mutation_candidates = Candidates(mutation_candidates) + mutation_candidates.update_resources(mutation_resources) + + return mutation_candidates + + def gen_crossover_candidates(self): + """Generate specofied number of crossover candicates.""" + crossover_resources = [] + crossover_candidates: List = [] + crossover_iter = 0 + max_crossover_iters = self.num_crossover * 10 + while len(crossover_candidates) < self.num_crossover: + crossover_iter += 1 + if crossover_iter > max_crossover_iters: + break + + crossover_candidate = self._crossover() + + is_pass, result = self._check_constraints( + random_subnet=crossover_candidate) + if is_pass: + crossover_candidates.append(crossover_candidate) + crossover_resources.append(result) + + crossover_candidates = Candidates(crossover_candidates) + crossover_candidates.update_resources(crossover_resources) + + return crossover_candidates + + def _mutation(self) -> SupportRandomSubnet: + """Mutate with the specified mutate_prob.""" + candidate1 = random.choice(self.top_k_candidates.subnets) + candidate2 = self.model.mutator.sample_choices() + candidate = crossover(candidate1, candidate2, prob=self.mutate_prob) + return candidate + + def _crossover(self) -> SupportRandomSubnet: + """Crossover.""" + candidate1 = random.choice(self.top_k_candidates.subnets) + candidate2 = random.choice(self.top_k_candidates.subnets) + candidate = crossover(candidate1, candidate2, prob=self.crossover_prob) + return candidate + + def _resume(self): + """Resume searching.""" + if self.runner.rank == 0: + searcher_resume = fileio.load(self.resume_from) + for k in searcher_resume.keys(): + setattr(self, k, searcher_resume[k]) + epoch_start = int(searcher_resume['_epoch']) + self._max_epochs = self._max_epochs - epoch_start + self.runner.logger.info('#' * 100) + self.runner.logger.info(f'Resume from epoch: {epoch_start}') + self.runner.logger.info('#' * 100) + + def _save_best_fix_subnet(self): + """Save best subnet in searched top-k candidates.""" + if self.runner.rank == 0: + best_random_subnet = self.top_k_candidates.subnets[0] + self.model.mutator.set_choices(best_random_subnet) + + best_fix_subnet, sliced_model = \ + export_fix_subnet(self.model, slice_weight=True) + + timestamp_subnet = time.strftime('%Y%m%d_%H%M', time.localtime()) + model_name = f'subnet_{timestamp_subnet}.pth' + save_path = osp.join(self.runner.work_dir, model_name) + torch.save({ + 'state_dict': sliced_model.state_dict(), + 'meta': {} + }, save_path) + self.runner.logger.info(f'Subnet checkpoint {model_name} saved in ' + f'{self.runner.work_dir}') + + save_name = 'best_fix_subnet.yaml' + best_fix_subnet = convert_fix_subnet(best_fix_subnet) + fileio.dump(best_fix_subnet, + osp.join(self.runner.work_dir, save_name)) + self.runner.logger.info( + f'Subnet config {save_name} saved in {self.runner.work_dir}.') + + self.runner.logger.info('Search finished.') + + @torch.no_grad() + def _val_candidate(self, use_predictor: bool = False) -> Dict: + """Run validation. + + Args: + use_predictor (bool): Whether to use predictor to get metrics. + Defaults to False. + """ + if use_predictor: + assert self.predictor is not None + metrics = self.predictor.predict(self.model) + else: + if self.calibrate_sample_num > 0: + self.calibrate_bn_statistics(self.runner.train_dataloader, + self.calibrate_sample_num) + self.runner.model.eval() + for data_batch in self.dataloader: + outputs = self.runner.model.val_step(data_batch) + self.evaluator.process( + data_samples=outputs, data_batch=data_batch) + metrics = self.evaluator.evaluate(len(self.dataloader.dataset)) + return metrics + + def _save_searcher_ckpt(self) -> None: + """Save searcher ckpt, which is different from common ckpt. + + It mainly contains the candicate pool, the top-k candicates with scores + and the current epoch. + """ + if self.runner.rank == 0: + save_for_resume = dict() + save_for_resume['_epoch'] = self._epoch + for k in ['candidates', 'top_k_candidates']: + save_for_resume[k] = getattr(self, k) + fileio.dump( + save_for_resume, + osp.join(self.runner.work_dir, + f'search_epoch_{self._epoch}.pkl')) + self.runner.logger.info( + f'Epoch:[{self._epoch}/{self._max_epochs}], top1_score: ' + f'{self.top_k_candidates.scores[0]}') + + if self.max_keep_ckpts > 0: + cur_ckpt = self._epoch + 1 + redundant_ckpts = range(1, cur_ckpt - self.max_keep_ckpts) + for _step in redundant_ckpts: + ckpt_path = osp.join(self.runner.work_dir, + f'search_epoch_{_step}.pkl') + if osp.isfile(ckpt_path): + os.remove(ckpt_path) + + def _check_constraints( + self, random_subnet: SupportRandomSubnet) -> Tuple[bool, Dict]: + """Check whether is beyond constraints. + + Returns: + bool, result: The result of checking. + """ + is_pass, results = check_subnet_resources( + model=self.model, + subnet=random_subnet, + estimator=self.estimator, + constraints_range=self.constraints_range) + + return is_pass, results + + def _init_predictor(self): + """Initialize predictor, training is required.""" + if self.predictor.handler_ckpt: + self.predictor.load_checkpoint() + self.runner.logger.info( + f'Loaded Checkpoints from {self.predictor.handler_ckpt}') + else: + self.runner.logger.info('No predictor checkpoints found. ' + 'Start pre-training the predictor.') + if isinstance(self.predictor.train_samples, str): + self.runner.logger.info('Find specified samples in ' + f'{self.predictor.train_samples}') + train_samples = fileio.load(self.predictor.train_samples) + self.candidates = train_samples['subnets'] + else: + self.runner.logger.info( + 'Without specified samples. Start random sampling.') + temp_num_candidates = self.num_candidates + self.num_candidates = self.predictor.train_samples + + assert self.use_predictor is False, ( + 'Real evaluation is required when initializing predictor.') + self.sample_candidates() + self.update_candidates_scores() + self.num_candidates = temp_num_candidates + + inputs = [] + for candidate in self.candidates.subnets: + inputs.append(self.predictor.model2vector(candidate)) + inputs = np.array(inputs) + labels = np.array(self.candidates.scores) + self.predictor.fit(inputs, labels) + if self.runner.rank == 0: + predictor_dir = self.predictor.save_checkpoint( + osp.join(self.runner.work_dir, 'predictor')) + self.runner.logger.info( + f'Predictor pre-trained, saved in {predictor_dir}.') + self.use_predictor = True + self.candidates = Candidates() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/iteprune_val_loop.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/iteprune_val_loop.py new file mode 100755 index 000000000..2a627f398 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/iteprune_val_loop.py @@ -0,0 +1,58 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import json +import os.path as osp + +import torch +from mmengine.runner import ValLoop + +from mmrazor.registry import LOOPS +from mmrazor.structures import export_fix_subnet + + +@LOOPS.register_module() +class ItePruneValLoop(ValLoop): + """Pruning loop for validation. Export fixed subnet configs. + + Args: + runner (Runner): A reference of runner. + dataloader (Dataloader or dict): A dataloader object or a dict to + build a dataloader. + evaluator (Evaluator or dict or list): Used for computing metrics. + fp16 (bool): Whether to enable fp16 validation. Defaults to + False. + """ + + def run(self): + """Launch validation.""" + self.runner.call_hook('before_val') + self.runner.call_hook('before_val_epoch') + self.runner.model.eval() + for idx, data_batch in enumerate(self.dataloader): + self.run_iter(idx, data_batch) + + # compute metrics + metrics = self.evaluator.evaluate(len(self.dataloader.dataset)) + self._save_fix_subnet() + self.runner.call_hook('after_val_epoch', metrics=metrics) + self.runner.call_hook('after_val') + return metrics + + def _save_fix_subnet(self): + """Save model subnet config.""" + model = self.runner.model.module \ + if self.runner.distributed else self.runner.model + + fix_subnet, static_model = export_fix_subnet( + model, export_subnet_mode='mutator', slice_weight=True) + fix_subnet = json.dumps(fix_subnet, indent=4, separators=(',', ':')) + + subnet_name = 'fix_subnet.json' + weight_name = 'fix_subnet_weight.pth' + with open(osp.join(self.runner.work_dir, subnet_name), 'w') as file: + file.write(fix_subnet) + torch.save({'state_dict': static_model.state_dict()}, + osp.join(self.runner.work_dir, weight_name)) + self.runner.logger.info( + 'export finished and ' + f'{subnet_name}, ' + f'{weight_name} saved in {self.runner.work_dir}.') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/quantization_loops.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/quantization_loops.py new file mode 100755 index 000000000..58d91cf18 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/quantization_loops.py @@ -0,0 +1,399 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +from typing import Dict, List, Optional, Sequence, Tuple, Union + +import torch +from mmengine.evaluator import Evaluator +from mmengine.logging import print_log +from mmengine.runner import EpochBasedTrainLoop, TestLoop, ValLoop + +try: + from torch.ao.quantization import (disable_observer, enable_fake_quant, + enable_observer) + from torch.nn.intrinsic.qat import freeze_bn_stats +except ImportError: + from mmrazor.utils import get_placeholder + + disable_observer = get_placeholder('torch>=1.13') + enable_fake_quant = get_placeholder('torch>=1.13') + enable_observer = get_placeholder('torch>=1.13') + freeze_bn_stats = get_placeholder('torch>=1.13') + +from mmengine.dist import all_reduce_params, is_distributed +from torch.utils.data import DataLoader + +from mmrazor.models import register_torch_fake_quants, register_torch_observers +from mmrazor.models.fake_quants import (enable_param_learning, + enable_static_estimate, enable_val) +from mmrazor.registry import LOOPS + +TORCH_observers = register_torch_observers() +TORCH_fake_quants = register_torch_fake_quants() + + +@LOOPS.register_module() +class QATEpochBasedLoop(EpochBasedTrainLoop): + """`EpochBasedLoop` for `QuantizationAwareTraining` + + Args: + runner (Runner): A reference of runner + dataloader (Dataloader or dict): An iterator to generate one batch of + dataset each iteration. + max_epochs (int): Total training epochs. + val_begin (int): The epoch that begins validating. Defaults to 1. + val_interval (int): Validation interval. Defaults to 1. + disable_observer_begin (int): The number of total epochs to update + observers. Defaults to -1, which means observers are enabled + all the time. + freeze_bn_begin (int): The number of total epochs to update batch norm + stats. Defaults to -1, which means no need to freeze bn. + dynamic_intervals (List[Tuple[int, int]], optional): The + first element in the tuple is a milestone and the second + element is a interval. The interval is used after the + corresponding milestone. Defaults to None. + """ + + def __init__( + self, + runner, + dataloader: Union[DataLoader, Dict], + max_epochs: int, + val_begin: int = 1, + val_interval: int = 1, + disable_observer_begin: int = -1, + freeze_bn_begin: int = -1, + dynamic_intervals: Optional[List[Tuple[int, int]]] = None) -> None: + super().__init__(runner, dataloader, max_epochs, val_begin, + val_interval, dynamic_intervals) + + self.disable_observer_begin = disable_observer_begin + self.freeze_bn_begin = freeze_bn_begin + + def prepare_for_run_epoch(self): + """Toggle the state of the observers and fake quantizers before qat + training.""" + self.runner.model.apply(enable_fake_quant) + + # The initialized _epoch equals to 0 so _epoch + 1 + # equal to the current epoch + if (self.disable_observer_begin > 0 + and self._epoch + 1 >= self.disable_observer_begin): + self.runner.model.apply(disable_observer) + else: + self.runner.model.apply(enable_observer) + + if (self.freeze_bn_begin > 0 + and self._epoch + 1 >= self.freeze_bn_begin): + self.runner.model.apply(freeze_bn_stats) + + def prepare_for_val(self): + """Toggle the state of the observers and fake quantizers before + validation.""" + self.runner.model.apply(enable_fake_quant) + self.runner.model.apply(disable_observer) + + def run(self): + """Launch training.""" + self.runner.call_hook('before_train') + + while self._epoch < self._max_epochs: + self.prepare_for_run_epoch() + self.run_epoch() + + self._decide_current_val_interval() + if (self.runner.val_loop is not None + and self._epoch >= self.val_begin + and self._epoch % self.val_interval == 0): + self.runner.val_loop.run() + + self.runner.call_hook('after_train') + + def run_epoch(self) -> None: + """Iterate one epoch.""" + self.runner.call_hook('before_train_epoch') + self.runner.model.train() + + for idx, data_batch in enumerate(self.dataloader): + self.run_iter(idx, data_batch) + + self.runner.model.sync_qparams(src_mode='loss') + # Make sure the registered buffer such as `observer_enabled` is + # correct in the saved checkpoint. + self.prepare_for_val() + self.runner.call_hook('after_train_epoch') + self._epoch += 1 + + +@LOOPS.register_module() +class LSQEpochBasedLoop(QATEpochBasedLoop): + """`EpochBasedLoop` for `LEARNED STEP SIZE QUANTIZATION` + + Paper: Learned Step Size Quantization. + + Args: + runner (Runner): A reference of runner + dataloader (Dataloader or dict): An iterator to generate one batch of + dataset each iteration. + max_epochs (int): Total training epochs. + val_begin (int): The epoch that begins validating. Defaults to 1. + val_interval (int): Validation interval. Defaults to 1. + freeze_bn_begin (int): The number of total epochs to update batch norm + stats. Defaults to -1, which means no need to freeze bn. + dynamic_intervals (List[Tuple[int, int]], optional): The + first element in the tuple is a milestone and the second + element is a interval. The interval is used after the + corresponding milestone. Defaults to None. + """ + + def __init__( + self, + runner, + dataloader: Union[DataLoader, Dict], + max_epochs: int, + val_begin: int = 1, + val_interval: int = 1, + freeze_bn_begin: int = -1, + dynamic_intervals: Optional[List[Tuple[int, int]]] = None) -> None: + super().__init__( + runner, + dataloader, + max_epochs, + val_begin, + val_interval, + freeze_bn_begin=freeze_bn_begin, + dynamic_intervals=dynamic_intervals) + + self.is_first_batch = True + self.distributed = is_distributed() + + def prepare_for_run_epoch(self): + """Toggle the state of the observers and fake quantizers before qat + training.""" + if (self.freeze_bn_begin > 0 + and self._epoch + 1 >= self.freeze_bn_begin): + self.runner.model.apply(freeze_bn_stats) + + self.runner.model.apply(enable_param_learning) + + def prepare_for_val(self): + """Toggle the state of the observers and fake quantizers before + validation.""" + self.runner.model.apply(enable_val) + + def run_epoch(self) -> None: + """Iterate one epoch.""" + self.runner.call_hook('before_train_epoch') + self.runner.model.train() + + for idx, data_batch in enumerate(self.dataloader): + if self.is_first_batch: + # lsq observer init + self.runner.model.apply(enable_static_estimate) + + self.run_iter(idx, data_batch) + + if self.is_first_batch: + # In the first batch, scale in LearnableFakeQuantize is + # calculated through lsq observer. As the values of `scale` of + # different observers in different rank are usually different, + # we have to sync the `scale` here. + if self.distributed: + all_reduce_params( + self.runner.model.parameters(), op='mean') + + # Change back to param learning mode + self.is_first_batch = False + self.runner.model.apply(enable_param_learning) + + self.runner.model.sync_qparams(src_mode='loss') + # Make sure the registered buffer such as `observer_enabled` is + # correct in the saved checkpoint. + self.prepare_for_val() + self.runner.call_hook('after_train_epoch') + self._epoch += 1 + + +@LOOPS.register_module() +class QATValLoop(ValLoop): + """`ValLoop` for `QuantizationAwareTraining` + + Args: + runner (Runner): A reference of runner + dataloader (Dataloader or dict): An iterator to generate one batch of + dataset each iteration. + evaluator (Evaluator or dict or list): Used for computing metrics. + fp16 (bool): Whether to enable fp16 validation. Defaults to + False. + """ + + def __init__(self, + runner, + dataloader: Union[DataLoader, Dict], + evaluator: Union[Evaluator, Dict, List], + fp16: bool = False) -> None: + super().__init__(runner, dataloader, evaluator, fp16) + if self.runner.distributed: + assert hasattr(self.runner.model.module, 'architecture') + # TODO: remove hard code after mmcls add data_preprocessor + data_preprocessor = self.runner.model.module.data_preprocessor + self.architecture = self.runner.model.module.architecture + self.architecture.data_preprocessor = data_preprocessor + + else: + assert hasattr(self.runner.model, 'architecture') + # TODO: remove hard code after mmcls add data_preprocessor + data_preprocessor = self.runner.model.data_preprocessor + self.architecture = self.runner.model.architecture + self.architecture.data_preprocessor = data_preprocessor + + def run(self) -> dict: + """Launch validation.""" + self.runner.call_hook('before_val') + self.runner.call_hook('before_val_epoch') + self.runner.model.eval() + for idx, data_batch in enumerate(self.dataloader): + self.run_iter(idx, data_batch, self.runner.model) + + # compute metrics + metrics = self.evaluator.evaluate(len(self.dataloader.dataset)) + qat_metrics = dict() + for key, value in metrics.items(): + qat_key = 'qat.' + key + ori_key = 'original.' + key + qat_metrics[qat_key] = value + self.runner.message_hub.log_scalars.pop(f'val/{ori_key}', None) + + self.runner.call_hook('after_val_epoch', metrics=qat_metrics) + + self.runner.call_hook('before_val_epoch') + self.runner.model.eval() + for idx, data_batch in enumerate(self.dataloader): + self.run_iter(idx, data_batch, self.architecture) + + # compute metrics + metrics = self.evaluator.evaluate(len(self.dataloader.dataset)) + qat_metrics = dict() + for key, value in metrics.items(): + qat_key = 'qat.' + key + ori_key = 'original.' + key + qat_metrics[ori_key] = value + self.runner.message_hub.log_scalars.pop(f'val/{qat_key}', None) + + self.runner.call_hook('after_val_epoch', metrics=qat_metrics) + + self.runner.call_hook('after_val') + return qat_metrics + + @torch.no_grad() + def run_iter(self, idx, data_batch: Sequence[dict], model): + """Iterate one mini-batch. + + Args: + data_batch (Sequence[dict]): Batch of data + from dataloader. + """ + self.runner.call_hook( + 'before_val_iter', batch_idx=idx, data_batch=data_batch) + # outputs should be sequence of BaseDataElement + + outputs = model.val_step(data_batch) + self.evaluator.process(data_samples=outputs, data_batch=data_batch) + self.runner.call_hook( + 'after_val_iter', + batch_idx=idx, + data_batch=data_batch, + outputs=outputs) + + +@LOOPS.register_module() +class PTQLoop(TestLoop): + """`TestLoop` for Post Training Quantization. + + Args: + runner (Runner): A reference of runner + dataloader (Dataloader or dict): An iterator to generate one batch of + dataset each iteration. + evaluator (Evaluator or dict or list): Used for computing metrics. + fp16 (bool, optional): Enable FP16 training mode. Defaults to False. + """ + + def __init__(self, + runner, + dataloader: Union[DataLoader, Dict], + evaluator: Union[Evaluator, Dict, List], + calibrate_dataloader: Union[DataLoader, Dict], + calibrate_steps=32, + fp16: bool = False, + only_val=False): + super().__init__(runner, dataloader, evaluator, fp16) + if isinstance(calibrate_dataloader, dict): + # Determine whether or not different ranks use different seed. + diff_rank_seed = runner._randomness_cfg.get( + 'diff_rank_seed', False) + self.calibrate_dataloader = runner.build_dataloader( + calibrate_dataloader, + seed=runner.seed, + diff_rank_seed=diff_rank_seed) + else: + self.calibrate_dataloader = calibrate_dataloader + + self.calibrate_steps = calibrate_steps + self.only_val = only_val + + def run(self) -> dict: + """Launch test.""" + self.runner.call_hook('before_test') + self.runner.call_hook('before_test_epoch') + + self.runner.model.eval() + + if not self.only_val: + self.runner.model.apply(enable_fake_quant) + self.runner.model.apply(enable_observer) + + print_log('Star calibratiion...') + for idx, data_batch in enumerate(self.calibrate_dataloader): + if idx == self.calibrate_steps: + break + self.run_iter(idx, data_batch) + print_log('Finish calibratiion!') + + self.runner.model.apply(enable_fake_quant) + self.runner.model.apply(disable_observer) + + save_dir = os.path.join(self.runner.work_dir, + self.runner.timestamp) + self.runner.save_checkpoint( + save_dir, + 'model_ptq.pth', + file_client_args=None, + save_optimizer=False, + save_param_scheduler=False) + print_log(f'Quantized model is saved in {save_dir}') + + print_log('Start Evaluating quantized model...') + self.runner.model.apply(enable_fake_quant) + self.runner.model.apply(disable_observer) + metricts = self.runner.val_loop.run() + self.runner.call_hook('after_test_epoch', metrics=metricts) + self.runner.call_hook('after_test') + + return metricts + + @torch.no_grad() + def run_iter(self, idx, data_batch: Sequence[dict]) -> None: + """Iterate one mini-batch. + + Args: + data_batch (Sequence[dict]): Batch of data from dataloader. + """ + self.runner.call_hook( + 'before_test_iter', batch_idx=idx, data_batch=data_batch) + + _ = self.runner.model.calibrate_step(data_batch) + + self.runner.call_hook( + 'after_test_iter', + batch_idx=idx, + data_batch=data_batch, + outputs=None) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/slimmable_val_loop.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/slimmable_val_loop.py new file mode 100755 index 000000000..d3f5e2a4e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/slimmable_val_loop.py @@ -0,0 +1,58 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Union + +from mmengine.evaluator import Evaluator +from mmengine.runner import ValLoop +from torch.utils.data import DataLoader + +from mmrazor.models.utils import add_prefix +from mmrazor.registry import LOOPS + + +@LOOPS.register_module() +class SlimmableValLoop(ValLoop): + """Knowledge Distill loop for validation. It is not only validate student, + but also validate teacher with the same dataloader. + + Args: + runner (Runner): A reference of runner. + dataloader (Dataloader or dict): A dataloader object or a dict to + build a dataloader. + evaluator (Evaluator or dict or list): Used for computing metrics. + fp16 (bool): Whether to enable fp16 validation. Defaults to + False. + """ + + def __init__(self, + runner, + dataloader: Union[DataLoader, Dict], + evaluator: Union[Evaluator, Dict, List], + fp16: bool = False) -> None: + super().__init__(runner, dataloader, evaluator, fp16) + + if self.runner.distributed: + model = self.runner.model.module + else: + model = self.runner.model + + # just for convenience + self._model = model + + def run(self): + """Launch validation.""" + self.runner.call_hook('before_val') + + all_metrics = dict() + for subnet_idx, subnet in enumerate(self._model.mutator.subnets): + self.runner.call_hook('before_val_epoch') + self.runner.model.eval() + self._model.mutator.set_choices(subnet) + for idx, data_batch in enumerate(self.dataloader): + self.run_iter(idx, data_batch) + # compute student metrics + metrics = self.evaluator.evaluate(len(self.dataloader.dataset)) + all_metrics.update(add_prefix(metrics, f'subnet_{subnet_idx}')) + + self.runner.call_hook('after_val_epoch', metrics=all_metrics) + + self.runner.call_hook('after_val') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_sampler_loop.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_sampler_loop.py new file mode 100755 index 000000000..4f26ee7a2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_sampler_loop.py @@ -0,0 +1,338 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import math +import os +import random +from abc import abstractmethod +from typing import Any, Dict, List, Optional, Sequence, Tuple, Union + +import torch +from mmengine import fileio +from mmengine.evaluator import Evaluator +from mmengine.runner import IterBasedTrainLoop +from mmengine.utils import is_list_of +from torch.utils.data import DataLoader + +from mmrazor.registry import LOOPS, TASK_UTILS +from mmrazor.structures import Candidates +from mmrazor.utils import SupportRandomSubnet +from .utils import check_subnet_resources + + +class BaseSamplerTrainLoop(IterBasedTrainLoop): + """IterBasedTrainLoop for base sampler. + + Args: + runner (Runner): A reference of runner. + dataloader (Dataloader or dict): A dataloader object or a dict to + build a dataloader for training the model. + max_iters (int): Total training iters. + val_begin (int): The iteration that begins validating. + Defaults to 1. + val_interval (int): Validation interval. Defaults to 1000. + """ + + def __init__(self, + runner, + dataloader: Union[Dict, DataLoader], + max_iters: int, + val_begin: int = 1, + val_interval: int = 1000): + super().__init__(runner, dataloader, max_iters, val_begin, + val_interval) + if self.runner.distributed: + self.model = runner.model.module + else: + self.model = runner.model + + @abstractmethod + def sample_subnet(self) -> SupportRandomSubnet: + """Sample a subnet to train the supernet.""" + + def run_iter(self, data_batch: Sequence[dict]) -> None: + """Iterate one mini-batch. + + Args: + data_batch (Sequence[dict]): Batch of data from dataloader. + """ + self.runner.call_hook( + 'before_train_iter', batch_idx=self._iter, data_batch=data_batch) + # Enable gradient accumulation mode and avoid unnecessary gradient + # synchronization during gradient accumulation process. + # outputs should be a dict of loss. + subnet = self.sample_subnet() + self.model.mutator.set_choices(subnet) + outputs = self.runner.model.train_step( + data_batch, optim_wrapper=self.runner.optim_wrapper) + self.runner.message_hub.update_info('train_logs', outputs) + + self.runner.call_hook( + 'after_train_iter', + batch_idx=self._iter, + data_batch=data_batch, + outputs=outputs) + self._iter += 1 + + +@LOOPS.register_module() +class GreedySamplerTrainLoop(BaseSamplerTrainLoop): + """IterBasedTrainLoop for greedy sampler. + In GreedySamplerTrainLoop, `Greedy` means that only use some top + sampled candidates to train the supernet. So GreedySamplerTrainLoop mainly + picks the top candidates based on their val socres, then use them to train + the supernet one by one. + Steps: + 1. Sample from the supernet and the candidates. + 2. Validate these sampled candidates to get each candidate's score. + 3. Get top-k candidates based on their scores, then use them to train + the supernet one by one. + Args: + runner (Runner): A reference of runner. + dataloader (Dataloader or dict): A dataloader object or a dict to + build a dataloader for training the model. + dataloader_val (Dataloader or dict): A dataloader object or a dict to + build a dataloader for evaluating the candidates. + evaluator (Evaluator or dict or list): Used for computing metrics. + max_iters (int): Total training iters. + val_begin (int): The iteration that begins validating. + Defaults to 1. + val_interval (int): Validation interval. Defaults to 1000. + score_key (str): Specify one metric in evaluation results to score + candidates. Defaults to 'accuracy_top-1'. + constraints_range (Dict[str, Any]): Constraints to be used for + screening candidates. Defaults to dict(flops=(0, 330)). + estimator_cfg (dict, Optional): Used for building a resource estimator. + Defaults to None. + num_candidates (int): The number of the candidates consist of samples + from supernet and itself. Defaults to 1000. + num_samples (int): The number of sample in each sampling subnet. + Defaults to 10. + top_k (int): Choose top_k subnet from the candidates used to train + the supernet. Defaults to 5. + prob_schedule (str): The schedule to generate the probablity of + sampling from the candidates. The probablity will increase from + [init_prob, max_prob] during [schedule_start_iter, + schedule_end_iter]. Both of 'linear' schedule and 'consine' + schedule are supported. Defaults to 'linear'. + schedule_start_iter (int): The start iter of the prob_schedule. + Defaults to 10000. 10000 is corresponding to batch_size: 1024. + You should adptive it based on your batch_size. + schedule_end_iter (int): The end iter in of the prob_schedule. + Defaults to 144360. 144360 = 120(epoch) * 1203 (iters/epoch), + batch_size is 1024. You should adptive it based on the batch_size + and the total training epochs. + init_prob (float): The init probablity of the prob_schedule. + Defaults to 0.0. + max_prob (float): The max probablity of the prob_schedule. + Defaults to 0.8. + """ + + def __init__(self, + runner, + dataloader: Union[Dict, DataLoader], + dataloader_val: Union[Dict, DataLoader], + evaluator: Union[Evaluator, Dict, List], + max_iters: int, + val_begin: int = 1, + val_interval: int = 1000, + score_key: str = 'accuracy/top1', + constraints_range: Dict[str, Any] = dict(flops=(0, 330)), + estimator_cfg: Optional[Dict] = None, + num_candidates: int = 1000, + num_samples: int = 10, + top_k: int = 5, + prob_schedule: str = 'linear', + schedule_start_iter: int = 10000, + schedule_end_iter: int = 144360, + init_prob: float = 0., + max_prob: float = 0.8) -> None: + super().__init__(runner, dataloader, max_iters, val_begin, + val_interval) + if isinstance(dataloader_val, dict): + self.dataloader_val = runner.build_dataloader( + dataloader_val, seed=runner.seed) + else: + self.dataloader_val = dataloader_val + + if isinstance(evaluator, dict) or is_list_of(evaluator, dict): + self.evaluator = runner.build_evaluator(evaluator) + else: + self.evaluator = evaluator + + self.score_key = score_key + self.constraints_range = constraints_range + self.num_candidates = num_candidates + self.num_samples = num_samples + self.top_k = top_k + assert prob_schedule in ['linear', 'consine'] + self.prob_schedule = prob_schedule + self.schedule_start_iter = schedule_start_iter + self.schedule_end_iter = schedule_end_iter + self.init_prob = init_prob + self.max_prob = max_prob + self.cur_prob: float = 0. + + self.candidates = Candidates() + self.top_k_candidates = Candidates() + + # initialize estimator + estimator_cfg = dict() if estimator_cfg is None else estimator_cfg + if 'type' not in estimator_cfg: + estimator_cfg['type'] = 'mmrazor.ResourceEstimator' + self.estimator = TASK_UTILS.build(estimator_cfg) + + def run(self) -> None: + """Launch training.""" + self.runner.call_hook('before_train') + # In iteration-based training loop, we treat the whole training process + # as a big epoch and execute the corresponding hook. + self.runner.call_hook('before_train_epoch') + while self._iter < self._max_iters: + self.runner.model.train() + + data_batch = next(self.dataloader_iterator) + self.run_iter(data_batch) + + if (self.runner.val_loop is not None + and self._iter >= self.runner.val_begin + and self._iter % self.runner.val_interval == 0): + self.runner.val_loop.run() + self._save_candidates() + + self.runner.call_hook('after_train_epoch') + self.runner.call_hook('after_train') + + def sample_subnet(self) -> SupportRandomSubnet: + """Sample a subnet from top_k candidates one by one, then to train the + surpernet with the subnet. + + Steps: + 1. Update and get the `top_k_candidates`. + 1.1. Update the prob of sampling from the `candidates` based on + the `prob_schedule` and the current iter. + 1.2. Sample `num_samples` candidates from the supernet and the + `candidates` based on the updated prob(step 1.1). + 1.3. Val all candidates to get their scores, including the + sampled candidates(step 1.2). + 1.4. Update the `top_k_candidates` based on + their scores(step 1.3). + 2. Pop from the `top_k_candidates` one by one to train + the supernet. + """ + if len(self.top_k_candidates) == 0: + self.update_cur_prob(cur_iter=self._iter) + + sampled_candidates, num_sample_from_supernet = \ + self.get_candidates_with_sample(num_samples=self.num_samples) + + self.candidates.extend(sampled_candidates) + + self.update_candidates_scores() + + self.candidates.sort_by(key_indicator='score', reverse=True) + self.candidates = Candidates( + self.candidates.data[:self.num_candidates]) + self.top_k_candidates = Candidates( + self.candidates.data[:self.top_k]) + + top1_score = self.top_k_candidates.scores[0] + if (self._iter % self.val_interval) < self.top_k: + self.runner.logger.info( + f'GreedySampler: [{self._iter:>6d}] ' + f'prob {self.cur_prob:.3f} ' + f'num_sample_from_supernet ' + f'{num_sample_from_supernet}/{self.num_samples} ' + f'top1_score {top1_score:.3f} ' + f'cur_num_candidates: {len(self.candidates)}') + return self.top_k_candidates.subnets[0] + + def update_cur_prob(self, cur_iter: int) -> None: + """update current probablity of sampling from the candidates, which is + generated based on the probablity strategy and current iter.""" + if cur_iter > self.schedule_end_iter: + self.cur_prob = self.max_prob + elif cur_iter < self.schedule_start_iter: + self.cur_prob = self.init_prob + else: + schedule_all_steps = self.schedule_end_iter - \ + self.schedule_start_iter + schedule_cur_steps = cur_iter - self.schedule_start_iter + if self.prob_schedule == 'linear': + tmp = self.max_prob - self.init_prob + self.cur_prob = tmp / schedule_all_steps * schedule_cur_steps + elif self.prob_schedule == 'consine': + tmp_1 = (1 - self.init_prob) * 0.5 + tmp_2 = math.pi * schedule_cur_steps + tmp_3 = schedule_all_steps + self.cur_prob = tmp_1 * (1 + math.cos(tmp_2 / tmp_3)) \ + + self.init_prob + else: + raise ValueError('`prob_schedule` is eroor, it should be \ + one of `linear` and `consine`.') + + def get_candidates_with_sample(self, + num_samples: int) -> Tuple[Candidates, int]: + """Get candidates with sampling from supernet and the candidates based + on the current probablity.""" + num_sample_from_supernet = 0 + sampled_candidates = Candidates() + for _ in range(num_samples): + if random.random() >= self.cur_prob or len(self.candidates) == 0: + subnet = self._sample_from_supernet() + is_pass, _ = self._check_constraints(subnet) + if is_pass: + sampled_candidates.append(subnet) + num_sample_from_supernet += 1 + else: + sampled_candidates.append(self._sample_from_candidates()) + return sampled_candidates, num_sample_from_supernet + + def update_candidates_scores(self) -> None: + """Update candidates' scores, which are validated with the + `dataloader_val`.""" + for i, candidate in enumerate(self.candidates.subnets): + self.model.mutator.set_choices(candidate) + metrics = self._val_candidate() + score = metrics[self.score_key] if len(metrics) != 0 else 0. + self.candidates.set_resource(i, score, 'score') + + @torch.no_grad() + def _val_candidate(self) -> Dict: + """Run validation.""" + self.runner.model.eval() + for data_batch in self.dataloader_val: + outputs = self.runner.model.val_step(data_batch) + self.evaluator.process(data_samples=outputs, data_batch=data_batch) + metrics = self.evaluator.evaluate(len(self.dataloader_val.dataset)) + return metrics + + def _sample_from_supernet(self) -> SupportRandomSubnet: + """Sample from the supernet.""" + subnet = self.model.sample_subnet() + return subnet + + def _sample_from_candidates(self) -> SupportRandomSubnet: + """Sample from the candidates.""" + assert len(self.candidates) > 0 + subnet = random.choice(self.candidates.data) + return subnet + + def _check_constraints(self, random_subnet: SupportRandomSubnet): + """Check whether is beyond constraints. + + Returns: + bool, result: The result of checking. + """ + is_pass, results = check_subnet_resources( + model=self.model, + subnet=random_subnet, + estimator=self.estimator, + constraints_range=self.constraints_range) + + return is_pass, results + + def _save_candidates(self) -> None: + """Save the candidates to init the next searching.""" + save_path = os.path.join(self.runner.work_dir, 'candidates.pkl') + fileio.dump(self.candidates, save_path) + self.runner.logger.info(f'candidates.pkl saved in ' + f'{self.runner.work_dir}') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_val_loop.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_val_loop.py new file mode 100755 index 000000000..d61e2747f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_val_loop.py @@ -0,0 +1,96 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Optional, Union + +from mmengine.evaluator import Evaluator +from mmengine.runner import ValLoop +from torch.utils.data import DataLoader + +from mmrazor.models.utils import add_prefix +from mmrazor.registry import LOOPS, TASK_UTILS +from .utils import CalibrateBNMixin + + +@LOOPS.register_module() +class SubnetValLoop(ValLoop, CalibrateBNMixin): + """Loop for subnet validation in NAS with BN re-calibration. + + Args: + runner (Runner): A reference of runner. + dataloader (Dataloader or dict): A dataloader object or a dict to + build a dataloader. + evaluator (Evaluator or dict or list): Used for computing metrics. + fp16 (bool): Whether to enable fp16 validation. Defaults to + False. + evaluate_fixed_subnet (bool): Whether to evaluate a fixed subnet only + or not. Defaults to False. + calibrate_sample_num (int): The number of images to compute the true + average of per-batch mean/variance instead of the running average. + Defaults to 4096. + estimator_cfg (dict, Optional): Used for building a resource estimator. + Defaults to dict(type='mmrazor.ResourceEstimator'). + """ + + def __init__( + self, + runner, + dataloader: Union[DataLoader, Dict], + evaluator: Union[Evaluator, Dict, List], + fp16: bool = False, + evaluate_fixed_subnet: bool = False, + calibrate_sample_num: int = 4096, + estimator_cfg: Optional[Dict] = dict(type='mmrazor.ResourceEstimator') + ) -> None: + super().__init__(runner, dataloader, evaluator, fp16) + + if self.runner.distributed: + model = self.runner.model.module + else: + model = self.runner.model + + self.model = model + self.evaluate_fixed_subnet = evaluate_fixed_subnet + self.calibrate_sample_num = calibrate_sample_num + self.estimator = TASK_UTILS.build(estimator_cfg) + + def run(self): + """Launch validation.""" + self.runner.call_hook('before_val') + self.runner.call_hook('before_val_epoch') + + all_metrics = dict() + + if self.evaluate_fixed_subnet: + metrics = self._evaluate_once() + all_metrics.update(add_prefix(metrics, 'fix_subnet')) + elif hasattr(self.model, 'sample_kinds'): + for kind in self.model.sample_kinds: + if kind == 'max': + self.model.mutator.set_max_choices() + metrics = self._evaluate_once() + all_metrics.update(add_prefix(metrics, 'max_subnet')) + elif kind == 'min': + self.model.mutator.set_min_choices() + metrics = self._evaluate_once() + all_metrics.update(add_prefix(metrics, 'min_subnet')) + elif 'random' in kind: + self.model.mutator.set_choices( + self.model.mutator.sample_choices()) + metrics = self._evaluate_once() + all_metrics.update(add_prefix(metrics, f'{kind}_subnet')) + + self.runner.call_hook('after_val_epoch', metrics=all_metrics) + self.runner.call_hook('after_val') + + def _evaluate_once(self) -> Dict: + """Evaluate a subnet once with BN re-calibration.""" + self.calibrate_bn_statistics(self.runner.train_dataloader, + self.calibrate_sample_num) + self.runner.model.eval() + for idx, data_batch in enumerate(self.dataloader): + self.run_iter(idx, data_batch) + + metrics = self.evaluator.evaluate(len(self.dataloader.dataset)) + resource_metrics = self.estimator.estimate(self.model) + metrics.update(resource_metrics) + + return metrics diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/__init__.py new file mode 100755 index 000000000..90a2aea84 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .calibrate_bn_mixin import CalibrateBNMixin +from .check import check_subnet_resources +from .genetic import crossover + +__all__ = ['crossover', 'check_subnet_resources', 'CalibrateBNMixin'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/calibrate_bn_mixin.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/calibrate_bn_mixin.py new file mode 100755 index 000000000..3e0fe4953 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/calibrate_bn_mixin.py @@ -0,0 +1,141 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Any + +import torch +import torch.distributed as dist +from mmengine.runner import Runner, autocast +from torch import Tensor +from torch.nn.modules.batchnorm import _BatchNorm +from torch.utils.data import DataLoader + + +class AverageMeter: + """Computes and stores the average and current value.""" + + def __init__(self) -> None: + self.reset() + + def reset(self) -> None: + self.avg: Tensor = 0 + self.sum: Tensor = 0 + self.count: int = 0 + + def update(self, val: Any, batch_size: int = 1) -> None: + if dist.is_initialized() and dist.is_available(): + dist.all_reduce(val, dist.ReduceOp.SUM, async_op=False) + batch_size_tensor = torch.tensor([batch_size], device=val.device) + dist.all_reduce( + batch_size_tensor, dist.ReduceOp.SUM, async_op=False) + total_batch_size = batch_size_tensor.item() + + val /= (total_batch_size / batch_size) + batch_size = total_batch_size + + self.sum += val * batch_size + self.count += batch_size + self.avg = self.sum / self.count + + +class CalibrateBNMixin: + runner: Runner + fp16: bool = False + + @torch.no_grad() + def calibrate_bn_statistics(self, + dataloader: DataLoader, + calibrate_sample_num: int = 2000) -> None: + + def record_input_statistics_hook(bn_module: _BatchNorm, input: Tensor, + output: Tensor) -> None: + mean_average_meter: AverageMeter = bn_module.__mean_average_meter__ + var_average_meter: AverageMeter = bn_module.__var_average_meter__ + + real_input = input[0] + mean = real_input.mean((0, 2, 3)) + var = real_input.var((0, 2, 3), unbiased=True) + + mean_average_meter.update(mean, real_input.size(0)) + var_average_meter.update(var, real_input.size(0)) + + hook_handles = [] + + for name, module in self.runner.model.named_modules(): + if isinstance(module, _BatchNorm): + self.runner.logger.debug( + 'register `record_input_statistics_hook` to module: ' + f'{name}') + module.__mean_average_meter__ = AverageMeter() + module.__var_average_meter__ = AverageMeter() + handle = module.register_forward_hook( + record_input_statistics_hook) + hook_handles.append(handle) + + self.runner.model.train() + self.runner.logger.info('Start calibrating batch norm statistics') + self.runner.logger.info( + f'Total sample number for calibration: {calibrate_sample_num}') + remaining = calibrate_sample_num + for data_batch in dataloader: + if len(data_batch) >= remaining: + data_batch = data_batch[:remaining] + if isinstance(data_batch, torch.Tensor): + data_batch_nums = len(data_batch) + else: + data_batch_nums = len(data_batch['inputs']) + if dist.is_initialized() and dist.is_available(): + data_batch_tensor = torch.tensor( + [data_batch_nums], device=self.runner.model.device) + dist.all_reduce( + data_batch_tensor, dist.ReduceOp.SUM, async_op=False) + data_batch_nums = data_batch_tensor.item() + remaining -= data_batch_nums + + self.runner.logger.debug( + f'Remaining samples for calibration: {remaining}') + with autocast(enabled=self.fp16): + self.runner.model.test_step(data_batch) + + if remaining <= 0: + break + + for name, module in self.runner.model.named_modules(): + if isinstance(module, _BatchNorm): + mean_average_meter = module.__mean_average_meter__ + var_average_meter = module.__var_average_meter__ + if mean_average_meter.count == 0 or \ + var_average_meter.count == 0: + assert mean_average_meter.count == 0 and \ + var_average_meter.count == 0 + self.runner.logger.debug( + f'layer {name} is not chosen, ignored') + continue + + calibrated_bn_mean = mean_average_meter.avg + calibrated_bn_var = var_average_meter.avg + + feature_dim = calibrated_bn_mean.size(0) + + self.runner.logger.debug( + f'layer: {name}, ' + f'current feature dimension: {feature_dim}, ' + 'number of samples for calibration: ' + f'{mean_average_meter.count}, ' + 'l2 norm of calibrated running mean: ' + f'{calibrated_bn_mean.norm()}, ' + 'l2 norm of calibrated running var: ' + f'{calibrated_bn_var.norm()}, ' + 'l2 norm of original running mean: ' + f'{module.running_mean[:feature_dim].norm()}, ' + 'l2 norm of original running var: ' + f'{module.running_var[:feature_dim].norm()}, ') + + module.running_mean[:feature_dim].copy_(calibrated_bn_mean) + module.running_var[:feature_dim].copy_(calibrated_bn_var) + + del module.__mean_average_meter__ + del module.__var_average_meter__ + + self.runner.logger.debug('Remove all hooks for calibration') + self.runner.logger.info('Calibrate batch norm statistics done') + for handle in hook_handles: + handle.remove() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/check.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/check.py new file mode 100755 index 000000000..ad774f647 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/check.py @@ -0,0 +1,48 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Any, Dict, Tuple + +import torch + +from mmrazor.models import ResourceEstimator +from mmrazor.structures import export_fix_subnet +from mmrazor.utils import SupportRandomSubnet + +try: + from mmdet.models.detectors import BaseDetector +except ImportError: + from mmrazor.utils import get_placeholder + BaseDetector = get_placeholder('mmdet') + + +@torch.no_grad() +def check_subnet_resources( + model, + subnet: SupportRandomSubnet, + estimator: ResourceEstimator, + constraints_range: Dict[str, Any] = dict(flops=(0, 330)) +) -> Tuple[bool, Dict]: + """Check whether is beyond resources constraints. + + Returns: + bool, result: The result of checking. + """ + if constraints_range is None: + return True, dict() + + assert hasattr(model, 'mutator') and hasattr(model, 'architecture') + model.mutator.set_choices(subnet) + _, sliced_model = export_fix_subnet(model, slice_weight=True) + + model_to_check = sliced_model.architecture # type: ignore + if isinstance(model_to_check, BaseDetector): + results = estimator.estimate(model=model_to_check.backbone) + else: + results = estimator.estimate(model=model_to_check) + + for k, v in constraints_range.items(): + if not isinstance(v, (list, tuple)): + v = (0, v) + if results[k] < v[0] or results[k] > v[1]: + return False, results + + return True, results diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/genetic.py b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/genetic.py new file mode 100755 index 000000000..12a4e7863 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/genetic.py @@ -0,0 +1,31 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy + +import numpy as np + +from mmrazor.utils import SingleMutatorRandomSubnet + + +def crossover(random_subnet1: SingleMutatorRandomSubnet, + random_subnet2: SingleMutatorRandomSubnet, + prob: float = 0.5) -> SingleMutatorRandomSubnet: + """Crossover in genetic algorithm. + + Args: + random_subnet1 (SINGLE_MUTATOR_RANDOM_SUBNET): One of the subnets to + crossover. + random_subnet2 (SINGLE_MUTATOR_RANDOM_SUBNET): One of the subnets to + crossover. + prob (float): The probablity of getting choice from `random_subnet2`. + Defaults to 0.5. + + Returns: + SINGLE_MUTATOR_RANDOM_SUBNET: The result of crossover. + """ + assert prob >= 0. and prob <= 1., \ + 'The probability of crossover has to be between 0 and 1' + crossover_subnet = copy.deepcopy(random_subnet1) + for group_id, choice in random_subnet2.items(): + if np.random.random_sample() < prob: + crossover_subnet[group_id] = choice + return crossover_subnet diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/implementations/__init__.py new file mode 100755 index 000000000..a03158f53 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/implementations/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""impl folder is an experimental file structure to store algorithm +implementations. + +Previous file structure splits the files of an algorithm into different folders +according to the types of these files. It may make it hard to understand an +algorithm. So we add the impl folder, where all files of an algorithm are +stored in one folder. As this structure is experimental, it may change rapidly. +""" + +from . import pruning # noqa + +__all__ = ['pruning'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/__init__.py new file mode 100755 index 000000000..e28ae7dc2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from . import group_fisher + +__all__ = ['group_fisher'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/__init__.py new file mode 100755 index 000000000..5dd85ce3c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/__init__.py @@ -0,0 +1,24 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .algorithm import GroupFisherAlgorithm +from .counters import GroupFisherConv2dCounter, GroupFisherLinearCounter +from .hook import PruningStructureHook, ResourceInfoHook +from .mutator import GroupFisherChannelMutator +from .ops import GroupFisherConv2d, GroupFisherLinear, GroupFisherMixin +from .prune_deploy_sub_model import GroupFisherDeploySubModel +from .prune_sub_model import GroupFisherSubModel +from .unit import GroupFisherChannelUnit + +__all__ = [ + 'GroupFisherDeploySubModel', + 'GroupFisherSubModel', + 'GroupFisherAlgorithm', + 'GroupFisherConv2dCounter', + 'GroupFisherLinearCounter', + 'PruningStructureHook', + 'ResourceInfoHook', + 'GroupFisherChannelMutator', + 'GroupFisherChannelUnit', + 'GroupFisherConv2d', + 'GroupFisherLinear', + 'GroupFisherMixin', +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/algorithm.py b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/algorithm.py new file mode 100755 index 000000000..a90b406db --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/algorithm.py @@ -0,0 +1,86 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional, Union + +import torch +import torch.distributed as dist +import torch.nn as nn +from mmengine.logging import print_log +from mmengine.model import BaseModel, MMDistributedDataParallel + +from mmrazor.models.algorithms.base import BaseAlgorithm +from mmrazor.registry import MODEL_WRAPPERS, MODELS +from mmrazor.utils import RuntimeInfo +from .mutator import GroupFisherChannelMutator + + +@MODELS.register_module() +class GroupFisherAlgorithm(BaseAlgorithm): + """`Group Fisher Pruning for Practical Network Compression`. + https://arxiv.org/pdf/2108.00708.pdf. + + Args: + architecture (Union[BaseModel, Dict]): The model to be pruned. + mutator (Union[Dict, ChannelMutator], optional): The config + of a mutator. Defaults to dict( type='GroupFisherChannelMutator', + channel_unit_cfg=dict( type='GroupFisherChannelUnit')). + interval (int): The interval of pruning two channels. Defaults to 10. + data_preprocessor (Optional[Union[Dict, nn.Module]], optional): + Defaults to None. + init_cfg (Optional[Dict], optional): init config for the model. + Defaults to None. + """ + + def __init__(self, + architecture: Union[BaseModel, Dict], + mutator: Union[Dict, GroupFisherChannelMutator] = dict( + type='GroupFisherChannelMutator', + channel_unit_cfg=dict(type='GroupFisherChannelUnit')), + interval: int = 10, + data_preprocessor: Optional[Union[Dict, nn.Module]] = None, + init_cfg: Optional[Dict] = None) -> None: + + super().__init__(architecture, data_preprocessor, init_cfg) + + self.interval = interval + + # using sync bn or normal bn + if dist.is_initialized(): + print_log('Convert Bn to SyncBn.') + self.architecture = nn.SyncBatchNorm.convert_sync_batchnorm( + self.architecture) + else: + from mmengine.model import revert_sync_batchnorm + self.architecture = revert_sync_batchnorm(self.architecture) + + # mutator + self.mutator: GroupFisherChannelMutator = MODELS.build(mutator) + self.mutator.prepare_from_supernet(self.architecture) + + def train_step(self, data: Union[dict, tuple, list], + optim_wrapper) -> Dict[str, torch.Tensor]: + return self._train_step(data, optim_wrapper) + + def _train_step(self, data: Union[dict, tuple, list], optim_wrapper): + """Train step function for GroupFisherAlgorithm and GroupFisherDDP.""" + self.mutator.start_record_info() + res = super().train_step(data, optim_wrapper) + self.mutator.end_record_info() + + self.mutator.update_imp() + self.mutator.reset_recorded_info() + + if RuntimeInfo.iter() % self.interval == 0: + self.mutator.try_prune() + self.mutator.reset_imp() + + return res + + +@MODEL_WRAPPERS.register_module() +class GroupFisherDDP(MMDistributedDataParallel): + """Train step for group fisher.""" + + def train_step(self, data: Union[dict, tuple, list], + optim_wrapper) -> Dict[str, torch.Tensor]: + algorithm = self.module + return GroupFisherAlgorithm._train_step(algorithm, data, optim_wrapper) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/counters.py b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/counters.py new file mode 100755 index 000000000..a8888e1dd --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/counters.py @@ -0,0 +1,16 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmrazor.models.task_modules.estimators.counters import ( + DynamicConv2dCounter, DynamicLinearCounter) +from mmrazor.registry import TASK_UTILS + + +@TASK_UTILS.register_module() +class GroupFisherConv2dCounter(DynamicConv2dCounter): + """Counter of GroupFisherConv2d.""" + pass + + +@TASK_UTILS.register_module() +class GroupFisherLinearCounter(DynamicLinearCounter): + """Counter of GroupFisherLinear.""" + pass diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/hook.py b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/hook.py new file mode 100755 index 000000000..524503dc1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/hook.py @@ -0,0 +1,198 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +from mmengine.dist import master_only +from mmengine.hooks import Hook +from mmengine.runner import Runner, save_checkpoint +from torch import distributed as torch_dist + +from mmrazor.models.algorithms import BaseAlgorithm +from mmrazor.models.mutators.channel_mutator.channel_mutator import \ + ChannelMutator +from mmrazor.models.task_modules.demo_inputs import DefaultDemoInput +from mmrazor.models.task_modules.estimators import ResourceEstimator +from mmrazor.registry import HOOKS, TASK_UTILS +from mmrazor.utils import RuntimeInfo, print_log + + +def get_model_from_runner(runner): + """Get the model from a runner.""" + if torch_dist.is_initialized(): + return runner.model.module + else: + return runner.model + + +def is_pruning_algorithm(algorithm): + """Check whether a model is a pruning algorithm.""" + return isinstance(algorithm, BaseAlgorithm) \ + and isinstance(getattr(algorithm, 'mutator', None), ChannelMutator) # noqa + + +@HOOKS.register_module() +class PruningStructureHook(Hook): + """This hook is used to display the structurn information during pruning. + + Args: + by_epoch (bool, optional): Whether to display structure information + iteratively by epoch. Defaults to True. + interval (int, optional): The interval between two structure + information display. + """ + + def __init__(self, by_epoch=True, interval=1) -> None: + + super().__init__() + self.by_epoch = by_epoch + self.interval = interval + + def show_unit_info(self, algorithm): + """Show unit information of an algorithm.""" + if is_pruning_algorithm(algorithm): + chices = algorithm.mutator.choice_template + import json + print_log(json.dumps(chices, indent=4)) + + for unit in algorithm.mutator.mutable_units: + if hasattr(unit, 'importance'): + imp = unit.importance() + print_log( + f'{unit.name}: \t{imp.min().item()}\t{imp.max().item()}' # noqa + ) + + @master_only + def show(self, runner): + """Show pruning algorithm information of a runner.""" + algorithm = get_model_from_runner(runner) + if is_pruning_algorithm(algorithm): + self.show_unit_info(algorithm) + + # hook points + + def after_train_epoch(self, runner) -> None: + if self.by_epoch and RuntimeInfo.epoch() % self.interval == 0: + self.show(runner) + + def after_train_iter(self, runner, batch_idx: int, data_batch, + outputs) -> None: + if not self.by_epoch and RuntimeInfo.iter() % self.interval == 0: + self.show(runner) + + +def input_generator_wrapper(model, demp_input: DefaultDemoInput): + + def input_generator(input_shape): + res = demp_input.get_data(model) + return res + + return input_generator + + +@HOOKS.register_module() +class ResourceInfoHook(Hook): + """This hook is used to display the resource related information and save + the checkpoint according to a threshold during pruning. + + Args: + demo_input (dict, optional): the demo input for ResourceEstimator. + Defaults to DefaultDemoInput([1, 3, 224, 224]). + interval (int, optional): the interval to check the resource. Defaults + to 10. + resource_type (str, optional): the type of resource to check. + Defaults to 'flops'. + save_ckpt_thr (list, optional): the threshold to save checkpoint. + Defaults to [0.5]. + early_stop (bool, optional): whether to stop when all checkpoints have + been saved according to save_ckpt_thr. Defaults to True. + """ + + def __init__(self, + demo_input=DefaultDemoInput([1, 3, 224, 224]), + interval=10, + resource_type='flops', + save_ckpt_thr=[0.5], + early_stop=True) -> None: + + super().__init__() + if isinstance(demo_input, dict): + demo_input = TASK_UTILS.build(demo_input) + + self.demo_input = demo_input + self.save_ckpt_thr = sorted( + save_ckpt_thr, reverse=True) # big to small + self.resource_type = resource_type + self.early_stop = early_stop + self.estimator: ResourceEstimator = TASK_UTILS.build( + dict( + _scope_='mmrazor', + type='ResourceEstimator', + flops_params_cfg=dict( + input_shape=tuple(demo_input.input_shape), ))) + self.interval = interval + self.origin_delta = None + + def before_run(self, runner) -> None: + """Init original_resource.""" + model = get_model_from_runner(runner) + original_resource = self._evaluate(model) + print_log(f'get original resource: {original_resource}') + + self.origin_delta = original_resource[self.resource_type] + + # save checkpoint + + def after_train_iter(self, + runner: Runner, + batch_idx: int, + data_batch=None, + outputs=None) -> None: + """Check resource after train iteration.""" + if RuntimeInfo.iter() % self.interval == 0 and len( + self.save_ckpt_thr) > 0: + model = get_model_from_runner(runner) + current_delta = self._evaluate(model)[self.resource_type] + percent = current_delta / self.origin_delta + if percent < self.save_ckpt_thr[0]: + self._save_checkpoint(model, runner.work_dir, + self.save_ckpt_thr.pop(0)) + if self.early_stop and len(self.save_ckpt_thr) == 0: + exit() + + # show info + + @master_only + def after_train_epoch(self, runner) -> None: + """Check resource after train epoch.""" + model = get_model_from_runner(runner) + current_delta = self._evaluate(model)[self.resource_type] + print_log( + f'current {self.resource_type}: {current_delta} / {self.origin_delta}' # noqa + ) + + # + + def _evaluate(self, model: nn.Module): + """Evaluate the resource required by a model.""" + with torch.no_grad(): + training = model.training + model.eval() + res = self.estimator.estimate( + model, + flops_params_cfg=dict( + input_constructor=input_generator_wrapper( + model, + self.demo_input, + ))) + if training: + model.train() + return res + + @master_only + def _save_checkpoint(self, model, path, delta_percent): + """Save the checkpoint of a model.""" + ckpt = {'state_dict': model.state_dict()} + save_path = f'{path}/{self.resource_type}_{delta_percent:.2f}.pth' + save_checkpoint(ckpt, save_path) + print_log( + f'Save checkpoint to {save_path} with {self._evaluate(model)}' # noqa + ) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/mutator.py b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/mutator.py new file mode 100755 index 000000000..d9e521a38 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/mutator.py @@ -0,0 +1,87 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +from typing import Dict, List, Type, Union + +from mmengine.dist import dist + +from mmrazor.models.mutators.channel_mutator.channel_mutator import \ + ChannelMutator +from mmrazor.registry import MODELS +from mmrazor.utils import print_log +from .unit import GroupFisherChannelUnit + + +@MODELS.register_module() +class GroupFisherChannelMutator(ChannelMutator[GroupFisherChannelUnit]): + """Channel mutator for GroupFisher Pruning Algorithm. + + Args: + channel_unit_cfg (Union[dict, Type[ChannelUnitType]], optional): + Config of MutableChannelUnits. Defaults to + dict(type='GroupFisherChannelUnit', + default_args=dict(choice_mode='ratio')). + parse_cfg (Dict): The config of the tracer to parse the model. + Defaults to dict(type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='FxTracer'). + """ + + def __init__(self, + channel_unit_cfg: Union[dict, + Type[GroupFisherChannelUnit]] = dict( + type='GroupFisherChannelUnit'), + parse_cfg: Dict = dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='FxTracer'), + **kwargs) -> None: + super().__init__(channel_unit_cfg, parse_cfg, **kwargs) + self.mutable_units: List[GroupFisherChannelUnit] + + def start_record_info(self) -> None: + """Start recording the related information.""" + for unit in self.mutable_units: + unit.start_record_fisher_info() + + def end_record_info(self) -> None: + """Stop recording the related information.""" + for unit in self.mutable_units: + unit.end_record_fisher_info() + + def reset_recorded_info(self) -> None: + """Reset the related information.""" + for unit in self.mutable_units: + unit.reset_recorded() + + def try_prune(self) -> None: + """Prune the channel with the minimum fisher unless it is the last + channel of the current layer.""" + min_imp = 1e5 + min_unit = self.mutable_units[0] + for unit in self.mutable_units: + if unit.mutable_channel.activated_channels > 1: + imp = unit.importance() + if imp.isnan().any(): + if dist.get_rank() == 0: + print_log( + f'{unit.name} detects nan in importance, this pruning skips.' # noqa + ) + return + if imp.min() < min_imp: + min_imp = imp.min().item() + min_unit = unit + if min_unit.try_to_prune_min_channel(): + if dist.get_rank() == 0: + print_log( + f'{min_unit.name} prunes a channel with min imp = {min_imp}' # noqa + ) + + def update_imp(self) -> None: + """Update the fisher information of each unit.""" + for unit in self.mutable_units: + unit.update_fisher_info() + + def reset_imp(self) -> None: + """Reset the fisher information of each unit.""" + for unit in self.mutable_units: + unit.reset_fisher_info() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/ops.py b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/ops.py new file mode 100755 index 000000000..35dbbd749 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/ops.py @@ -0,0 +1,150 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List + +import torch + +from mmrazor.models.architectures.dynamic_ops.bricks.dynamic_conv import \ + DynamicConv2d +from mmrazor.models.architectures.dynamic_ops.bricks.dynamic_linear import \ + DynamicLinear + + +class GroupFisherMixin: + """The mixin class for GroupFisher ops.""" + + def _init(self) -> None: + self.handlers: list = [] + self.recorded_input: List = [] + self.recorded_grad: List = [] + self.recorded_out_shape: List = [] + + def forward_hook_wrapper(self): + """Wrap the hook used in forward.""" + + def forward_hook(module: GroupFisherMixin, input, output): + module.recorded_out_shape.append(output.shape) + module.recorded_input.append(input[0]) + + return forward_hook + + def backward_hook_wrapper(self): + """Wrap the hook used in backward.""" + + def backward_hook(module: GroupFisherMixin, grad_in, grad_out): + module.recorded_grad.insert(0, grad_in[0]) + + return backward_hook + + def start_record(self: torch.nn.Module) -> None: + """Start recording information during forward and backward.""" + self.end_record() # ensure to run start_record only once + self.handlers.append( + self.register_forward_hook(self.forward_hook_wrapper())) + self.handlers.append( + self.register_backward_hook(self.backward_hook_wrapper())) + + def end_record(self): + """Stop recording information during forward and backward.""" + for handle in self.handlers: + handle.remove() + self.handlers = [] + + def reset_recorded(self): + """Reset the recorded information.""" + self.recorded_input = [] + self.recorded_grad = [] + self.recorded_out_shape = [] + + @property + def delta_flop_of_a_out_channel(self): + raise NotImplementedError() + + @property + def delta_flop_of_a_in_channel(self): + raise NotImplementedError() + + @property + def delta_memory_of_a_out_channel(self): + raise NotImplementedError() + + +class GroupFisherConv2d(DynamicConv2d, GroupFisherMixin): + """The Dynamic Conv2d operation used in GroupFisher Algorithm.""" + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self._init() + + @property + def delta_flop_of_a_out_channel(self) -> torch.Tensor: + """Calculate the summation of flops when prune an out_channel.""" + delta_flop_sum = 0 + for shape in self.recorded_out_shape: + _, _, h, w = shape + in_c = int(self.mutable_attrs['in_channels'].current_mask.float(). + sum().item()) + # normal conv + if self.groups == 1: + delta_flop = h * w * self.kernel_size[0] * self.kernel_size[ + 1] * in_c + # dwconv + elif self.groups == self.in_channels == self.out_channels: + delta_flop = h * w * self.kernel_size[0] * self.kernel_size[1] + # groupwise conv + else: + raise NotImplementedError() + delta_flop_sum += delta_flop + return delta_flop_sum + + @property + def delta_flop_of_a_in_channel(self): + """Calculate the summation of flops when prune an in_channel.""" + delta_flop_sum = 0 + for shape in self.recorded_out_shape: + _, out_c, h, w = shape + # normal conv + if self.groups == 1: + delta_flop = h * w * self.kernel_size[0] * self.kernel_size[ + 1] * out_c + # dwconv + elif self.groups == self.in_channels == self.out_channels: + delta_flop = h * w * self.kernel_size[0] * self.kernel_size[1] + # groupwise conv + else: + raise NotImplementedError() + delta_flop_sum += delta_flop + return delta_flop_sum + + @property + def delta_memory_of_a_out_channel(self): + """Calculate the summation of memory when prune a channel.""" + delta_flop_sum = 0 + for shape in self.recorded_out_shape: + _, _, h, w = shape + delta_flop_sum += h * w + return delta_flop_sum + + +class GroupFisherLinear(DynamicLinear, GroupFisherMixin): + """The Dynamic Linear operation used in GroupFisher Algorithm.""" + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self._init() + + @property + def delta_flop_of_a_out_channel(self): + """Calculate the summation of flops when prune an out_channel.""" + in_c = self.mutable_attrs['in_channels'].current_mask.float().sum() + return in_c * len(self.recorded_out_shape) + + @property + def delta_flop_of_a_in_channel(self): + """Calculate the summation of flops when prune an in_channel.""" + out_c = self.mutable_attrs['out_channels'].current_mask.float().sum() + return out_c * len(self.recorded_out_shape) + + @property + def delta_memory_of_a_out_channel(self): + """Calculate the summation of memory when prune a channel.""" + return 1 * len(self.recorded_out_shape) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_deploy_sub_model.py b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_deploy_sub_model.py new file mode 100755 index 000000000..00a569ef5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_deploy_sub_model.py @@ -0,0 +1,78 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import json +import types +from typing import Union + +import torch.nn as nn +from mmengine import fileio + +from mmrazor.models.utils.expandable_utils import make_channel_divisible +from mmrazor.registry import MODELS +from mmrazor.structures.subnet.fix_subnet import (export_fix_subnet, + load_fix_subnet) +from mmrazor.utils import print_log + + +def post_process_for_mmdeploy_wrapper(divisor): + + def post_process_for_mmdeploy(model: nn.Module): + s = make_channel_divisible(model, divisor=divisor) + print_log(f'structure after make divisible: {json.dumps(s,indent=4)}') + + return post_process_for_mmdeploy + + +@MODELS.register_module() +def GroupFisherDeploySubModel(architecture, + fix_subnet: Union[dict, str] = {}, + divisor=1, + parse_cfg=dict( + _scope_='mmrazor', + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='FxTracer'), + **kwargs): + """Convert a architecture to a pruned static architecture for mmdeploy. + + Args: + architecture (Union[nn.Module, dict]): the model to be pruned. + fix_subnet (Union[dict, str]): the channel remaining ratio for each + unit, or the path of a file including this info. Defaults to {}. + divisor (int, optional): The divisor to make the channel number + divisible. Defaults to 1. + parse_cfg (dict, optional): The args for channel mutator. + Returns: + BaseModel: a BaseModel of mmengine. + """ + # import avoid circular import + from mmrazor.models.mutables import SequentialMutableChannelUnit + from mmrazor.models.mutators import ChannelMutator + from mmrazor.models.utils.expandable_utils.unit import ExpandableUnit + + # build architecture + if isinstance(architecture, dict): + architecture = MODELS.build(architecture) + assert isinstance(architecture, nn.Module) + + # to dynamic model + mutator = ChannelMutator[ExpandableUnit]( + channel_unit_cfg=SequentialMutableChannelUnit, parse_cfg=parse_cfg) + + mutator.prepare_from_supernet(architecture) + if isinstance(fix_subnet, str): + fix_subnet = fileio.load(fix_subnet) + assert isinstance(fix_subnet, dict) + mutator.set_choices(fix_subnet) + print_log(json.dumps(mutator.current_choices, indent=4)) + + fix_subnet = export_fix_subnet(architecture)[0] + load_fix_subnet(architecture, fix_subnet) + + # cooperate with mmdeploy to make the channel divisible after load + # the checkpoint. + if divisor != 1: + setattr( + architecture, 'post_process_for_mmdeploy', + types.MethodType( + post_process_for_mmdeploy_wrapper(divisor), architecture)) + return architecture diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_sub_model.py b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_sub_model.py new file mode 100755 index 000000000..87a77346d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_sub_model.py @@ -0,0 +1,105 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import json +import types + +import torch.nn as nn +from mmengine import dist, fileio +from mmengine.model import BaseModel, BaseModule + +from mmrazor.models.algorithms import BaseAlgorithm +from mmrazor.models.utils.expandable_utils import make_channel_divisible +from mmrazor.registry import MODELS +from mmrazor.structures.subnet.fix_subnet import (export_fix_subnet, + load_fix_subnet) +from mmrazor.utils import RuntimeInfo, print_log + + +def clean_params_init_info(model: nn.Module): + """Clean param init info.""" + if hasattr(model, '_params_init_info'): + delattr(model, '_params_init_info') + for module in model.modules(): + if hasattr(module, '_params_init_info'): + delattr(module, '_params_init_info') + + +def clean_init_cfg(model: BaseModule): + """Clean init cfg.""" + for module in model.modules(): + if module is model: + continue + if isinstance(module, BaseModule): + module.init_cfg = {} + + +def hacky_init_weights_wrapper(fix_subnet): + """This init weight method is used to prevent the model init again after + build. + + Besides, It also save fix_subnet.json after RuntimeInfo is ready. + """ + + def hacky_init_weights(model): + if dist.get_rank() == 0: + try: + work_dir = RuntimeInfo.work_dir() + fileio.dump( + fix_subnet, work_dir + '/fix_subnet.json', indent=4) + print_log( + f'save pruning structure in {work_dir}/fix_subnet.json') + except Exception: + pass + + return hacky_init_weights + + +@MODELS.register_module() +def GroupFisherSubModel( + algorithm, + divisor=1, + **kargs, +): + """Convert a algorithm(with an architecture) to a static pruned + architecture. + + Args: + algorithm (Union[BaseAlgorithm, dict]): The pruning algorithm to + finetune. + divisor (int): The divisor to make the channel number + divisible. Defaults to 1. + + Returns: + nn.Module: a static model. + """ + # init algorithm + if isinstance(algorithm, dict): + algorithm = MODELS.build(algorithm) # type: ignore + assert isinstance(algorithm, BaseAlgorithm) + algorithm.init_weights() + clean_params_init_info(algorithm) + + pruning_structure = algorithm.mutator.choice_template + print_log('PruneSubModel get pruning structure:') + print_log(json.dumps(pruning_structure, indent=4)) + + # to static model + fix_mutable = export_fix_subnet(algorithm.architecture)[0] + load_fix_subnet(algorithm.architecture, fix_mutable) + model = algorithm.architecture + + # make channel divisible + if divisor != 1: + divisible_structure = make_channel_divisible( + model, divisor=divisor, zero_weight=False) + + print_log('PruneSubModel get divisible pruning structure:') + print_log(json.dumps(divisible_structure, indent=4)) + pruning_structure = divisible_structure + + # refine model + model.data_preprocessor = algorithm.data_preprocessor + if isinstance(model, BaseModel): + model.init_cfg = None + model.init_weights = types.MethodType( + hacky_init_weights_wrapper(pruning_structure), model) + return model diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/unit.py b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/unit.py new file mode 100755 index 000000000..1c9128b78 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/unit.py @@ -0,0 +1,230 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List + +import torch +import torch.nn as nn +from mmengine.model.utils import _BatchNormXd +from mmengine.utils.dl_utils.parrots_wrapper import \ + SyncBatchNorm as EngineSyncBatchNorm +from torch import distributed as dist + +import mmrazor.models.architectures.dynamic_ops as dynamic_ops +from mmrazor.models.mutables.mutable_channel.mutable_channel_container import \ + MutableChannelContainer +from mmrazor.models.mutables.mutable_channel.units.l1_mutable_channel_unit import \ + L1MutableChannelUnit # noqa +from mmrazor.registry import MODELS +from .ops import GroupFisherConv2d, GroupFisherLinear, GroupFisherMixin + + +@MODELS.register_module() +class GroupFisherChannelUnit(L1MutableChannelUnit): + """ChannelUnit for GroupFisher Pruning Algorithm. + + Args: + num_channels (int): Number of channels. + normalization_type (str): Type of normalization. It can be one of + ['flops','act','none',]. Defaults to 'flop'. + mutate_linear (bool): Whether to prune linear layers. + """ + + def __init__(self, + num_channels: int, + normalization_type: str = 'flops', + mutate_linear=False, + *args) -> None: + super().__init__(num_channels, *args) + normalized_fisher_info = torch.zeros([self.num_channels]) + self.register_buffer('normalized_fisher_info', normalized_fisher_info) + self.normalized_fisher_info: torch.Tensor + + self.hook_handles: List = [] + assert normalization_type in ['flops', 'act', 'none'] + self.delta_type = normalization_type + + self.mutate_linear = mutate_linear + + def prepare_for_pruning(self, model: nn.Module) -> None: + """Prepare for pruning, including register mutable channels. + + Args: + model (nn.Module): The model need to be pruned. + """ + # register MutableMask + self._replace_with_dynamic_ops( + model, { + nn.Conv2d: GroupFisherConv2d, + nn.BatchNorm2d: dynamic_ops.DynamicBatchNorm2d, + nn.Linear: GroupFisherLinear, + nn.SyncBatchNorm: dynamic_ops.DynamicSyncBatchNorm, + EngineSyncBatchNorm: dynamic_ops.DynamicSyncBatchNorm, + _BatchNormXd: dynamic_ops.DynamicBatchNormXd, + }) + self._register_channel_container(model, MutableChannelContainer) + self._register_mutable_channel(self.mutable_channel) + + # prune + def try_to_prune_min_channel(self) -> bool: + """Prune the channel with the minimum value of fisher information.""" + if self.mutable_channel.activated_channels > 1: + imp = self.importance() + index = imp.argmin() + self.mutable_channel.mask.scatter_(0, index, 0.0) + return True + else: + return False + + @property + def is_mutable(self) -> bool: + """Whether the unit is mutable.""" + mutable = super().is_mutable + if self.mutate_linear: + return mutable + else: + has_linear = False + for layer in self.input_related: + if isinstance(layer.module, nn.Linear): + has_linear = True + return mutable and (not has_linear) + + @property + def input_related_dynamic_ops(self): + for channel in self.input_related: + if isinstance(channel.module, GroupFisherMixin): + yield channel.module + + @property + def output_related_dynamic_ops(self): + for channel in self.output_related: + if isinstance(channel.module, GroupFisherMixin): + yield channel.module + + @property + def dynamic_ops(self): + for module in self.input_related_dynamic_ops: + yield module + for module in self.output_related_dynamic_ops: + yield module + + # fisher information recorded + + def start_record_fisher_info(self) -> None: + """Start recording the related fisher info of each channel.""" + for module in self.dynamic_ops: + module.start_record() + + def end_record_fisher_info(self) -> None: + """Stop recording the related fisher info of each channel.""" + for module in self.dynamic_ops: + module.end_record() + + def reset_recorded(self) -> None: + """Reset the recorded info of each channel.""" + for module in self.dynamic_ops: + module.reset_recorded() + + # fisher related computation + + def importance(self): + """The importance of each channel.""" + fisher = self.normalized_fisher_info.clone() + mask = self.mutable_channel.current_mask + n_mask = (1 - mask.float()).bool() + fisher.masked_fill_(n_mask, fisher.max() + 1) + return fisher + + def reset_fisher_info(self) -> None: + """Reset the related fisher info.""" + self.normalized_fisher_info.zero_() + + @torch.no_grad() + def update_fisher_info(self) -> None: + """Update the fisher info of each channel.""" + + batch_fisher_sum = self.current_batch_fisher + assert isinstance(batch_fisher_sum, torch.Tensor) + if dist.is_initialized(): + dist.all_reduce(batch_fisher_sum) + batch_fisher_sum = self._get_normalized_fisher_info( + batch_fisher_sum, self.delta_type) + self.normalized_fisher_info = self.normalized_fisher_info + batch_fisher_sum # noqa + + @property + def current_batch_fisher(self) -> torch.Tensor: + """Accumulate the unit's fisher info of this batch.""" + with torch.no_grad(): + fisher: torch.Tensor = 0 + for module in self.input_related_dynamic_ops: + fisher = fisher + self._fisher_of_a_module(module) + return (fisher**2).sum(0) # shape: [C] + + @torch.no_grad() + def _fisher_of_a_module(self, module: GroupFisherMixin) -> torch.Tensor: + """Calculate the fisher info of one module. + + Args: + module (GroupFisherConv2d): A `GroupFisherConv2d` module. + + Return: + torch.Tensor: Whose shape is [B C] + """ + assert len(module.recorded_input) > 0 and \ + len(module.recorded_input) == len(module.recorded_grad) + fisher_sum: torch.Tensor = 0 + for input, grad_input in zip(module.recorded_input, + module.recorded_grad): + fisher: torch.Tensor = input * grad_input + if len(fisher.shape) == 4: + fisher = fisher.sum(dim=[2, 3]) + assert len(fisher.shape) == 2 # B C + fisher_sum = fisher_sum + fisher + assert isinstance(fisher_sum, torch.Tensor) + # expand to full num_channel + batch_size = fisher_sum.shape[0] + mask = self.mutable_channel.current_mask.unsqueeze(0).expand( + [batch_size, self.num_channels]) + zeros = fisher_sum.new_zeros([batch_size, self.num_channels]) + fisher_sum = zeros.masked_scatter_(mask, fisher_sum) + return fisher_sum + + @torch.no_grad() + def _get_normalized_fisher_info(self, + fisher_info, + delta_type='flop') -> torch.Tensor: + """Get the normalized fisher info. + + Args: + delta_type (str): Type of delta. Defaults to 'flop'. + """ + fisher = fisher_info.double() + if delta_type == 'flops': + delta_flop = self._delta_flop_of_a_channel + assert delta_flop > 0 + fisher = fisher / (float(delta_flop) / 1e9) + elif delta_type == 'act': + delta_memory = self._delta_memory_of_a_channel + assert delta_memory > 0 + fisher = fisher / (float(delta_memory) / 1e6) + elif delta_type == 'none': + pass + else: + raise NotImplementedError(delta_type) + return fisher + + @property + def _delta_flop_of_a_channel(self) -> torch.Tensor: + """Calculate the flops of a channel.""" + delta_flop = 0 + for module in self.output_related_dynamic_ops: + delta_flop += module.delta_flop_of_a_out_channel + for module in self.input_related_dynamic_ops: + delta_flop += module.delta_flop_of_a_in_channel + return delta_flop + + @property + def _delta_memory_of_a_channel(self) -> torch.Tensor: + """Calculate the memory of a channel.""" + delta_memory = 0 + for module in self.output_related_dynamic_ops: + delta_memory += module.delta_memory_of_a_out_channel + return delta_memory diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/__init__.py new file mode 100755 index 000000000..e5b9ec451 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/__init__.py @@ -0,0 +1,12 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .algorithms import * # noqa: F401,F403 +from .architectures import * # noqa: F401,F403 +from .distillers import * # noqa: F401,F403 +from .fake_quants import * # noqa: F401,F403 +from .losses import * # noqa: F401,F403 +from .mutables import * # noqa: F401,F403 +from .mutators import * # noqa: F401,F403 +from .observers import * # noqa: F401,F403 +from .quantizers import * # noqa: F401,F403 +from .task_modules import * # noqa: F401,F403 +from .utils import * # noqa: F401,F403 diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/__init__.py new file mode 100755 index 000000000..178cc6535 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/__init__.py @@ -0,0 +1,20 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .base import BaseAlgorithm +from .distill import (DAFLDataFreeDistillation, DataFreeDistillation, + FpnTeacherDistill, OverhaulFeatureDistillation, + SelfDistill, SingleTeacherDistill) +from .nas import (DSNAS, DSNASDDP, SPOS, Autoformer, AutoSlim, AutoSlimDDP, + BigNAS, BigNASDDP, Darts, DartsDDP) +from .pruning import DCFF, DMCP, DMCPDDP, SlimmableNetwork, SlimmableNetworkDDP +from .pruning.ite_prune_algorithm import ItePruneAlgorithm +from .quantization import MMArchitectureQuant, MMArchitectureQuantDDP + +__all__ = [ + 'SingleTeacherDistill', 'BaseAlgorithm', 'FpnTeacherDistill', 'SPOS', + 'SlimmableNetwork', 'SlimmableNetworkDDP', 'AutoSlim', 'AutoSlimDDP', + 'Darts', 'DartsDDP', 'DCFF', 'SelfDistill', 'DataFreeDistillation', + 'DAFLDataFreeDistillation', 'OverhaulFeatureDistillation', + 'ItePruneAlgorithm', 'DSNAS', 'DSNASDDP', 'Autoformer', 'BigNAS', + 'BigNASDDP', 'DMCP', 'DMCPDDP', 'MMArchitectureQuant', + 'MMArchitectureQuantDDP' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/base.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/base.py new file mode 100755 index 000000000..5bb98391b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/base.py @@ -0,0 +1,209 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Optional, OrderedDict, Tuple, Union + +import torch +import torch.nn as nn +from mmengine.model import BaseModel +from mmengine.structures import BaseDataElement + +from mmrazor.registry import MODELS + +LossResults = Dict[str, torch.Tensor] +TensorResults = Union[Tuple[torch.Tensor], torch.Tensor] +PredictResults = List[BaseDataElement] +ForwardResults = Union[LossResults, TensorResults, PredictResults] + + +@MODELS.register_module() +class BaseAlgorithm(BaseModel): + """Base class for algorithms. + + BaseAlgorithm inherit from BaseModel. BaseModel implements the basic + functions of the algorithmic model, such as weights initialize, + batch inputs preprocess(see more information in + :class:`BaseDataPreprocessor`), parse losses, and update model parameters. + More details of BaseModel could see docs for :class:`BaseModel`. + + :obj:`BaseAlgorithm` forward just is a wrapper of :obj:`BaseModel` forward. + Various compression algorithms can be implemented by inheriting + BaseAlgorithm. + + Subclasses inherit from BaseAlgorithm only need to override the + :meth:`loss`, which implements the logic to calculate loss, then + can be trained in the runner. + + Args: + architecture (dict | :obj:`BaseModel`): The config of + :class:`BaseModel` or built model. + data_preprocessor (dict | torch.nn.Module | None): The pre-process + config of :class:`BaseDataPreprocessor`. Defaults to None. + init_cfg (dict): The weight initialized config for + :class:`BaseModule`. + module_inplace(bool): Whether to allow module inplace attribute True. + Defaults to False. + + Note: + If `data_preprocessor` is None, :obj:`BaseAlgorithm` will set + `data_preprocessor` to model's `data_preprocessor`. + + + Attributes: + architecture (:obj:`BaseModel`): Model that needs to be compressed. + data_preprocessor (:obj:`BaseDataPreprocessor`): Used for + pre-processing data sampled by dataloader to the format accepted by + :meth:`forward`. + init_cfg (dict, optional): Initialization config dict. + """ + + def __init__(self, + architecture: Union[BaseModel, Dict], + data_preprocessor: Optional[Union[Dict, nn.Module]] = None, + init_cfg: Optional[Dict] = None, + module_inplace: bool = False) -> None: + + # super().__init__() needs built data_preprocessor, so + # build model first. + if isinstance(architecture, Dict): + architecture = MODELS.build(architecture) + + if not isinstance(architecture, BaseModel): + raise TypeError('architecture should be a `dict` or ' + f'`BaseModel` instance, but got ' + f'{type(architecture)}') + + # If `data_preprocessor` is None, there will set + # `data_preprocessor` to model's `data_preprocessor`. + if data_preprocessor is None: + # use model's data_preprocessor + data_preprocessor = getattr(architecture, 'data_preprocessor', + None) + super().__init__(data_preprocessor, init_cfg) + + # Cannot assign module before Module.__init__() + self.architecture = architecture + + # Find all nn.Modules in the model that contain the 'inplace' attribute + # and set them to False + self.module_inplace = module_inplace + if not self.module_inplace: + self.set_module_inplace_false(architecture, 'self.architecture') + pass + + def forward(self, + inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + mode: str = 'tensor') -> ForwardResults: + """Returns losses or predictions of training, validation, testing, and + simple inference process. + + ``forward`` method of BaseModel is an abstract method, its subclasses + must implement this method. + + Accepts ``batch_inputs`` and ``data_samples`` processed by + :attr:`data_preprocessor`, and returns results according to mode + arguments. + + During non-distributed training, validation, and testing process, + ``forward`` will be called by ``BaseModel.train_step``, + ``BaseModel.val_step`` and ``BaseModel.val_step`` directly. + + During distributed data parallel training process, + ``MMSeparateDistributedDataParallel.train_step`` will first call + ``DistributedDataParallel.forward`` to enable automatic + gradient synchronization, and then call ``forward`` to get training + loss. + + Args: + batch_inputs (torch.Tensor): batch input tensor collated by + :attr:`data_preprocessor`. + data_samples (List[BaseDataElement], optional): + data samples collated by :attr:`data_preprocessor`. + mode (str): mode should be one of ``loss``, ``predict`` and + ``tensor`` + - ``loss``: Called by ``train_step`` and return loss ``dict`` + used for logging + - ``predict``: Called by ``val_step`` and ``test_step`` + and return list of ``BaseDataElement`` results used for + computing metric. + - ``tensor``: Called by custom use to get ``Tensor`` type + results. + + Returns: + ForwardResults: + - If ``mode == loss``, return a ``dict`` of loss tensor used + for backward and logging. + - If ``mode == predict``, return a ``list`` of + :obj:`BaseDataElement` for computing metric + and getting inference result. + - If ``mode == tensor``, return a tensor or ``tuple`` of tensor + or ``dict of tensor for custom use. + """ + if mode == 'loss': + return self.loss(inputs, data_samples) + elif mode == 'tensor': + return self._forward(inputs, data_samples) + elif mode == 'predict': + return self._predict(inputs, data_samples) + else: + raise RuntimeError(f'Invalid mode "{mode}". ' + 'Only supports loss, predict and tensor mode') + + def loss( + self, + inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + ) -> LossResults: + """Calculate losses from a batch of inputs and data samples.""" + return self.architecture(inputs, data_samples, mode='loss') + + def _forward( + self, + inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + ) -> TensorResults: + """Network forward process.""" + return self.architecture(inputs, data_samples, mode='tensor') + + def _predict( + self, + inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + ) -> PredictResults: + """Predict results from a batch of inputs and data samples with post- + processing.""" + return self.architecture(inputs, data_samples, mode='predict') + + def set_module_inplace_false(self, architecture: Union[OrderedDict, + nn.Module], + varstr: str) -> None: + """Find all nn.Modules in the model that contain the 'inplace' + attribute and set them to False in order to prevent occur error in + Recorders using recursion algorithm. + + This function will disassemble the Args architecture .If type + 'nn.Module' is detected, determine if it contains an 'inplace' + attribute and set False if it does. If none, get the OrderedDict + and then iterate through the dictionary to continue the recursive + search. + + Args: + architecture (OrderedDict | nn.Module): The config OrderedDict + for model or built model. + varstr (str): Records the call-level string containing the + 'inplace' attribute. + + Returns: + None + """ + + if isinstance(architecture, nn.Module): + if hasattr(eval(varstr), 'inplace'): + eval(varstr).inplace = False + else: + self.set_module_inplace_false(architecture._modules, + varstr + '._modules') + elif isinstance(architecture, OrderedDict): + for key, value in architecture.items(): + self.set_module_inplace_false(value, varstr + f"['{key}']") + else: + return diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/__init__.py new file mode 100755 index 000000000..40bc62a46 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/__init__.py @@ -0,0 +1,10 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .configurable import (DAFLDataFreeDistillation, DataFreeDistillation, + FpnTeacherDistill, OverhaulFeatureDistillation, + SelfDistill, SingleTeacherDistill) + +__all__ = [ + 'SingleTeacherDistill', 'FpnTeacherDistill', 'SelfDistill', + 'DataFreeDistillation', 'DAFLDataFreeDistillation', + 'OverhaulFeatureDistillation' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/__init__.py new file mode 100755 index 000000000..8902f737c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .datafree_distillation import (DAFLDataFreeDistillation, + DataFreeDistillation) +from .fpn_teacher_distill import FpnTeacherDistill +from .overhaul_feature_distillation import OverhaulFeatureDistillation +from .self_distill import SelfDistill +from .single_teacher_distill import SingleTeacherDistill + +__all__ = [ + 'SelfDistill', 'SingleTeacherDistill', 'FpnTeacherDistill', + 'DataFreeDistillation', 'DAFLDataFreeDistillation', + 'OverhaulFeatureDistillation' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/datafree_distillation.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/datafree_distillation.py new file mode 100755 index 000000000..1aff807cd --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/datafree_distillation.py @@ -0,0 +1,229 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Tuple + +import torch +import torch.nn as nn +from mmengine.optim import OPTIMIZERS, OptimWrapper +from mmengine.runner import load_checkpoint + +from mmrazor.models.utils import add_prefix, set_requires_grad +from mmrazor.registry import MODELS +from ...base import BaseAlgorithm + + +@MODELS.register_module() +class DataFreeDistillation(BaseAlgorithm): + """Algorithm for data-free teacher-student distillation Typically, the + teacher is a pretrained model and the student is a small model trained on + the generator's output. The student is trained to mimic the behavior of the + teacher. The generator is trained to generate images that are similar to + the real images. + + Args: + distiller (dict): The config dict for built distiller. + generator_distiller (dict): The distiller collecting outputs & losses + to update the generator. + teachers (dict[str, dict]): The dict of config dict for teacher models + and their ckpt_path (optional). + generator (dictl): The config dict for built distiller generator. + student_iter (int): The number of student steps in train_step(). + Defaults to 1. + student_train_first (bool): Whether to train student in first place. + Defaults to False. + """ + + def __init__(self, + distiller: dict, + generator_distiller: dict, + teachers: Dict[str, Dict[str, dict]], + generator: dict, + student_iter: int = 1, + student_train_first: bool = False, + **kwargs) -> None: + super().__init__(**kwargs) + self.student_iter = student_iter + self.student_train_first = student_train_first + self.distiller = MODELS.build(distiller) + self.generator_distiller = MODELS.build(generator_distiller) + + if not isinstance(teachers, Dict): + raise TypeError('teacher should be a `dict` but got ' + f'{type(teachers)}') + + self.teachers = nn.ModuleDict() + for teacher_name, cfg in teachers.items(): + self.teachers[teacher_name] = MODELS.build(cfg['build_cfg']) + if 'ckpt_path' in cfg: + # avoid loaded parameters be overwritten + self.teachers[teacher_name].init_weights() + _ = load_checkpoint(self.teachers[teacher_name], + cfg['ckpt_path']) + self.teachers[teacher_name].eval() + set_requires_grad(self.teachers[teacher_name], False) + + if not isinstance(generator, Dict): + raise TypeError('generator should be a `dict` instance, but got ' + f'{type(generator)}') + self.generator = MODELS.build(generator) + + # In ``DataFreeDistiller``, the recorder manager is just + # constructed, but not really initialized yet. + self.distiller.prepare_from_student(self.student) + self.distiller.prepare_from_teacher(self.teachers) + self.generator_distiller.prepare_from_student(self.student) + self.generator_distiller.prepare_from_teacher(self.teachers) + + @property + def student(self) -> nn.Module: + """Alias for ``architecture``.""" + return self.architecture + + def train_step(self, data: Dict[str, List[dict]], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + """Train step for DataFreeDistillation. + + Args: + data (Dict[str, List[dict]]): Data sampled by dataloader. + optim_wrapper (OptimWrapper): A wrapper of optimizer to + update parameters. + """ + log_vars = dict() + for _, teacher in self.teachers.items(): + teacher.eval() + + if self.student_train_first: + _, dis_log_vars = self.train_student(data, + optim_wrapper['architecture']) + _, generator_loss_vars = self.train_generator( + data, optim_wrapper['generator']) + else: + _, generator_loss_vars = self.train_generator( + data, optim_wrapper['generator']) + _, dis_log_vars = self.train_student(data, + optim_wrapper['architecture']) + + log_vars.update(dis_log_vars) + log_vars.update(generator_loss_vars) + return log_vars + + def train_student( + self, data: Dict[str, List[dict]], optimizer: OPTIMIZERS + ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor]]: + """Train step for the student model. + + Args: + data (Dict[str, List[dict]]): Data sampled by dataloader. + optimizer (OPTIMIZERS): The optimizer to update student. + """ + log_vars = dict() + batch_size = len(data['inputs']) + + for _ in range(self.student_iter): + fakeimg_init = torch.randn( + (batch_size, self.generator.module.latent_dim)) + fakeimg = self.generator(fakeimg_init, batch_size).detach() + + with optimizer.optim_context(self.student): + pseudo_data = self.data_preprocessor(data, True) + pseudo_data_samples = pseudo_data['data_samples'] + # recorde the needed information + with self.distiller.student_recorders: + _ = self.student(fakeimg, pseudo_data_samples, mode='loss') + with self.distiller.teacher_recorders, torch.no_grad(): + for _, teacher in self.teachers.items(): + _ = teacher(fakeimg, pseudo_data_samples, mode='loss') + loss_distill = self.distiller.compute_distill_losses() + + distill_loss, distill_log_vars = self.parse_losses(loss_distill) + optimizer.update_params(distill_loss) + log_vars = dict(add_prefix(distill_log_vars, 'distill')) + + return distill_loss, log_vars + + def train_generator( + self, data: Dict[str, List[dict]], optimizer: OPTIMIZERS + ) -> Tuple[torch.Tensor, Dict[str, torch.Tensor]]: + """Train step for the generator. + + Args: + data (Dict[str, List[dict]]): Data sampled by dataloader. + optimizer (OPTIMIZERS): The optimizer to update generator. + """ + batch_size = len(data['inputs']) + fakeimg_init = torch.randn( + (batch_size, self.generator.module.latent_dim)) + fakeimg = self.generator(fakeimg_init, batch_size) + + with optimizer.optim_context(self.generator): + pseudo_data = self.data_preprocessor(data, True) + pseudo_data_samples = pseudo_data['data_samples'] + # recorde the needed information + with self.generator_distiller.student_recorders: + _ = self.student(fakeimg, pseudo_data_samples, mode='loss') + with self.generator_distiller.teacher_recorders: + for _, teacher in self.teachers.items(): + _ = teacher(fakeimg, pseudo_data_samples, mode='loss') + loss_generator = self.generator_distiller.compute_distill_losses() + + generator_loss, generator_loss_vars = self.parse_losses(loss_generator) + optimizer.update_params(generator_loss) + log_vars = dict(add_prefix(generator_loss_vars, 'generator')) + + return generator_loss, log_vars + + +@MODELS.register_module() +class DAFLDataFreeDistillation(DataFreeDistillation): + + def train_step(self, data: Dict[str, List[dict]], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + """DAFL train step. + + Args: + data (Dict[str, List[dict]): Data sampled by dataloader. + optim_wrapper (OptimWrapper): A wrapper of optimizer to + update parameters. + """ + log_vars = dict() + batch_size = len(data['inputs']) + + for _, teacher in self.teachers.items(): + teacher.eval() + + # fakeimg initialization and revised by generator. + fakeimg_init = torch.randn( + (batch_size, self.generator.module.latent_dim)) + fakeimg = self.generator(fakeimg_init, batch_size) + pseudo_data = self.data_preprocessor(data, True) + pseudo_data_samples = pseudo_data['data_samples'] + + with optim_wrapper['generator'].optim_context(self.generator): + # recorde the needed information + with self.generator_distiller.student_recorders: + _ = self.student(fakeimg, pseudo_data_samples, mode='loss') + with self.generator_distiller.teacher_recorders: + for _, teacher in self.teachers.items(): + _ = teacher(fakeimg, pseudo_data_samples, mode='loss') + loss_generator = self.generator_distiller.compute_distill_losses() + + generator_loss, generator_loss_vars = self.parse_losses(loss_generator) + log_vars.update(add_prefix(generator_loss_vars, 'generator')) + + with optim_wrapper['architecture'].optim_context(self.student): + # recorde the needed information + with self.distiller.student_recorders: + _ = self.student( + fakeimg.detach(), pseudo_data_samples, mode='loss') + with self.distiller.teacher_recorders, torch.no_grad(): + for _, teacher in self.teachers.items(): + _ = teacher( + fakeimg.detach(), pseudo_data_samples, mode='loss') + loss_distill = self.distiller.compute_distill_losses() + + distill_loss, distill_log_vars = self.parse_losses(loss_distill) + log_vars.update(add_prefix(distill_log_vars, 'distill')) + + optim_wrapper['generator'].update_params(generator_loss) + optim_wrapper['architecture'].update_params(distill_loss) + + return log_vars diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/fpn_teacher_distill.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/fpn_teacher_distill.py new file mode 100755 index 000000000..4a7027491 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/fpn_teacher_distill.py @@ -0,0 +1,59 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List, Optional + +import torch +from mmengine.structures import BaseDataElement + +from mmrazor.models.utils import add_prefix +from mmrazor.registry import MODELS +from ...base import LossResults +from .single_teacher_distill import SingleTeacherDistill + + +@MODELS.register_module() +class FpnTeacherDistill(SingleTeacherDistill): + """``FpnTeacherDistill`` means teacher only execute backbone and neck. + + If the intermediate results required for distill algorithm are generated by + the backbone and neck parts, using ``FpnTeacherDistill`` can speed up + training. + """ + + def loss( + self, + batch_inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + ) -> LossResults: + """Calculate losses from a batch of inputs and data samples.""" + + losses = dict() + # If the `override_data` of a delivery is False, the delivery will + # record the origin data. + self.distiller.set_deliveries_override(False) + + # Unlike ``SingleTeacherDistill``, teacher will only execute + # back + neck, not head, so there will be no loss. + if self.teacher_trainable: + with self.distiller.teacher_recorders, self.distiller.deliveries: + _ = self.teacher.extract_feat(batch_inputs) + else: + with self.distiller.teacher_recorders, self.distiller.deliveries: + with torch.no_grad(): + _ = self.teacher.extract_feat(batch_inputs) + + # If the `override_data` of a delivery is True, the delivery will + # override the origin data with the recorded data. + self.distiller.set_deliveries_override(True) + with self.distiller.student_recorders, self.distiller.deliveries: + student_losses = self.student( + batch_inputs, data_samples, mode='loss') + losses.update(add_prefix(student_losses, 'student')) + + if not self.distillation_stopped: + # Automatically compute distill losses based on + # `loss_forward_mappings`. + # The required data already exists in the recorders. + distill_losses = self.distiller.compute_distill_losses() + losses.update(add_prefix(distill_losses, 'distill')) + + return losses diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/overhaul_feature_distillation.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/overhaul_feature_distillation.py new file mode 100755 index 000000000..4b1992699 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/overhaul_feature_distillation.py @@ -0,0 +1,53 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional, Union + +from mmengine.model import BaseModel + +from mmrazor.registry import MODELS +from ....distillers import OFDDistiller +from .single_teacher_distill import SingleTeacherDistill + + +@MODELS.register_module() +class OverhaulFeatureDistillation(SingleTeacherDistill): + """`A Comprehensive Overhaul of Feature Distillation` + https://sites.google.com/view/byeongho-heo/overhaul. + + Inherited from ``SingleTeacherDistill``. + + + Args: + distiller (dict): The config dict for built distiller. Must be a + ``OFDDistiller``. + teacher (dict | BaseModel): The config dict for teacher model or built + teacher model. + teacher_ckpt (str): The path of teacher's checkpoint. Defaults to None. + teacher_trainable (bool): Whether the teacher is trainable. Defaults + to False. + teacher_norm_eval (bool): Whether to set teacher's norm layers to eval + mode, namely, freeze running stats (mean and var). Note: Effect on + Batch Norm and its variants only. Defaults to True. + student_trainable (bool): Whether the student is trainable. Defaults + to True. + calculate_student_loss (bool): Whether to calculate student loss + (original task loss) to update student model. Defaults to True. + """ + + def __init__(self, + distiller: dict, + teacher: Union[BaseModel, Dict], + teacher_ckpt: Optional[str] = None, + teacher_trainable: bool = False, + teacher_norm_eval: bool = True, + student_trainable: bool = True, + calculate_student_loss: bool = True, + **kwargs) -> None: + super().__init__(distiller, teacher, teacher_ckpt, teacher_trainable, + teacher_norm_eval, student_trainable, + calculate_student_loss, **kwargs) + + assert isinstance(self.distiller, OFDDistiller), ( + 'distiller of `OverhaulFeatureDistillation` expects `OFDDistiller`' + f', but get {type(self.distiller)}') + + self.distiller.init_ofd_connectors(self.teacher) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/self_distill.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/self_distill.py new file mode 100755 index 000000000..533d548e5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/self_distill.py @@ -0,0 +1,92 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List, Optional + +import torch +from mmengine.structures import BaseDataElement +from torch import nn + +from mmrazor.models.utils import add_prefix +from mmrazor.registry import MODELS +from ...base import BaseAlgorithm, LossResults + + +@MODELS.register_module() +class SelfDistill(BaseAlgorithm): + """``SelfDistill`` can be used to develop distill algorithms without + teacher. + + Args: + distiller (dict): The config dict for built distiller. Distiller may + have teacher. + student_trainable (bool): Whether the student is trainable. Defaults + to True. + calculate_student_loss (bool): Whether to calculate student loss + (original task loss) to update student model. Defaults to True. + """ + + def __init__(self, + distiller: dict, + student_trainable: bool = True, + calculate_student_loss: bool = True, + **kwargs) -> None: + super().__init__(**kwargs) + + self.distiller = MODELS.build(distiller) + # The student model will not calculate gradients and update parameters + # in some pretraining process. + self.student_trainable = student_trainable + + # The student loss will not be updated into ``losses`` in some + # pretraining process. + self.calculate_student_loss = calculate_student_loss + + # In ``ConfigurableDistller``, the recorder manager is just + # constructed, but not really initialized yet. + self.distiller.prepare_from_student(self.student) + # Still prepare from self-teacher. Teacher recorders of + # ``SelfDistiller`` hook from self.student but require detach(). + self.distiller.prepare_from_teacher(self.student) + + @property + def student(self) -> nn.Module: + """Alias for ``architecture``.""" + return self.architecture + + def loss( + self, + batch_inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + ) -> LossResults: + """Calculate losses from a batch of inputs and data samples.""" + + losses = dict() + + # If the `override_data` of a delivery is True, the delivery will + # override the origin data with the recorded data. + self.distiller.set_deliveries_override(True) + # Original task loss will not be used during some pretraining process. + if self.calculate_student_loss: + # teacher_recorders hook from student + with self.distiller.student_recorders, \ + self.distiller.teacher_recorders, \ + self.distiller.deliveries: + student_losses = self.student( + batch_inputs, data_samples, mode='loss') + losses.update(add_prefix(student_losses, 'student')) + else: + with self.distiller.student_recorders, \ + self.distiller.teacher_recorders, \ + self.distiller.deliveries: + if self.student_trainable: + _ = self.student(batch_inputs, data_samples, mode='loss') + else: + with torch.no_grad(): + _ = self.student( + batch_inputs, data_samples, mode='loss') + + # Automatically compute distill losses based on `loss_forward_mappings` + # The required data already exists in the recorders. + distill_losses = self.distiller.compute_distill_losses() + losses.update(add_prefix(distill_losses, 'distill')) + + return losses diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/single_teacher_distill.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/single_teacher_distill.py new file mode 100755 index 000000000..97139d256 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/single_teacher_distill.py @@ -0,0 +1,156 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Optional, Union + +import torch +from mmengine.model import BaseModel +from mmengine.runner import load_checkpoint +from mmengine.structures import BaseDataElement +from torch import nn +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.models.utils import add_prefix +from mmrazor.registry import MODELS +from ...base import BaseAlgorithm, LossResults + + +@MODELS.register_module() +class SingleTeacherDistill(BaseAlgorithm): + """``SingleTeacherDistill`` can be used to develop distill algorithms which + only use one teacher. + + Args: + distiller (dict): The config dict for built distiller. + teacher (dict | BaseModel): The config dict for teacher model or built + teacher model. + teacher_ckpt (str): The path of teacher's checkpoint. Defaults to None. + teacher_trainable (bool): Whether the teacher is trainable. Defaults + to False. + teacher_norm_eval (bool): Whether to set teacher's norm layers to eval + mode, namely, freeze running stats (mean and var). Note: Effect on + Batch Norm and its variants only. Defaults to True. + student_trainable (bool): Whether the student is trainable. Defaults + to True. + calculate_student_loss (bool): Whether to calculate student loss + (original task loss) to update student model. Defaults to True. + teacher_module_inplace(bool): Whether to allow teacher module inplace + attribute True. Defaults to False. + """ + + def __init__(self, + distiller: dict, + teacher: Union[BaseModel, Dict], + teacher_ckpt: Optional[str] = None, + teacher_trainable: bool = False, + teacher_norm_eval: bool = True, + student_trainable: bool = True, + calculate_student_loss: bool = True, + teacher_module_inplace: bool = False, + **kwargs) -> None: + super().__init__(**kwargs) + + self.distiller = MODELS.build(distiller) + + if isinstance(teacher, Dict): + teacher = MODELS.build(teacher) + + if not isinstance(teacher, BaseModel): + raise TypeError('teacher should be a `dict` or ' + f'`BaseModel` instance, but got ' + f'{type(teacher)}') + + self.teacher = teacher + + # Find all nn.Modules in the model that contain the 'inplace' attribute + # and set them to False. + self.teacher_module_inplace = teacher_module_inplace + if not self.teacher_module_inplace: + self.set_module_inplace_false(teacher, 'self.teacher') + + if teacher_ckpt: + _ = load_checkpoint(self.teacher, teacher_ckpt) + # avoid loaded parameters be overwritten + self.teacher._is_init = True + self.teacher_trainable = teacher_trainable + if not self.teacher_trainable: + for param in self.teacher.parameters(): + param.requires_grad = False + self.teacher_norm_eval = teacher_norm_eval + + # The student model will not calculate gradients and update parameters + # in some pretraining process. + self.student_trainable = student_trainable + + # The student loss will not be updated into ``losses`` in some + # pretraining process. + self.calculate_student_loss = calculate_student_loss + + # In ``ConfigurableDistller``, the recorder manager is just + # constructed, but not really initialized yet. + self.distiller.prepare_from_student(self.student) + self.distiller.prepare_from_teacher(self.teacher) + + # may be modified by stop distillation hook + self.distillation_stopped = False + + @property + def student(self) -> nn.Module: + """Alias for ``architecture``.""" + return self.architecture + + def loss( + self, + batch_inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + ) -> LossResults: + """Calculate losses from a batch of inputs and data samples.""" + + losses = dict() + + # If the `override_data` of a delivery is False, the delivery will + # record the origin data. + self.distiller.set_deliveries_override(False) + if self.teacher_trainable: + with self.distiller.teacher_recorders, self.distiller.deliveries: + teacher_losses = self.teacher( + batch_inputs, data_samples, mode='loss') + + losses.update(add_prefix(teacher_losses, 'teacher')) + else: + with self.distiller.teacher_recorders, self.distiller.deliveries: + with torch.no_grad(): + _ = self.teacher(batch_inputs, data_samples, mode='loss') + + # If the `override_data` of a delivery is True, the delivery will + # override the origin data with the recorded data. + self.distiller.set_deliveries_override(True) + # Original task loss will not be used during some pretraining process. + if self.calculate_student_loss: + with self.distiller.student_recorders, self.distiller.deliveries: + student_losses = self.student( + batch_inputs, data_samples, mode='loss') + losses.update(add_prefix(student_losses, 'student')) + else: + with self.distiller.student_recorders, self.distiller.deliveries: + if self.student_trainable: + _ = self.student(batch_inputs, data_samples, mode='loss') + else: + with torch.no_grad(): + _ = self.student( + batch_inputs, data_samples, mode='loss') + + if not self.distillation_stopped: + # Automatically compute distill losses based on + # `loss_forward_mappings`. + # The required data already exists in the recorders. + distill_losses = self.distiller.compute_distill_losses() + losses.update(add_prefix(distill_losses, 'distill')) + + return losses + + def train(self, mode: bool = True) -> None: + """Set distiller's forward mode.""" + super().train(mode) + if mode and self.teacher_norm_eval: + for m in self.teacher.modules(): + if isinstance(m, _BatchNorm): + m.eval() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/__init__.py new file mode 100755 index 000000000..6a9c29161 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/__init__.py @@ -0,0 +1,12 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .autoformer import Autoformer +from .autoslim import AutoSlim, AutoSlimDDP +from .bignas import BigNAS, BigNASDDP +from .darts import Darts, DartsDDP +from .dsnas import DSNAS, DSNASDDP +from .spos import SPOS + +__all__ = [ + 'SPOS', 'AutoSlim', 'AutoSlimDDP', 'BigNAS', 'BigNASDDP', 'Darts', + 'DartsDDP', 'DSNAS', 'DSNASDDP', 'DSNAS', 'DSNASDDP', 'Autoformer' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoformer.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoformer.py new file mode 100755 index 000000000..1ac5432d8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoformer.py @@ -0,0 +1,63 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Optional, Union + +import torch +from mmengine.model import BaseModel +from mmengine.structures import BaseDataElement +from torch import nn + +from mmrazor.models.mutators import NasMutator +from mmrazor.registry import MODELS +from ..base import BaseAlgorithm, LossResults + +VALID_MUTATOR_TYPE = Union[NasMutator, Dict] + + +@MODELS.register_module() +class Autoformer(BaseAlgorithm): + """Implementation of `Autoformer `_ + + AutoFormer is dedicated to vision transformer search. AutoFormer + entangles the weights of different blocks in the same layers during + supernet training. + The logic of the search part is implemented in + :class:`mmrazor.engine.EvolutionSearchLoop` + + Args: + architecture (dict|:obj:`BaseModel`): The config of :class:`BaseModel` + or built model. Corresponding to supernet in NAS algorithm. + mutator (VALID_MUTATOR_TYPE): The config of :class:`NasMutator` or + built mutator. + data_preprocessor (Optional[Union[dict, nn.Module]]): The pre-process + config of :class:`BaseDataPreprocessor`. Defaults to None. + init_cfg (Optional[dict]): Init config for ``BaseModule``. + Defaults to None. + """ + + def __init__(self, + architecture: Union[BaseModel, Dict], + mutator: VALID_MUTATOR_TYPE = None, + data_preprocessor: Optional[Union[dict, nn.Module]] = None, + init_cfg: Optional[dict] = None): + super().__init__(architecture, data_preprocessor, init_cfg) + + self.mutator = self._build_mutator(mutator) + self.mutator.prepare_from_supernet(self.architecture) + + def _build_mutator(self, mutator: VALID_MUTATOR_TYPE = None) -> NasMutator: + """build mutator.""" + if isinstance(mutator, dict): + mutator = MODELS.build(mutator) + if not isinstance(mutator, NasMutator): + raise TypeError('mutator should be a `dict` or `NasMutator` ' + f'instance, but got {type(mutator)}.') + return mutator + + def loss( + self, + batch_inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + ) -> LossResults: + """Calculate losses from a batch of inputs and data samples.""" + self.mutator.set_choices(self.mutator.sample_choices()) + return self.architecture(batch_inputs, data_samples, mode='loss') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoslim.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoslim.py new file mode 100755 index 000000000..dc8d54c0e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoslim.py @@ -0,0 +1,263 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +from pathlib import Path +from typing import Dict, List, Optional, Union + +import torch +from mmengine.model import BaseModel, MMDistributedDataParallel +from mmengine.optim import OptimWrapper +from mmengine.structures import BaseDataElement +from torch import nn +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.models.distillers import ConfigurableDistiller +from mmrazor.models.mutators import ChannelMutator +from mmrazor.models.utils import (add_prefix, + reinitialize_optim_wrapper_count_status) +from mmrazor.registry import MODEL_WRAPPERS, MODELS +from ..base import BaseAlgorithm + +VALID_MUTATOR_TYPE = Union[ChannelMutator, Dict] +VALID_DISTILLER_TYPE = Union[ConfigurableDistiller, Dict] +VALID_PATH_TYPE = Union[str, Path] +VALID_CHANNEL_CFG_PATH_TYPE = Union[VALID_PATH_TYPE, List[VALID_PATH_TYPE]] + + +@MODELS.register_module() +class AutoSlim(BaseAlgorithm): + """Implementation of Autoslim algorithm. Please refer to + https://arxiv.org/abs/1903.11728 for more details. + + Args: + architecture (dict|:obj:`BaseModel`): The config of :class:`BaseModel` + or built model. Corresponding to supernet in NAS algorithm. + mutator (VALID_MUTATOR_TYPE): The config of :class:`ChannelMutator` or + built mutator. + distiller (VALID_DISTILLER_TYPE): Cfg of :class:`ConfigurableDistiller` + or built distiller. + norm_training (bool): Whether set bn to training mode when model is + set to eval mode. Note that in slimmable networks, accumulating + different numbers of channels results in different feature means + and variances, which further leads to inaccurate statistics of + shared BN. Set ``norm_training`` to True to use the feature + means and variances in a batch. + data_preprocessor (Optional[Union[dict, nn.Module]]): The pre-process + config of :class:`BaseDataPreprocessor`. Defaults to None. + num_random_samples (int): number of random sample subnets. + Defaults to 2. + init_cfg (Optional[dict]): Init config for ``BaseModule``. + Defaults to None. + """ + + def __init__(self, + architecture: Union[BaseModel, Dict], + mutator: VALID_MUTATOR_TYPE = None, + distiller: VALID_DISTILLER_TYPE = None, + norm_training: bool = False, + num_random_samples: int = 2, + data_preprocessor: Optional[Union[Dict, nn.Module]] = None, + init_cfg: Optional[Dict] = None) -> None: + super().__init__(architecture, data_preprocessor, init_cfg) + + self.mutator = self._build_mutator(mutator) + # NOTE: `mutator.prepare_from_supernet` must be called + # before distiller initialized. + self.mutator.prepare_from_supernet(self.architecture) + + self.distiller = self._build_distiller(distiller) + self.distiller.prepare_from_teacher(self.architecture) + self.distiller.prepare_from_student(self.architecture) + + self.sample_kinds = ['max', 'min'] + for i in range(num_random_samples): + self.sample_kinds.append('random' + str(i)) + + self._optim_wrapper_count_status_reinitialized = False + self.norm_training = norm_training + + def _build_mutator(self, + mutator: VALID_MUTATOR_TYPE = None) -> ChannelMutator: + """Build mutator.""" + if isinstance(mutator, dict): + mutator = MODELS.build(mutator) + if not isinstance(mutator, ChannelMutator): + raise TypeError('mutator should be a `dict` or `ChannelMutator` ' + f'instance, but got {type(mutator)}.') + return mutator + + def _build_distiller( + self, + distiller: VALID_DISTILLER_TYPE = None) -> ConfigurableDistiller: + """Build distiller.""" + if isinstance(distiller, dict): + distiller = MODELS.build(distiller) + if not isinstance(distiller, ConfigurableDistiller): + raise TypeError('distiller should be a `dict` or ' + '`ConfigurableDistiller` instance, but got ' + f'{type(distiller)}') + return distiller + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + """Train step.""" + + def distill_step( + batch_inputs: torch.Tensor, data_samples: List[BaseDataElement] + ) -> Dict[str, torch.Tensor]: + subnet_losses = dict() + with optim_wrapper.optim_context( + self), self.distiller.student_recorders: # type: ignore + hard_loss = self(batch_inputs, data_samples, mode='loss') + soft_loss = self.distiller.compute_distill_losses() + + subnet_losses.update(hard_loss) + subnet_losses.update(soft_loss) + + parsed_subnet_losses, _ = self.parse_losses(subnet_losses) + optim_wrapper.update_params(parsed_subnet_losses) + + return subnet_losses + + if not self._optim_wrapper_count_status_reinitialized: + reinitialize_optim_wrapper_count_status( + model=self, + optim_wrapper=optim_wrapper, + accumulative_counts=len(self.sample_kinds)) + self._optim_wrapper_count_status_reinitialized = True + + input_data = self.data_preprocessor(data, True) + batch_inputs = input_data['inputs'] + data_samples = input_data['data_samples'] + + total_losses = dict() + for kind in self.sample_kinds: + # update the max subnet loss. + if kind == 'max': + self.mutator.set_choices(self.mutator.max_choices) + with optim_wrapper.optim_context( + self + ), self.distiller.teacher_recorders: # type: ignore + max_subnet_losses = self( + batch_inputs, data_samples, mode='loss') + parsed_max_subnet_losses, _ = self.parse_losses( + max_subnet_losses) + optim_wrapper.update_params(parsed_max_subnet_losses) + total_losses.update( + add_prefix(max_subnet_losses, 'max_subnet')) + # update the min subnet loss. + elif kind == 'min': + self.mutator.set_choices(self.mutator.min_choices) + min_subnet_losses = distill_step(batch_inputs, data_samples) + total_losses.update( + add_prefix(min_subnet_losses, 'min_subnet')) + # update the random subnets loss. + elif 'random' in kind: + self.mutator.set_choices(self.mutator.sample_choices()) + random_subnet_losses = distill_step(batch_inputs, data_samples) + total_losses.update( + add_prefix(random_subnet_losses, f'{kind}_subnet')) + + return total_losses + + def train(self, mode=True): + """Overwrite the train method in ``nn.Module`` to set ``nn.BatchNorm`` + to training mode when model is set to eval mode when + ``self.norm_training`` is ``True``. + + Args: + mode (bool): whether to set training mode (``True``) or evaluation + mode (``False``). Default: ``True``. + """ + super(AutoSlim, self).train(mode) + if not mode and self.norm_training: + for module in self.modules(): + if isinstance(module, _BatchNorm): + module.training = True + + +@MODEL_WRAPPERS.register_module() +class AutoSlimDDP(MMDistributedDataParallel): + """DDPwapper for autoslim.""" + + def __init__(self, + *, + device_ids: Optional[Union[List, int, torch.device]] = None, + **kwargs) -> None: + if device_ids is None: + if os.environ.get('LOCAL_RANK') is not None: + device_ids = [int(os.environ['LOCAL_RANK'])] + super().__init__(device_ids=device_ids, **kwargs) + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + + def distill_step( + batch_inputs: torch.Tensor, data_samples: List[BaseDataElement] + ) -> Dict[str, torch.Tensor]: + subnet_losses = dict() + with optim_wrapper.optim_context( + self + ), self.module.distiller.student_recorders: # type: ignore + hard_loss = self(batch_inputs, data_samples, mode='loss') + soft_loss = self.module.distiller.compute_distill_losses() + + subnet_losses.update(hard_loss) + subnet_losses.update(soft_loss) + + parsed_subnet_losses, _ = self.module.parse_losses( + subnet_losses) + optim_wrapper.update_params(parsed_subnet_losses) + + return subnet_losses + + if not self._optim_wrapper_count_status_reinitialized: + reinitialize_optim_wrapper_count_status( + model=self, + optim_wrapper=optim_wrapper, + accumulative_counts=len(self.module.sample_kinds)) + self._optim_wrapper_count_status_reinitialized = True + + input_data = self.module.data_preprocessor(data, True) + batch_inputs = input_data['inputs'] + data_samples = input_data['data_samples'] + + total_losses = dict() + for kind in self.module.sample_kinds: + # update the max subnet loss. + if kind == 'max': + self.module.mutator.set_max_choices() + with optim_wrapper.optim_context( + self + ), self.module.distiller.teacher_recorders: # type: ignore + max_subnet_losses = self( + batch_inputs, data_samples, mode='loss') + parsed_max_subnet_losses, _ = self.module.parse_losses( + max_subnet_losses) + optim_wrapper.update_params(parsed_max_subnet_losses) + total_losses.update( + add_prefix(max_subnet_losses, 'max_subnet')) + # update the min subnet loss. + elif kind == 'min': + self.module.mutator.set_min_choices() + min_subnet_losses = distill_step(batch_inputs, data_samples) + total_losses.update( + add_prefix(min_subnet_losses, 'min_subnet')) + # update the random subnets loss. + elif 'random' in kind: + self.module.mutator.set_choices( + self.module.mutator.sample_choices()) + random_subnet_losses = distill_step(batch_inputs, data_samples) + total_losses.update( + add_prefix(random_subnet_losses, f'{kind}_subnet')) + + return total_losses + + @property + def _optim_wrapper_count_status_reinitialized(self) -> bool: + return self.module._optim_wrapper_count_status_reinitialized + + @_optim_wrapper_count_status_reinitialized.setter + def _optim_wrapper_count_status_reinitialized(self, val: bool) -> None: + assert isinstance(val, bool) + + self.module._optim_wrapper_count_status_reinitialized = val diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/bignas.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/bignas.py new file mode 100755 index 000000000..bd3ec4e20 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/bignas.py @@ -0,0 +1,280 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +from typing import Dict, List, Optional, Union + +import torch +from mmengine.model import BaseModel, MMDistributedDataParallel +from mmengine.optim import OptimWrapper +from mmengine.structures import BaseDataElement +from torch import nn + +from mmrazor.models.architectures.ops.mobilenet_series import MBBlock +from mmrazor.models.architectures.utils import set_dropout +from mmrazor.models.distillers import ConfigurableDistiller +from mmrazor.models.mutators import NasMutator +from mmrazor.models.utils import (add_prefix, + reinitialize_optim_wrapper_count_status) +from mmrazor.registry import MODEL_WRAPPERS, MODELS +from ..base import BaseAlgorithm + +VALID_MUTATOR_TYPE = Union[NasMutator, Dict] +VALID_DISTILLER_TYPE = Union[ConfigurableDistiller, Dict] + + +@MODELS.register_module() +class BigNAS(BaseAlgorithm): + """Implementation of `BigNas `_ + + BigNAS is a NAS algorithm which searches the following items in MobileNetV3 + with the one-shot paradigm: kernel_sizes, out_channels, expand_ratios, + block_depth and input sizes. + + BigNAS uses a `sandwich` strategy to sample subnets from the supernet, + which includes the max subnet, min subnet and N random subnets. It doesn't + require retraining, therefore we can directly get well-trained subnets + after supernet training. + + The logic of the search part is implemented in + :class:`mmrazor.engine.EvolutionSearchLoop` + + Args: + architecture (dict|:obj:`BaseModel`): The config of :class:`BaseModel` + or built model. Corresponding to supernet in NAS algorithm. + mutator (VALID_MUTATOR_TYPE): The config of :class:`NasMutator` or + built mutator. + distiller (VALID_DISTILLER_TYPE): Cfg of :class:`ConfigurableDistiller` + or built distiller. + data_preprocessor (Optional[Union[dict, nn.Module]]): The pre-process + config of :class:`BaseDataPreprocessor`. Defaults to None. + num_random_samples (int): number of random sample subnets. + Defaults to 2. + drop_path_rate (float): Stochastic depth rate. Defaults to 0.2. + backbone_dropout_stages (List): Stages to be set dropout. Defaults to + [6, 7]. + init_cfg (Optional[dict]): Init config for ``BaseModule``. + Defaults to None. + """ + + def __init__(self, + architecture: Union[BaseModel, Dict], + mutator: VALID_MUTATOR_TYPE = None, + distiller: VALID_DISTILLER_TYPE = None, + data_preprocessor: Optional[Union[Dict, nn.Module]] = None, + num_random_samples: int = 2, + drop_path_rate: float = 0.2, + backbone_dropout_stages: List = [6, 7], + init_cfg: Optional[Dict] = None) -> None: + super().__init__(architecture, data_preprocessor, init_cfg) + + self.mutator = self._build_mutator(mutator) + # NOTE: `mutator.prepare_from_supernet` must be called + # before distiller initialized. + self.mutator.prepare_from_supernet(self.architecture) + + self.distiller = self._build_distiller(distiller) + self.distiller.prepare_from_teacher(self.architecture) + self.distiller.prepare_from_student(self.architecture) + + self.sample_kinds = ['max', 'min'] + for i in range(num_random_samples): + self.sample_kinds.append('random' + str(i)) + + self.drop_path_rate = drop_path_rate + self.backbone_dropout_stages = backbone_dropout_stages + self._optim_wrapper_count_status_reinitialized = False + + def _build_mutator(self, mutator: VALID_MUTATOR_TYPE = None) -> NasMutator: + """Build mutator.""" + if isinstance(mutator, dict): + mutator = MODELS.build(mutator) + if not isinstance(mutator, NasMutator): + raise TypeError('mutator should be a `dict` or `NasMutator` ' + f'instance, but got {type(mutator)}.') + return mutator + + def _build_distiller( + self, + distiller: VALID_DISTILLER_TYPE = None) -> ConfigurableDistiller: + """Build distiller.""" + if isinstance(distiller, dict): + distiller = MODELS.build(distiller) + if not isinstance(distiller, ConfigurableDistiller): + raise TypeError('distiller should be a `dict` or ' + '`ConfigurableDistiller` instance, but got ' + f'{type(distiller)}') + return distiller + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + + def distill_step( + batch_inputs: torch.Tensor, data_samples: List[BaseDataElement] + ) -> Dict[str, torch.Tensor]: + subnet_losses = dict() + with optim_wrapper.optim_context( + self), self.distiller.student_recorders: # type: ignore + _ = self(batch_inputs, data_samples, mode='loss') + soft_loss = self.distiller.compute_distill_losses() + + subnet_losses.update(soft_loss) + + parsed_subnet_losses, _ = self.parse_losses(subnet_losses) + optim_wrapper.update_params(parsed_subnet_losses) + + return subnet_losses + + if not self._optim_wrapper_count_status_reinitialized: + reinitialize_optim_wrapper_count_status( + model=self, + optim_wrapper=optim_wrapper, + accumulative_counts=len(self.sample_kinds)) + self._optim_wrapper_count_status_reinitialized = True + + batch_inputs, data_samples = self.data_preprocessor(data, + True).values() + + total_losses = dict() + for kind in self.sample_kinds: + # update the max subnet loss. + if kind == 'max': + self.mutator.set_max_choices() + set_dropout( + layers=self.architecture.backbone.layers[:-1], + module=MBBlock, + dropout_stages=self.backbone_dropout_stages, + drop_path_rate=self.drop_path_rate) + with optim_wrapper.optim_context( + self + ), self.distiller.teacher_recorders: # type: ignore + max_subnet_losses = self( + batch_inputs, data_samples, mode='loss') + parsed_max_subnet_losses, _ = self.parse_losses( + max_subnet_losses) + optim_wrapper.update_params(parsed_max_subnet_losses) + total_losses.update( + add_prefix(max_subnet_losses, 'max_subnet')) + # update the min subnet loss. + elif kind == 'min': + self.mutator.set_min_choices() + set_dropout( + layers=self.architecture.backbone.layers[:-1], + module=MBBlock, + dropout_stages=self.backbone_dropout_stages, + drop_path_rate=0.) + min_subnet_losses = distill_step(batch_inputs, data_samples) + total_losses.update( + add_prefix(min_subnet_losses, 'min_subnet')) + # update the random subnets loss. + elif 'random' in kind: + self.mutator.set_choices(self.mutator.sample_choices()) + set_dropout( + layers=self.architecture.backbone.layers[:-1], + module=MBBlock, + dropout_stages=self.backbone_dropout_stages, + drop_path_rate=0.) + random_subnet_losses = distill_step(batch_inputs, data_samples) + total_losses.update( + add_prefix(random_subnet_losses, f'{kind}_subnet')) + + return total_losses + + +@MODEL_WRAPPERS.register_module() +class BigNASDDP(MMDistributedDataParallel): + + def __init__(self, + *, + device_ids: Optional[Union[List, int, torch.device]] = None, + **kwargs) -> None: + if device_ids is None: + if os.environ.get('LOCAL_RANK') is not None: + device_ids = [int(os.environ['LOCAL_RANK'])] + super().__init__(device_ids=device_ids, **kwargs) + self.device = 'cuda' if torch.cuda.is_available() else 'cpu' + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + + def distill_step( + batch_inputs: torch.Tensor, data_samples: List[BaseDataElement] + ) -> Dict[str, torch.Tensor]: + subnet_losses = dict() + with optim_wrapper.optim_context( + self + ), self.module.distiller.student_recorders: # type: ignore + _ = self(batch_inputs, data_samples, mode='loss') + soft_loss = self.module.distiller.compute_distill_losses() + + subnet_losses.update(soft_loss) + + parsed_subnet_losses, _ = self.module.parse_losses( + subnet_losses) + optim_wrapper.update_params(parsed_subnet_losses) + + return subnet_losses + + if not self._optim_wrapper_count_status_reinitialized: + reinitialize_optim_wrapper_count_status( + model=self, + optim_wrapper=optim_wrapper, + accumulative_counts=len(self.module.sample_kinds)) + self._optim_wrapper_count_status_reinitialized = True + + batch_inputs, data_samples = self.module.data_preprocessor( + data, True).values() + + total_losses = dict() + for kind in self.module.sample_kinds: + # update the max subnet loss. + if kind == 'max': + self.module.mutator.set_max_choices() + set_dropout( + layers=self.module.architecture.backbone.layers[:-1], + module=MBBlock, + dropout_stages=self.module.backbone_dropout_stages, + drop_path_rate=self.module.drop_path_rate) + with optim_wrapper.optim_context( + self + ), self.module.distiller.teacher_recorders: # type: ignore + max_subnet_losses = self( + batch_inputs, data_samples, mode='loss') + parsed_max_subnet_losses, _ = self.module.parse_losses( + max_subnet_losses) + optim_wrapper.update_params(parsed_max_subnet_losses) + total_losses.update( + add_prefix(max_subnet_losses, 'max_subnet')) + # update the min subnet loss. + elif kind == 'min': + self.module.mutator.set_min_choices() + set_dropout( + layers=self.module.architecture.backbone.layers[:-1], + module=MBBlock, + dropout_stages=self.module.backbone_dropout_stages, + drop_path_rate=0.) + min_subnet_losses = distill_step(batch_inputs, data_samples) + total_losses.update( + add_prefix(min_subnet_losses, 'min_subnet')) + # update the random subnets loss. + elif 'random' in kind: + self.module.mutator.set_choices( + self.module.mutator.sample_choices()) + set_dropout( + layers=self.module.architecture.backbone.layers[:-1], + module=MBBlock, + dropout_stages=self.module.backbone_dropout_stages, + drop_path_rate=0.) + random_subnet_losses = distill_step(batch_inputs, data_samples) + total_losses.update( + add_prefix(random_subnet_losses, f'{kind}_subnet')) + + return total_losses + + @property + def _optim_wrapper_count_status_reinitialized(self) -> bool: + return self.module._optim_wrapper_count_status_reinitialized + + @_optim_wrapper_count_status_reinitialized.setter + def _optim_wrapper_count_status_reinitialized(self, val: bool) -> None: + assert isinstance(val, bool) + + self.module._optim_wrapper_count_status_reinitialized = val diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/darts.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/darts.py new file mode 100755 index 000000000..b110f47ce --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/darts.py @@ -0,0 +1,523 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +from typing import Dict, List, Optional, Union + +import torch +from mmengine.model import BaseModel, MMDistributedDataParallel +from mmengine.optim import OptimWrapper, OptimWrapperDict +from torch import nn +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.models.mutators import NasMutator +from mmrazor.models.utils import add_prefix +from mmrazor.registry import MODEL_WRAPPERS, MODELS +from ..base import BaseAlgorithm + +VALID_MUTATOR_TYPE = Union[NasMutator, Dict] + + +@MODELS.register_module() +class Darts(BaseAlgorithm): + """Implementation of `DARTS `_ + + DARTS means Differentiable Architecture Search, a classic NAS algorithm. + :class:`Darts` implements the APIs required by the DARTS, as well as the + supernet training and subnet retraining logic for each iter. + + Args: + architecture (dict|:obj:`BaseModel`): The config of :class:`BaseModel` + or built model. Corresponding to supernet in NAS algorithm. + mutator (VALID_MUTATOR_TYPE): The config of :class:`NasMutator` or + built mutator. + norm_training (bool): Whether to set norm layers to training mode, + namely, not freeze running stats (mean and var). Note: Effect on + Batch Norm and its variants only. Defaults to False. + data_preprocessor (Optional[Union[dict, nn.Module]]): The pre-process + config of :class:`BaseDataPreprocessor`. Defaults to None. + init_cfg (Optional[dict]): Init config for ``BaseModule``. + Defaults to None. + """ + + def __init__(self, + architecture: Union[BaseModel, Dict], + mutator: VALID_MUTATOR_TYPE = None, + unroll: bool = False, + norm_training: bool = False, + data_preprocessor: Optional[Union[dict, nn.Module]] = None, + init_cfg: Optional[dict] = None): + super().__init__(architecture, data_preprocessor, init_cfg) + + self.mutator = self._build_mutator(mutator) + # Mutator is an essential component of the NAS algorithm. It + # provides some APIs commonly used by NAS. + # Before using it, you must do some preparation according to + # the supernet. + self.mutator.prepare_from_supernet(self.architecture) + self.mutator.prepare_arch_params() + + self.norm_training = norm_training + self.unroll = unroll + + def _build_mutator(self, mutator: VALID_MUTATOR_TYPE = None) -> NasMutator: + """Build mutator.""" + if isinstance(mutator, dict): + mutator = MODELS.build(mutator) + if not isinstance(mutator, NasMutator): + raise TypeError('mutator should be a `dict` or `NasMutator` ' + f'instance, but got {type(mutator)}.') + return mutator + + def train(self, mode=True): + """Convert the model into eval mode while keep normalization layer + unfreezed.""" + + super().train(mode) + if self.norm_training and not mode: + for module in self.architecture.modules(): + if isinstance(module, _BatchNorm): + module.training = True + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + """The iteration step during training. + + This method defines an iteration step during training, except for the + back propagation and optimizer updating, which are done in an optimizer + hook. Note that in some complicated cases or models, the whole process + including back propagation and optimizer updating are also defined in + this method, such as GAN. + + Args: + data (dict): The output of dataloader. + optimizer (:obj:`torch.optim.Optimizer` | dict): The optimizer of + runner is passed to ``train_step()``. This argument is unused + and reserved. + Returns: + dict: It should contain at least 3 keys: ``loss``, ``log_vars``, + ``num_samples``. + ``loss`` is a tensor for back propagation, which can be a + weighted sum of multiple losses. + ``log_vars`` contains all the variables to be sent to the + logger. + ``num_samples`` indicates the batch size (when the model is + DDP, it means the batch size on each GPU), which is used for + averaging the logs. + """ + if isinstance(data, (tuple, list)) and isinstance( + optim_wrapper, OptimWrapperDict): + assert len(data) == len(optim_wrapper), \ + f'The length of data ({len(data)}) should be equal to that '\ + f'of optimizers ({len(optim_wrapper)}).' + + supernet_data, mutator_data = data + + log_vars = dict() + + # Update the parameter of mutator + if self.unroll: + with optim_wrapper['mutator'].optim_context(self): + optim_wrapper['mutator'].zero_grad() + mutator_log_vars = self._unrolled_backward( + mutator_data, supernet_data, optim_wrapper) + optim_wrapper['mutator'].step() + log_vars.update(add_prefix(mutator_log_vars, 'mutator')) + else: + with optim_wrapper['mutator'].optim_context(self): + pseudo_data = self.data_preprocessor(mutator_data, True) + mutator_batch_inputs = pseudo_data['inputs'] + mutator_data_samples = pseudo_data['data_samples'] + mutator_loss = self( + mutator_batch_inputs, + mutator_data_samples, + mode='loss') + mutator_losses, mutator_log_vars = self.parse_losses( + mutator_loss) + optim_wrapper['mutator'].update_params(mutator_losses) + log_vars.update(add_prefix(mutator_log_vars, 'mutator')) + + # Update the parameter of supernet + with optim_wrapper['architecture'].optim_context(self): + pseudo_data = self.data_preprocessor(supernet_data, True) + supernet_batch_inputs = pseudo_data['inputs'] + supernet_data_samples = pseudo_data['data_samples'] + supernet_loss = self( + supernet_batch_inputs, supernet_data_samples, mode='loss') + supernet_losses, supernet_log_vars = self.parse_losses( + supernet_loss) + optim_wrapper['architecture'].update_params(supernet_losses) + log_vars.update(add_prefix(supernet_log_vars, 'supernet')) + + else: + # Enable automatic mixed precision training context. + with optim_wrapper.optim_context(self): + pseudo_data = self.data_preprocessor(data, True) + batch_inputs = pseudo_data['inputs'] + data_samples = pseudo_data['data_samples'] + losses = self(batch_inputs, data_samples, mode='loss') + parsed_losses, log_vars = self.parse_losses(losses) + optim_wrapper.update_params(parsed_losses) + return log_vars + + def _unrolled_backward(self, mutator_data, supernet_data, optim_wrapper): + """Compute unrolled loss and backward its gradients.""" + backup_params = copy.deepcopy(tuple(self.architecture.parameters())) + + # Do virtual step on training data + lr = optim_wrapper['architecture'].param_groups[0]['lr'] + momentum = optim_wrapper['architecture'].param_groups[0]['momentum'] + weight_decay = optim_wrapper['architecture'].param_groups[0][ + 'weight_decay'] + self._compute_virtual_model(supernet_data, lr, momentum, weight_decay, + optim_wrapper['architecture']) + + # Calculate unrolled loss on validation data + # Keep gradients for model here for compute hessian + pseudo_data = self.data_preprocessor(mutator_data, True) + mutator_batch_inputs = pseudo_data['inputs'] + mutator_data_samples = pseudo_data['data_samples'] + mutator_loss = self( + mutator_batch_inputs, mutator_data_samples, mode='loss') + mutator_losses, mutator_log_vars = self.parse_losses(mutator_loss) + + # Here we use the backward function of optimWrapper to calculate + # the gradients of mutator loss. The gradients of model and arch + # can directly obtained. For more information, please refer to + # https://github.com/open-mmlab/mmengine/blob/main/mmengine/optim/optimizer/optimizer_wrapper.py + optim_wrapper['mutator'].backward(mutator_losses) + d_model = [param.grad for param in self.architecture.parameters()] + d_arch = [param.grad for param in self.mutator.parameters()] + + # compute hessian and final gradients + hessian = self._compute_hessian(backup_params, d_model, supernet_data, + optim_wrapper['architecture']) + + w_arch = tuple(self.mutator.parameters()) + + with torch.no_grad(): + for param, d, h in zip(w_arch, d_arch, hessian): + # gradient = dalpha - lr * hessian + param.grad = d - lr * h + + # restore weights + self._restore_weights(backup_params) + return mutator_log_vars + + def _compute_virtual_model(self, supernet_data, lr, momentum, weight_decay, + optim_wrapper): + """Compute unrolled weights w`""" + # don't need zero_grad, using autograd to calculate gradients + pseudo_data = self.data_preprocessor(supernet_data, True) + supernet_batch_inputs = pseudo_data['inputs'] + supernet_data_samples = pseudo_data['data_samples'] + supernet_loss = self( + supernet_batch_inputs, supernet_data_samples, mode='loss') + supernet_loss, _ = self.parse_losses(supernet_loss) + + optim_wrapper.backward(supernet_loss) + gradients = [param.grad for param in self.architecture.parameters()] + + with torch.no_grad(): + for w, g in zip(self.architecture.parameters(), gradients): + m = optim_wrapper.optimizer.state[w].get('momentum_buffer', 0.) + w = w - lr * (momentum * m + g + weight_decay * w) + + def _restore_weights(self, backup_params): + """restore weight from backup params.""" + with torch.no_grad(): + for param, backup in zip(self.architecture.parameters(), + backup_params): + param.copy_(backup) + + def _compute_hessian(self, backup_params, dw, supernet_data, + optim_wrapper) -> List: + """compute hession metric + dw = dw` { L_val(w`, alpha) } + w+ = w + eps * dw + w- = w - eps * dw + hessian = (dalpha { L_trn(w+, alpha) } \ + - dalpha { L_trn(w-, alpha) }) / (2*eps) + eps = 0.01 / ||dw|| + """ + self._restore_weights(backup_params) + norm = torch.cat([w.view(-1) for w in dw]).norm() + eps = 0.01 / norm + if norm < 1E-8: + print( + 'In computing hessian, norm is smaller than 1E-8, \ + cause eps to be %.6f.', norm.item()) + + dalphas = [] + for e in [eps, -2. * eps]: + # w+ = w + eps*dw`, w- = w - eps*dw` + with torch.no_grad(): + for p, d in zip(self.architecture.parameters(), dw): + p += e * d + + pseudo_data = self.data_preprocessor(supernet_data, True) + supernet_batch_inputs = pseudo_data['inputs'] + supernet_data_samples = pseudo_data['data_samples'] + supernet_loss = self( + supernet_batch_inputs, supernet_data_samples, mode='loss') + supernet_loss, _ = self.parse_losses(supernet_loss) + + optim_wrapper.backward(supernet_loss) + dalpha = [param.grad for param in self.mutator.parameters()] + dalphas.append(dalpha) + + # dalpha { L_trn(w+) }, # dalpha { L_trn(w-) } + dalpha_pos, dalpha_neg = dalphas + hessian = [(p - n) / (2. * eps) + for p, n in zip(dalpha_pos, dalpha_neg)] + return hessian + + +class BatchNormWrapper(nn.Module): + """Wrapper for BatchNorm. + + For more information, Please refer to + https://github.com/NVIDIA/apex/issues/121 + """ + + def __init__(self, m): + super(BatchNormWrapper, self).__init__() + self.m = m + # Set the batch norm to eval mode + self.m.eval() + + def forward(self, x): + """Convert fp16 to fp32 when forward.""" + input_type = x.dtype + x = self.m(x.float()) + return x.to(input_type) + + +@MODEL_WRAPPERS.register_module() +class DartsDDP(MMDistributedDataParallel): + """DDP for Darts and rewrite train_step of MMDDP.""" + + def __init__(self, + *, + device_ids: Optional[Union[List, int, torch.device]] = None, + **kwargs) -> None: + if device_ids is None: + if os.environ.get('LOCAL_RANK') is not None: + device_ids = [int(os.environ['LOCAL_RANK'])] + super().__init__(device_ids=device_ids, **kwargs) + + fp16 = True + if fp16: + + def add_fp16_bn_wrapper(model): + for child_name, child in model.named_children(): + if isinstance(child, nn.BatchNorm2d): + setattr(model, child_name, BatchNormWrapper(child)) + else: + add_fp16_bn_wrapper(child) + + add_fp16_bn_wrapper(self.module) + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + """The iteration step during training. + + This method defines an iteration step during training, except for the + back propagation and optimizer updating, which are done in an optimizer + hook. Note that in some complicated cases or models, the whole process + including back propagation and optimizer updating are also defined in + this method, such as GAN. + + Args: + data (dict): The output of dataloader. + optimizer (:obj:`torch.optim.Optimizer` | dict): The optimizer of + runner is passed to ``train_step()``. This argument is unused + and reserved. + Returns: + dict: It should contain at least 3 keys: ``loss``, ``log_vars``, + ``num_samples``. + ``loss`` is a tensor for back propagation, which can be a + weighted sum of multiple losses. + ``log_vars`` contains all the variables to be sent to the + logger. + ``num_samples`` indicates the batch size (when the model is + DDP, it means the batch size on each GPU), which is used for + averaging the logs. + """ + if isinstance(data, (tuple, list)) and isinstance( + optim_wrapper, OptimWrapperDict): + assert len(data) == len(optim_wrapper), \ + f'The length of data ({len(data)}) should be equal to that '\ + f'of optimizers ({len(optim_wrapper)}).' + + supernet_data, mutator_data = data + + log_vars = dict() + + # Update the parameter of mutator + if self.module.unroll: + with optim_wrapper['mutator'].optim_context(self): + optim_wrapper['mutator'].zero_grad() + mutator_log_vars = self._unrolled_backward( + mutator_data, supernet_data, optim_wrapper) + optim_wrapper['mutator'].step() + log_vars.update(add_prefix(mutator_log_vars, 'mutator')) + else: + with optim_wrapper['mutator'].optim_context(self): + pseudo_data = self.module.data_preprocessor( + mutator_data, True) + mutator_batch_inputs = pseudo_data['inputs'] + mutator_data_samples = pseudo_data['data_samples'] + mutator_loss = self( + mutator_batch_inputs, + mutator_data_samples, + mode='loss') + + mutator_losses, mutator_log_vars = self.module.parse_losses( # noqa: E501 + mutator_loss) + optim_wrapper['mutator'].update_params(mutator_losses) + log_vars.update(add_prefix(mutator_log_vars, 'mutator')) + + # Update the parameter of supernet + with optim_wrapper['architecture'].optim_context(self): + pseudo_data = self.module.data_preprocessor( + supernet_data, True) + supernet_batch_inputs = pseudo_data['inputs'] + supernet_data_samples = pseudo_data['data_samples'] + supernet_loss = self( + supernet_batch_inputs, supernet_data_samples, mode='loss') + + supernet_losses, supernet_log_vars = self.module.parse_losses( + supernet_loss) + + optim_wrapper['architecture'].update_params(supernet_losses) + log_vars.update(add_prefix(supernet_log_vars, 'supernet')) + + else: + # Enable automatic mixed precision training context. + with optim_wrapper.optim_context(self): + pseudo_data = self.module.data_preprocessor(data, True) + batch_inputs = pseudo_data['inputs'] + data_samples = pseudo_data['data_samples'] + losses = self(batch_inputs, data_samples, mode='loss') + parsed_losses, log_vars = self.module.parse_losses(losses) + optim_wrapper.update_params(parsed_losses) + + return log_vars + + def _unrolled_backward(self, mutator_data, supernet_data, optim_wrapper): + """Compute unrolled loss and backward its gradients.""" + backup_params = copy.deepcopy( + tuple(self.module.architecture.parameters())) + + # do virtual step on training data + lr = optim_wrapper['architecture'].param_groups[0]['lr'] + momentum = optim_wrapper['architecture'].param_groups[0]['momentum'] + weight_decay = optim_wrapper['architecture'].param_groups[0][ + 'weight_decay'] + self._compute_virtual_model(supernet_data, lr, momentum, weight_decay, + optim_wrapper['architecture']) + + # calculate unrolled loss on validation data + # keep gradients for model here for compute hessian + pseudo_data = self.module.data_preprocessor(mutator_data, True) + mutator_batch_inputs = pseudo_data['inputs'] + mutator_data_samples = pseudo_data['data_samples'] + mutator_loss = self( + mutator_batch_inputs, mutator_data_samples, mode='loss') + mutator_losses, mutator_log_vars = self.module.parse_losses( + mutator_loss) + + # Here we use the backward function of optimWrapper to calculate + # the gradients of mutator loss. The gradients of model and arch + # can directly obtained. For more information, please refer to + # https://github.com/open-mmlab/mmengine/blob/main/mmengine/optim/optimizer/optimizer_wrapper.py + optim_wrapper['mutator'].backward(mutator_losses) + d_model = [ + param.grad for param in self.module.architecture.parameters() + ] + d_arch = [param.grad for param in self.module.mutator.parameters()] + + # compute hessian and final gradients + hessian = self._compute_hessian(backup_params, d_model, supernet_data, + optim_wrapper['architecture']) + + w_arch = tuple(self.module.mutator.parameters()) + + with torch.no_grad(): + for param, da, he in zip(w_arch, d_arch, hessian): + # gradient = dalpha - lr * hessian + param.grad = da - lr * he + + # restore weights + self._restore_weights(backup_params) + return mutator_log_vars + + def _compute_virtual_model(self, supernet_data, lr, momentum, weight_decay, + optim_wrapper): + """Compute unrolled weights w`""" + # don't need zero_grad, using autograd to calculate gradients + pseudo_data = self.module.data_preprocessor(supernet_data, True) + supernet_batch_inputs = pseudo_data['inputs'] + supernet_data_samples = pseudo_data['data_samples'] + supernet_loss = self( + supernet_batch_inputs, supernet_data_samples, mode='loss') + supernet_loss, _ = self.module.parse_losses(supernet_loss) + + optim_wrapper.backward(supernet_loss) + gradients = [ + param.grad for param in self.module.architecture.parameters() + ] + + with torch.no_grad(): + for w, g in zip(self.module.architecture.parameters(), gradients): + m = optim_wrapper.optimizer.state[w].get('momentum_buffer', 0.) + w = w - lr * (momentum * m + g + weight_decay * w) + + def _restore_weights(self, backup_params): + """restore weight from backup params.""" + with torch.no_grad(): + for param, backup in zip(self.module.architecture.parameters(), + backup_params): + param.copy_(backup) + + def _compute_hessian(self, backup_params, dw, supernet_data, + optim_wrapper) -> List: + """compute hession metric + dw = dw` { L_val(w`, alpha) } + w+ = w + eps * dw + w- = w - eps * dw + hessian = (dalpha { L_trn(w+, alpha) } \ + - dalpha { L_trn(w-, alpha) }) / (2*eps) + eps = 0.01 / ||dw|| + """ + self._restore_weights(backup_params) + norm = torch.cat([w.view(-1) for w in dw]).norm() + eps = 0.01 / norm + if norm < 1E-8: + print( + 'In computing hessian, norm is smaller than 1E-8, \ + cause eps to be %.6f.', norm.item()) + + dalphas = [] + for e in [eps, -2. * eps]: + # w+ = w + eps*dw`, w- = w - eps*dw` + with torch.no_grad(): + for p, d in zip(self.module.architecture.parameters(), dw): + p += e * d + + pseudo_data = self.module.data_preprocessor(supernet_data, True) + supernet_batch_inputs = pseudo_data['inputs'] + supernet_data_samples = pseudo_data['data_samples'] + supernet_loss = self( + supernet_batch_inputs, supernet_data_samples, mode='loss') + supernet_loss, _ = self.module.parse_losses(supernet_loss) + + optim_wrapper.backward(supernet_loss) + dalpha = [param.grad for param in self.module.mutator.parameters()] + dalphas.append(dalpha) + + # dalpha { L_trn(w+) }, # dalpha { L_trn(w-) } + dalpha_pos, dalpha_neg = dalphas + hessian = [(p - n) / (2. * eps) + for p, n in zip(dalpha_pos, dalpha_neg)] + return hessian diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/dsnas.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/dsnas.py new file mode 100755 index 000000000..e5937ba71 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/dsnas.py @@ -0,0 +1,332 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +from typing import Any, Dict, List, Optional, Union + +import torch +import torch.distributed as dist +import torch.nn.functional as F +from mmengine.dist import get_dist_info +from mmengine.logging import MessageHub +from mmengine.model import BaseModel, MMDistributedDataParallel +from mmengine.optim import OptimWrapper, OptimWrapperDict +from torch import nn +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.models.mutables import BaseMutable +from mmrazor.models.mutators import NasMutator +from mmrazor.models.utils import add_prefix +from mmrazor.registry import MODEL_WRAPPERS, MODELS, TASK_UTILS +from mmrazor.structures import export_fix_subnet, load_fix_subnet +from ..base import BaseAlgorithm + +VALID_MUTATOR_TYPE = Union[NasMutator, Dict] + + +@MODELS.register_module() +class DSNAS(BaseAlgorithm): + """Implementation of `DSNAS `_ + + Args: + architecture (dict|:obj:`BaseModel`): The config of :class:`BaseModel` + or built model. Corresponding to supernet in NAS algorithm. + mutator (VALID_MUTATOR_TYPE): The config of :class:`NasMutator` or + built mutator. + pretrain_epochs (int): Num of epochs for supernet pretraining. + finetune_epochs (int): Num of epochs for subnet finetuning. + flops_constraints (float): Flops constraints for judging whether to + backward flops loss or not. Default to 300.0(M). + estimator_cfg (Dict[str, Any]): Used for building a resource estimator. + Default to None. + norm_training (bool): Whether to set norm layers to training mode, + namely, not freeze running stats (mean and var). Note: Effect on + Batch Norm and its variants only. Defaults to False. + data_preprocessor (dict, optional): The pre-process config of + :class:`BaseDataPreprocessor`. Defaults to None. + init_cfg (dict): Init config for ``BaseModule``. + + Note: + Dsnas doesn't require retraining. It has 3 stages in searching: + 1. `cur_epoch` < `pretrain_epochs` refers to supernet pretraining. + 2. `pretrain_epochs` <= `cur_epoch` < `finetune_epochs` refers to + normal supernet training while mutator is updated. + 3. `cur_epoch` >= `finetune_epochs` refers to subnet finetuning. + """ + + def __init__(self, + architecture: Union[BaseModel, Dict], + mutator: VALID_MUTATOR_TYPE = None, + pretrain_epochs: int = 0, + finetune_epochs: int = 80, + flops_constraints: float = 300.0, + estimator_cfg: Dict[str, Any] = None, + norm_training: bool = False, + data_preprocessor: Optional[Union[dict, nn.Module]] = None, + init_cfg: Optional[dict] = None): + super().__init__(architecture, data_preprocessor, init_cfg) + + # initialize estimator + estimator_cfg = dict() if estimator_cfg is None else estimator_cfg + if 'type' not in estimator_cfg: + estimator_cfg['type'] = 'mmrazor.ResourceEstimator' + self.estimator = TASK_UTILS.build(estimator_cfg) + + self.mutator = self._build_mutator(mutator) + # Mutator is an essential component of the NAS algorithm. It + # provides some APIs commonly used by NAS. + # Before using it, you must do some preparation according to + # the supernet. + self.mutator.prepare_from_supernet(self.architecture) + self.mutator.prepare_arch_params() + + self.mutable_module_resources = self._get_module_resources() + self.search_space_name_list = list(self.mutator._name2mutable.keys()) + + self.is_supernet = True + + self.norm_training = norm_training + self.pretrain_epochs = pretrain_epochs + self.finetune_epochs = finetune_epochs + if pretrain_epochs >= finetune_epochs: + raise ValueError(f'Pretrain stage (optional) must be done before ' + f'finetuning stage. Got `{pretrain_epochs}` >= ' + f'`{finetune_epochs}`.') + + self.flops_loss_coef = 1e-2 + self.flops_constraints = flops_constraints + _, self.world_size = get_dist_info() + + def _build_mutator(self, mutator: VALID_MUTATOR_TYPE = None) -> NasMutator: + """Build mutator.""" + if isinstance(mutator, dict): + mutator = MODELS.build(mutator) + if not isinstance(mutator, NasMutator): + raise TypeError('mutator should be a `dict` or `NasMutator` ' + f'instance, but got {type(mutator)}.') + return mutator + + def train(self, mode=True): + """Convert the model into eval mode while keep normalization layer + unfreezed.""" + + super().train(mode) + if self.norm_training and not mode: + for module in self.architecture.modules(): + if isinstance(module, _BatchNorm): + module.training = True + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + """The iteration step during training. + + Args: + data (dict): The output of dataloader. + optimizer (:obj:`torch.optim.Optimizer` | dict): The optimizer of + runner is passed to ``train_step()``. + """ + if isinstance(optim_wrapper, OptimWrapperDict): + log_vars = dict() + self.message_hub = MessageHub.get_current_instance() + cur_epoch = self.message_hub.get_info('epoch') + need_update_mutator = self.need_update_mutator(cur_epoch) + + if cur_epoch == self.finetune_epochs and self.is_supernet: + # synchronize arch params to start the finetune stage. + for k, v in self.mutator.arch_params.items(): + dist.broadcast(v, src=0) + self._fix_archtecture() + self.is_supernet = False + + # 1. update architecture + with optim_wrapper['architecture'].optim_context(self): + pseudo_data = self.data_preprocessor(data, True) + supernet_batch_inputs = pseudo_data['inputs'] + supernet_data_samples = pseudo_data['data_samples'] + supernet_loss = self( + supernet_batch_inputs, supernet_data_samples, mode='loss') + + supernet_losses, supernet_log_vars = self.parse_losses( + supernet_loss) + optim_wrapper['architecture'].backward( + supernet_losses, retain_graph=need_update_mutator) + optim_wrapper['architecture'].step() + optim_wrapper['architecture'].zero_grad() + log_vars.update(add_prefix(supernet_log_vars, 'supernet')) + + # 2. update mutator + if need_update_mutator: + with optim_wrapper['mutator'].optim_context(self): + mutator_loss = self.compute_mutator_loss() + mutator_losses, mutator_log_vars = \ + self.parse_losses(mutator_loss) + optim_wrapper['mutator'].update_params(mutator_losses) + log_vars.update(add_prefix(mutator_log_vars, 'mutator')) + # handle the grad of arch params & weights + self.handle_grads() + + else: + # Enable automatic mixed precision training context. + with optim_wrapper.optim_context(self): + pseudo_data = self.data_preprocessor(data, True) + batch_inputs = pseudo_data['inputs'] + data_samples = pseudo_data['data_samples'] + losses = self(batch_inputs, data_samples, mode='loss') + parsed_losses, log_vars = self.parse_losses(losses) + optim_wrapper.update_params(parsed_losses) + + return log_vars + + def _fix_archtecture(self): + """Fix architecture based on current choice.""" + self.mutator.set_choices(self.mutator.sample_choices()) + for module in self.architecture.modules(): + if isinstance(module, BaseMutable): + if not module.is_fixed: + module.fix_chosen(module.current_choice) + + def _get_module_resources(self): + """Get resources of spec modules.""" + spec_modules = [] + for name, module in self.architecture.named_modules(): + if isinstance(module, BaseMutable): + for choice in module.choices: + spec_modules.append(name + '._candidates.' + choice) + + mutable_module_resources = self.estimator.estimate_separation_modules( + self.architecture, dict(spec_modules=spec_modules)) + + return mutable_module_resources + + def need_update_mutator(self, cur_epoch: int) -> bool: + """Whether to update mutator.""" + if cur_epoch >= self.pretrain_epochs and \ + cur_epoch < self.finetune_epochs: + return True + return False + + def compute_mutator_loss(self) -> Dict[str, torch.Tensor]: + """Compute mutator loss. + + In this method, arch_loss & flops_loss[optional] are computed + by traversing arch_weights & probs in search groups. + + Returns: + Dict: Loss of the mutator. + """ + arch_loss = 0.0 + flops_loss = 0.0 + for name, module in self.architecture.named_modules(): + if isinstance(module, BaseMutable): + k = module.mutable_prefix + '_' + \ + str(self.search_space_name_list.index(name)) + probs = F.softmax(self.mutator.arch_params[k], -1) + arch_loss += torch.log( + (module.arch_weights * probs).sum(-1)).sum() + + # get the index of op with max arch weights. + index = (module.arch_weights == 1).nonzero().item() + _module_key = name + '._candidates.' + module.choices[index] + flops_loss += probs[index] * \ + self.mutable_module_resources[_module_key]['flops'] + + mutator_loss = dict(arch_loss=arch_loss / self.world_size) + + copied_model = copy.deepcopy(self) + copied_model.mutator.set_choices(copied_model.mutator.sample_choices()) + + subnet_dict = export_fix_subnet(copied_model)[0] + load_fix_subnet(copied_model, subnet_dict) + + subnet_flops = self.estimator.estimate(copied_model)['flops'] + if subnet_flops >= self.flops_constraints: + mutator_loss['flops_loss'] = \ + (flops_loss * self.flops_loss_coef) / self.world_size + + return mutator_loss + + def handle_grads(self): + """Handle grads of arch params & arch weights.""" + for name, module in self.architecture.named_modules(): + if isinstance(module, BaseMutable): + k = module.mutable_prefix + '_' + \ + str(self.search_space_name_list.index(name)) + self.mutator.arch_params[k].grad.data.mul_( + module.arch_weights.grad.data.sum()) + module.arch_weights.grad.zero_() + + +@MODEL_WRAPPERS.register_module() +class DSNASDDP(MMDistributedDataParallel): + + def __init__(self, + *, + device_ids: Optional[Union[List, int, torch.device]] = None, + **kwargs) -> None: + if device_ids is None: + if os.environ.get('LOCAL_RANK') is not None: + device_ids = [int(os.environ['LOCAL_RANK'])] + super().__init__(device_ids=device_ids, **kwargs) + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + """The iteration step during training. + + This method defines an iteration step during training, except for the + back propagation and optimizer updating, which are done in an optimizer + hook. Note that in some complicated cases or models, the whole process + including back propagation and optimizer updating are also defined in + this method, such as GAN. + """ + if isinstance(optim_wrapper, OptimWrapperDict): + log_vars = dict() + self.message_hub = MessageHub.get_current_instance() + cur_epoch = self.message_hub.get_info('epoch') + need_update_mutator = self.module.need_update_mutator(cur_epoch) + + # TODO process the input + if cur_epoch == self.module.finetune_epochs and \ + self.module.is_supernet: + # synchronize arch params to start the finetune stage. + for k, v in self.module.mutator.arch_params.items(): + dist.broadcast(v, src=0) + self.module._fix_archtecture() + self.module.is_supernet = False + + # 1. update architecture + with optim_wrapper['architecture'].optim_context(self): + pseudo_data = self.module.data_preprocessor(data, True) + supernet_batch_inputs = pseudo_data['inputs'] + supernet_data_samples = pseudo_data['data_samples'] + supernet_loss = self( + supernet_batch_inputs, supernet_data_samples, mode='loss') + + supernet_losses, supernet_log_vars = self.module.parse_losses( + supernet_loss) + optim_wrapper['architecture'].backward( + supernet_losses, retain_graph=need_update_mutator) + optim_wrapper['architecture'].step() + optim_wrapper['architecture'].zero_grad() + log_vars.update(add_prefix(supernet_log_vars, 'supernet')) + + # 2. update mutator + if need_update_mutator: + with optim_wrapper['mutator'].optim_context(self): + mutator_loss = self.module.compute_mutator_loss() + mutator_losses, mutator_log_vars = \ + self.module.parse_losses(mutator_loss) + optim_wrapper['mutator'].update_params(mutator_losses) + log_vars.update(add_prefix(mutator_log_vars, 'mutator')) + # handle the grad of arch params & weights + self.module.handle_grads() + + else: + # Enable automatic mixed precision training context. + with optim_wrapper.optim_context(self): + pseudo_data = self.module.data_preprocessor(data, True) + batch_inputs = pseudo_data['inputs'] + data_samples = pseudo_data['data_samples'] + losses = self(batch_inputs, data_samples, mode='loss') + parsed_losses, log_vars = self.module.parse_losses(losses) + optim_wrapper.update_params(parsed_losses) + + return log_vars diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/spos.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/spos.py new file mode 100755 index 000000000..90a27aa4b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/spos.py @@ -0,0 +1,97 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Optional, Union + +import torch +from mmengine.model import BaseModel +from mmengine.structures import BaseDataElement +from torch import nn +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.models.mutators import NasMutator +from mmrazor.registry import MODELS +from ..base import BaseAlgorithm, LossResults + +VALID_MUTATOR_TYPE = Union[NasMutator, Dict] + + +@MODELS.register_module() +class SPOS(BaseAlgorithm): + """Implementation of `SPOS `_ + + SPOS means Single Path One-Shot, a classic NAS algorithm. + :class:`SPOS` implements the APIs required by the Single Path One-Shot + algorithm, as well as the supernet training and subnet retraining logic + for each iter. + + The logic of the search part is implemented in + :class:`mmrazor.core.EvolutionSearch` + + Args: + architecture (dict|:obj:`BaseModel`): The config of :class:`BaseModel` + or built model. Corresponding to supernet in NAS algorithm. + mutator (VALID_MUTATOR_TYPE): The config of :class:`NasMutator` or + built mutator. + norm_training (bool): Whether to set norm layers to training mode, + namely, not freeze running stats (mean and var). Note: Effect on + Batch Norm and its variants only. Defaults to False. + data_preprocessor (Optional[Union[dict, nn.Module]]): The pre-process + config of :class:`BaseDataPreprocessor`. Defaults to None. + init_cfg (Optional[dict]): Init config for ``BaseModule``. + Defaults to None. + + Note: + During supernet training, since each op is not fully trained, the + statistics of :obj:_BatchNorm are inaccurate. This problem affects the + evaluation of the performance of each subnet in the search phase. There + are usually two ways to solve this problem, both need to set + `norm_training` to True: + + 1) Using a large batch size, BNs use the mean and variance of the + current batch during forward. + 2) Recalibrate the statistics of BN before searching. + """ + + def __init__(self, + architecture: Union[BaseModel, Dict], + mutator: VALID_MUTATOR_TYPE = None, + norm_training: bool = False, + data_preprocessor: Optional[Union[dict, nn.Module]] = None, + init_cfg: Optional[dict] = None): + super().__init__(architecture, data_preprocessor, init_cfg) + + self.mutator = self._build_mutator(mutator) + # Mutator is an essential component of the NAS algorithm. It + # provides some APIs commonly used by NAS. + # Before using it, you must do some preparations according to + # the supernet. + self.mutator.prepare_from_supernet(self.architecture) + + self.norm_training = norm_training + + def _build_mutator(self, mutator: VALID_MUTATOR_TYPE = None) -> NasMutator: + """Build mutator.""" + if isinstance(mutator, dict): + mutator = MODELS.build(mutator) + if not isinstance(mutator, NasMutator): + raise TypeError('mutator should be a `dict` or `NasMutator` ' + f'instance, but got {type(mutator)}.') + return mutator + + def loss( + self, + batch_inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + ) -> LossResults: + """Calculate losses from a batch of inputs and data samples.""" + self.mutator.set_choices(self.mutator.sample_choices()) + return self.architecture(batch_inputs, data_samples, mode='loss') + + def train(self, mode=True): + """Convert the model into eval mode while keep normalization layer + unfreezed.""" + + super().train(mode) + if self.norm_training and not mode: + for module in self.architecture.modules(): + if isinstance(module, _BatchNorm): + module.training = True diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/__init__.py new file mode 100755 index 000000000..09a87b90d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/__init__.py @@ -0,0 +1,8 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .dcff import DCFF +from .dmcp import DMCP, DMCPDDP +from .slimmable_network import SlimmableNetwork, SlimmableNetworkDDP + +__all__ = [ + 'SlimmableNetwork', 'SlimmableNetworkDDP', 'DCFF', 'DMCP', 'DMCPDDP' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dcff.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dcff.py new file mode 100755 index 000000000..e89da50b4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dcff.py @@ -0,0 +1,153 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import math +from typing import Dict, List, Optional, Tuple, Union + +import torch +import torch.nn as nn +from mmengine import MMLogger +from mmengine.model import BaseModel +from mmengine.structures import BaseDataElement + +from mmrazor.models.mutators import DCFFChannelMutator +from mmrazor.registry import MODELS +from .ite_prune_algorithm import ItePruneAlgorithm, ItePruneConfigManager + +LossResults = Dict[str, torch.Tensor] +TensorResults = Union[Tuple[torch.Tensor], torch.Tensor] +PredictResults = List[BaseDataElement] +ForwardResults = Union[LossResults, TensorResults, PredictResults] + + +@MODELS.register_module() +class DCFF(ItePruneAlgorithm): + """DCFF Networks. + + Please refer to paper + [Dynamic-coded Filter Fusion](https://arxiv.org/abs/2107.06916). + + Args: + architecture (Union[BaseModel, Dict]): The model to be pruned. + mutator_cfg (Union[Dict, ChannelMutator], optional): The config + of a mutator. Defaults to dict( type='DCFFChannelMutator', + channel_unit_cfg=dict( type='DCFFChannelUnit')). + data_preprocessor (Optional[Union[Dict, nn.Module]], optional): + Defaults to None. + target_pruning_ratio (dict, optional): The prune-target. The template + of the prune-target can be get by calling + mutator.choice_template(). Defaults to {}. + step_freq (int, optional): The step between two pruning operations. + Defaults to 1. Legal input includes [1, self._max_iters] + One and only one of (step_freq, prune_times) is set to legal int. + prune_times (int, optional): The total times to prune a model. + Defaults to 0. Legal input includes [1, self._max_iters] + One and only one of (step_freq, prune_times) is set to legal int. + init_cfg (Optional[Dict], optional): init config for architecture. + Defaults to None. + linear_schedule (bool, optional): flag to set linear ratio schedule. + Defaults to False due to dcff fixed pruning rate. + """ + + def __init__(self, + architecture: Union[BaseModel, Dict], + mutator_cfg: Union[Dict, DCFFChannelMutator] = dict( + type='DCFFChannelMutator', + channel_unit_cfg=dict(type='DCFFChannelUnit')), + data_preprocessor: Optional[Union[Dict, nn.Module]] = None, + target_pruning_ratio: Optional[Dict[str, float]] = None, + step_freq=1, + prune_times=0, + init_cfg: Optional[Dict] = None, + linear_schedule=False) -> None: + # invalid param prune_times, reset after message_hub get [max_epoch] + super().__init__(architecture, mutator_cfg, data_preprocessor, + target_pruning_ratio, step_freq, prune_times, + init_cfg, linear_schedule) + + def _calc_temperature(self, cur_num: int, max_num: int): + """Calculate temperature param.""" + # Set the fixed parameters required to calculate the temperature t + t_s, t_e, k = 1, 10000, 1 + + A = 2 * (t_e - t_s) * (1 + math.exp(-k * max_num)) / ( + 1 - math.exp(-k * max_num)) + T = A / (1 + math.exp(-k * cur_num)) + t_s - A / 2 + t = 1 / T + return t + + def _legal_freq_time(self, freq_time): + """check whether step_freq or prune_times belongs to legal range: + + [1, self._max_iters] + + Args: + freq_time (Int): step_freq or prune_times. + """ + return (freq_time > 0) and (freq_time < self._max_iters) + + def _init_prune_config_manager(self): + """init prune_config_manager and check step_freq & prune_times. + + In DCFF, prune_times is set by step_freq and self._max_iters. + """ + if self.target_pruning_ratio is None: + target_pruning_ratio = self.mutator.current_choices + else: + target_pruning_ratio = self.set_target_pruning_ratio( + self.target_pruning_ratio, self.mutator.mutable_units) + + if self.by_epoch: + # step_freq based on iterations + self.step_freq *= self._iters_per_epoch + + if self._legal_freq_time(self.step_freq) ^ self._legal_freq_time( + self.prune_times): + if self._legal_freq_time(self.step_freq): + self.prune_times = self._max_iters // self.step_freq + else: + self.step_freq = self._max_iters // self.prune_times + else: + raise RuntimeError('One and only one of (step_freq, prune_times)' + 'can be set to legal int.') + + # config_manager move to forward. + # message_hub['max_epoch'] unaccessible when init + prune_config_manager = ItePruneConfigManager( + target_pruning_ratio, + self.mutator.current_choices, + self.step_freq, + prune_times=self.prune_times, + linear_schedule=self.linear_schedule) + + return prune_config_manager + + def forward(self, + inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + mode: str = 'tensor') -> ForwardResults: + """Forward.""" + + if self.training: + # In DCFF prune_message is related to total_num + # Set self.prune_config_manager after message_hub + # has['max_epoch/iter'] + if not hasattr(self, 'prune_config_manager'): + # iter num per epoch only available after initiation + self.prune_config_manager = self._init_prune_config_manager() + if self.prune_config_manager.is_prune_time(self._iter): + config = self.prune_config_manager.prune_at(self._iter) + self.mutator.set_choices(config) + + # calc fusion channel + temperature = self._calc_temperature(self._iter, + self._max_iters) + self.mutator.calc_information(temperature) + + logger = MMLogger.get_current_instance() + if (self.by_epoch): + logger.info( + f'The model is pruned at {self._epoch}th epoch once.') + else: + logger.info( + f'The model is pruned at {self._iter}th iter once.') + + return super().forward(inputs, data_samples, mode) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dmcp.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dmcp.py new file mode 100755 index 000000000..043cf9acf --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dmcp.py @@ -0,0 +1,425 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import random +from typing import Any, Dict, List, Optional, Tuple, Union + +import torch +from mmengine import MessageHub +from mmengine.model import BaseModel, MMDistributedDataParallel +from mmengine.optim import OptimWrapper +from mmengine.structures import BaseDataElement +from torch import nn + +from mmrazor.models.distillers import ConfigurableDistiller +from mmrazor.models.mutators import ChannelMutator, DMCPChannelMutator +from mmrazor.models.utils import add_prefix +from mmrazor.registry import MODEL_WRAPPERS, MODELS +from ...task_modules.estimators import ResourceEstimator +from ..base import BaseAlgorithm + +VALID_DISTILLER_TYPE = Union[ConfigurableDistiller, Dict, Any] + +LossResults = Dict[str, torch.Tensor] +TensorResults = Union[Tuple[torch.Tensor], torch.Tensor] +PredictResults = List[BaseDataElement] +ForwardResults = Union[LossResults, TensorResults, PredictResults] + + +@MODELS.register_module() +class DMCP(BaseAlgorithm): + """Implementation of `DMCP `_ + + Args: + architecture (dict|:obj:`BaseModel`): The config of :class:`BaseModel` + or built model. Corresponding to supernet in NAS algorithm. + distiller (VALID_DISTILLER_TYPE): Configs to build a distiller. + data_preprocessor (Optional[Union[dict, nn.Module]]): The pre-process + config of :class:`BaseDataPreprocessor`. Defaults to None. + strategy (list): mode of sampled net. + Defaults to ['max', 'min', 'arch_random']. + arch_start_train (int): Number of iter to start arch training. + Defaults to ['max', 'min', 'arch_random']. + arch_train_freq (int): Frequency of training. + Defaults to 500. + distillation_times (int): Number of iter to start arch training. + Defaults to 20000. + target_flops (int): Target FLOPs. Default unit: MFLOPs. + Defaults to 150. + flops_loss_type (str): The model used to calculate flops_loss. + Defaults to `log_l1`. + flop_loss_weight (float): Weight of flops_loss. + Defaults to 1.0. + init_cfg (Optional[dict]): Init config for ``BaseModule``. + Defaults to None. + """ + + def __init__(self, + distiller: VALID_DISTILLER_TYPE, + architecture: Union[BaseModel, Dict], + mutator_cfg: Union[Dict, DMCPChannelMutator] = dict( + type=' DMCPChannelMutator', + channel_unit_cfg=dict(type='DMCPChannelUnit')), + data_preprocessor: Optional[Union[Dict, nn.Module]] = None, + strategy: List = ['max', 'min', 'arch_random'], + init_cfg: Optional[Dict] = None, + arch_start_train=10000, + arch_train_freq=500, + distillation_times=20000, + target_flops=150, + flops_loss_type: str = 'log_l1', + flop_loss_weight: float = 1.0) -> None: + super().__init__(architecture, data_preprocessor, init_cfg) + + self.arch_start_train = arch_start_train + self.arch_train_freq = arch_train_freq + self.strategy = strategy + self.distillation_times = distillation_times + self.target_flops = target_flops + + self.flops_loss_type = flops_loss_type + self.flop_loss_weight = flop_loss_weight + self.cur_sample_prob = 1.0 + self.arch_train = False + + self.mutator: ChannelMutator = MODELS.build(mutator_cfg) + self.mutator.prepare_from_supernet(self.architecture) + + self.distiller = self._build_distiller(distiller) + self.distiller.prepare_from_teacher(self.architecture) + self.distiller.prepare_from_student(self.architecture) + + def _build_distiller( + self, distiller: VALID_DISTILLER_TYPE) -> ConfigurableDistiller: + """Build distiller.""" + if isinstance(distiller, dict): + distiller = MODELS.build(distiller) + if not isinstance(distiller, ConfigurableDistiller): + raise TypeError('distiller should be a `dict` or ' + '`ConfigurableDistiller` instance, but got ' + f'{type(distiller)}') + + return distiller + + def set_subnet(self, mode, arch_train=None) -> None: + """Set subnet by 'max' 'min' 'random' 'direct' or 'expected.""" + assert mode in ('max', 'min', 'random', 'direct', 'expected') + if arch_train is None: + arch_train = self.arch_train + self.mutator.sample_subnet(mode, arch_train) + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + """The iteration step during training.""" + if not self.arch_train and \ + self._iter > self.arch_start_train: + self.arch_train = True + + def distill_step( + batch_inputs: torch.Tensor, data_samples: List[BaseDataElement] + ) -> Dict[str, torch.Tensor]: + subnet_losses = dict() + with optim_wrapper['architecture'].optim_context( + self), self.distiller.student_recorders: # type: ignore + hard_loss = self(batch_inputs, data_samples, mode='loss') + subnet_losses.update(hard_loss) + + if self._iter > self.distillation_times: + soft_loss = self.distiller.compute_distill_losses() + subnet_losses.update(soft_loss) + + parsed_subnet_losses, _ = self.parse_losses(subnet_losses) + optim_wrapper['architecture'].update_params( + parsed_subnet_losses) + + return subnet_losses + + batch_inputs, data_samples = self.data_preprocessor(data, + True).values() + + total_losses = dict() + # update model parameters + max_net_num = min_net_num = random_net_num = direct_net_num = 1 + for kind in self.strategy: + if kind in ('max'): + self.set_subnet(mode='max') + with optim_wrapper['architecture'].optim_context( + self + ), self.distiller.teacher_recorders: # type: ignore + max_subnet_losses = self( + batch_inputs, data_samples, mode='loss') + parsed_max_subnet_losses, _ = self.parse_losses( + max_subnet_losses) + optim_wrapper['architecture'].update_params( + parsed_max_subnet_losses) + total_losses.update( + add_prefix(max_subnet_losses, f'max_subnet{max_net_num}')) + max_net_num += 1 + elif kind in ('min'): + self.set_subnet(mode='min') + min_subnet_losses =\ + distill_step(batch_inputs, data_samples) + total_losses.update( + add_prefix(min_subnet_losses, f'min_subnet{min_net_num}')) + min_net_num += 1 + elif kind in ('arch_random'): + if self.arch_train: + self.set_subnet(mode='direct') + direct_subnet_losses = distill_step( + batch_inputs, data_samples) + total_losses.update( + add_prefix(direct_subnet_losses, + f'direct_subnet{direct_net_num}')) + direct_net_num += 1 + else: + self.set_subnet(mode='random') + random_subnet_losses = distill_step( + batch_inputs, data_samples) + total_losses.update( + add_prefix(random_subnet_losses, + f'random_subnet{random_net_num}')) + random_net_num += 1 + elif kind in ('scheduled_random'): + if random.uniform(0, 1) > self.cur_sample_prob\ + and self.arch_train: + self.set_subnet(mode='direct') + direct_subnet_losses = distill_step( + batch_inputs, data_samples) + total_losses.update( + add_prefix(direct_subnet_losses, + f'direct_subnet{direct_net_num}')) + direct_net_num += 1 + else: + self.set_subnet(mode='random') + random_subnet_losses = distill_step( + batch_inputs, data_samples) + total_losses.update( + add_prefix(random_subnet_losses, + f'random_subnet{random_net_num}')) + random_net_num += 1 + self.cur_sample_prob *= 0.9999 + + # update arch parameters + if self.arch_train \ + and self._iter % self.arch_train_freq == 0: + with optim_wrapper['mutator'].optim_context(self): + optim_wrapper['mutator'].zero_grad() + mutator_loss = self._update_arch_params( + batch_inputs, data_samples, optim_wrapper, mode='loss') + total_losses.update(mutator_loss) + return total_losses + + def _update_arch_params(self, + inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]], + optim_wrapper: OptimWrapper, + mode: str = 'loss') -> Dict: + """Update the arch parameters in mutator. + + Returns: + dict: It should contain 2 keys: ``arch_loss``, ``flops_loss``. + ``arch_loss`` is a tensor for back propagation, which can be a + weighted sum of multiple losses. + ``flops_loss`` contains all the variables to be sent to the + logger. + """ + arch_params_loss = dict() + self.eval() + # update arch_loss + self.set_subnet(mode='max', arch_train=True) + with optim_wrapper['mutator'].optim_context(self): + arch_loss = self(inputs, data_samples, mode=mode) + parsed_arch_loss, _ = self.parse_losses(arch_loss) + optim_wrapper['mutator'].update_params(parsed_arch_loss) + arch_params_loss.update(add_prefix(arch_loss, 'arch')) + + # update flops_loss + self.set_subnet(mode='expected', arch_train=False) + expected_flops = self.calc_current_flops() + flops_loss = self._compute_flops_loss(expected_flops).to( + arch_loss['loss'].device) + parsed_flops_loss, _ = self.parse_losses({'loss': flops_loss}) + optim_wrapper['mutator'].update_params(parsed_flops_loss) + arch_params_loss.update(add_prefix({'loss': flops_loss}, 'flops')) + self.train() + return arch_params_loss + + def _compute_flops_loss(self, expected_flops): + """Calculation of loss functions of arch parameters. + + Calculate the difference between the calculated FLOPs and the target + FLOPs(MFLOPs). + + Args: + expected_flops (tensor|float): FLOPs calculated from the current + number of sampling channels + Returns: + tensor|float: A loss calculated from the input expected FLOPs and + the target FLOPs. And the type of this loss should be the same + as the expected FLOPs. + """ + flops_error = expected_flops - self.target_flops * 1e6 + + if self.flops_loss_type == 'l2': + floss = torch.pow(flops_error, 2) + elif self.flops_loss_type == 'inverted_log_l1': + floss = -torch.log(1 / (flops_error + 1e-5)) + elif self.flops_loss_type == 'log_l1': + if abs(flops_error) > 200: + ratio = 0.1 + else: + ratio = 1.0 + # piecewise log function + lower_flops = self.target_flops * 0.95 + if expected_flops < lower_flops: + floss = torch.log(ratio * abs(flops_error)) + elif (lower_flops <= expected_flops < self.target_flops): + floss = expected_flops * 0 + else: + floss = ( + torch.log(ratio * abs(expected_flops - (lower_flops)))) + elif self.flops_loss_type == 'l1': + floss = abs(flops_error) + else: + raise NotImplementedError + return floss * self.flop_loss_weight + + def calc_current_flops(self): + """Calculate the FLOPs under the current sampled network.""" + estimator = ResourceEstimator() + model = getattr(self, 'module', self) + estimation = estimator.estimate( + model=model.architecture.backbone, + flops_params_cfg=dict(units=None)) + return estimation['flops'] + + def forward(self, + inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + mode: str = 'loss') -> ForwardResults: + """Forward.""" + return BaseAlgorithm.forward(self, inputs, data_samples, mode) + + @property + def _iter(self): + """Get current sum iteration number.""" + message_hub = MessageHub.get_current_instance() + if 'iter' in message_hub.runtime_info: + return message_hub.runtime_info['iter'] + else: + raise RuntimeError('Use MessageHub before initiation.' + 'iter is inited in before_run_iter().') + + +@MODEL_WRAPPERS.register_module() +class DMCPDDP(MMDistributedDataParallel): + """DDP for DMCP and rewrite train_step of MMDDP.""" + + def __init__(self, + *, + device_ids: Optional[Union[List, int, torch.device]] = None, + **kwargs) -> None: + if device_ids is None: + if os.environ.get('LOCAL_RANK') is not None: + device_ids = [int(os.environ['LOCAL_RANK'])] + super().__init__(device_ids=device_ids, **kwargs) + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + """The iteration step during training.""" + if not self.module.arch_train and \ + self.module._iter > self.module.arch_start_train: + self.module.arch_train = True + + def distill_step( + batch_inputs: torch.Tensor, data_samples: List[BaseDataElement] + ) -> Dict[str, torch.Tensor]: + subnet_losses = dict() + with optim_wrapper['architecture'].optim_context( + self), self.module.distiller.student_recorders: + hard_loss = self(batch_inputs, data_samples, mode='loss') + subnet_losses.update(hard_loss) + if self.module._iter > self.module.distillation_times: + soft_loss = \ + self.module.distiller.compute_distill_losses() + subnet_losses.update(soft_loss) + + parsed_subnet_losses, _ = \ + self.module.parse_losses(subnet_losses) + optim_wrapper['architecture'].update_params( + parsed_subnet_losses) + + return subnet_losses + + batch_inputs, data_samples = self.module.data_preprocessor( + data, True).values() + + total_losses = dict() + # update model parameters + max_net_num = min_net_num = random_net_num = direct_net_num = 1 + for kind in self.module.strategy: + if kind in ('max'): + self.module.set_subnet(mode='max') + with optim_wrapper['architecture'].optim_context( + self + ), self.module.distiller.teacher_recorders: # type: ignore + max_subnet_losses = self( + batch_inputs, data_samples, mode='loss') + parsed_max_subnet_losses, _ = self.module.parse_losses( + max_subnet_losses) + optim_wrapper['architecture'].update_params( + parsed_max_subnet_losses) + total_losses.update( + add_prefix(max_subnet_losses, f'max_subnet{max_net_num}')) + max_net_num += 1 + elif kind in ('min'): + self.module.set_subnet(mode='min') + min_subnet_losses = distill_step(batch_inputs, data_samples) + total_losses.update( + add_prefix(min_subnet_losses, f'min_subnet{min_net_num}')) + min_net_num += 1 + elif kind in ('arch_random'): + if self.module.arch_train: + self.module.set_subnet(mode='direct') + direct_subnet_losses = distill_step( + batch_inputs, data_samples) + total_losses.update( + add_prefix(direct_subnet_losses, + f'direct_subnet{direct_net_num}')) + direct_net_num += 1 + else: + self.module.set_subnet(mode='random') + random_subnet_losses = distill_step( + batch_inputs, data_samples) + total_losses.update( + add_prefix(random_subnet_losses, + f'random_subnet{random_net_num}')) + random_net_num += 1 + elif kind in ('scheduled_random'): + if random.uniform(0, 1) > self.module.cur_sample_prob\ + and self.module.arch_train: + self.module.set_subnet(mode='direct') + direct_subnet_losses = distill_step( + batch_inputs, data_samples) + total_losses.update( + add_prefix(direct_subnet_losses, + f'direct_subnet{direct_net_num}')) + direct_net_num += 1 + else: + self.module.set_subnet(mode='random') + random_subnet_losses = distill_step( + batch_inputs, data_samples) + total_losses.update( + add_prefix(random_subnet_losses, + f'random_subnet{random_net_num}')) + random_net_num += 1 + self.module.cur_sample_prob *= 0.9999 + + # update arch parameters + if self.module.arch_train \ + and self.module._iter % self.module.arch_train_freq == 0: + with optim_wrapper['mutator'].optim_context(self): + optim_wrapper['mutator'].zero_grad() + mutator_loss = self.module._update_arch_params( + batch_inputs, data_samples, optim_wrapper, mode='loss') + total_losses.update(mutator_loss) + return total_losses diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/group_fisher_algoritho.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/group_fisher_algoritho.py new file mode 100755 index 000000000..eccbe1228 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/group_fisher_algoritho.py @@ -0,0 +1,7 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This file includes the modules in the impl folder. + +As it only records impl modules, it is not initialized automatically. +""" +from mmrazor.implementations.pruning.group_fisher import \ + GroupFisherAlgorithm # noqa diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/ite_prune_algorithm.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/ite_prune_algorithm.py new file mode 100755 index 000000000..937aaa156 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/ite_prune_algorithm.py @@ -0,0 +1,273 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Optional, Tuple, Union + +import torch +import torch.nn as nn +from mmengine import MessageHub, MMLogger +from mmengine.model import BaseModel +from mmengine.structures import BaseDataElement + +from mmrazor.models.mutables import MutableChannelUnit +from mmrazor.models.mutators import ChannelMutator +from mmrazor.registry import MODELS +from ..base import BaseAlgorithm + +LossResults = Dict[str, torch.Tensor] +TensorResults = Union[Tuple[torch.Tensor], torch.Tensor] +PredictResults = List[BaseDataElement] +ForwardResults = Union[LossResults, TensorResults, PredictResults] + + +class ItePruneConfigManager: + """ItePruneConfigManager manages the config of the structure of the model + during pruning. + + Args: + target (Dict[str, Union[int, float]]): The target structure to prune. + supernet (Dict[str, Union[int, float]]): The sturecture of the + supernet. + step_freq (int, optional): The prune step of epoch/iter to prune. + Defaults to 1. + prune_times (int, optional): The times to prune. Defaults to 1. + linear_schedule (bool, optional): flag to set linear ratio schedule. + Defaults to True. + """ + + def __init__(self, + target: Dict[str, Union[int, float]], + supernet: Dict[str, Union[int, float]], + step_freq=1, + prune_times=1, + linear_schedule=True) -> None: + + self.supernet = supernet + self.target = target + self.step_freq = step_freq + self.prune_times = prune_times + self.linear_schedule = linear_schedule + + self.delta: Dict = self._get_delta_each_iter(self.target, + self.supernet, + self.prune_times) + + def is_prune_time(self, iteration): + """Is the time to prune during training process.""" + return iteration % self.step_freq == 0 \ + and iteration // self.step_freq < self.prune_times + + def prune_at(self, iteration): + """Get the pruning structure in a time(iteration).""" + times = iteration // self.step_freq + 1 + assert times <= self.prune_times + prune_current = {} + ratio = times / self.prune_times + + for key in self.target: + if self.linear_schedule: + # TO DO: add scheduler for more pruning rate schedule + prune_current[key] = (self.target[key] - self.supernet[key] + ) * ratio + self.supernet[key] + else: + prune_current[key] = self.target[key] + if isinstance(self.supernet[key], int): + prune_current[key] = int(prune_current[key]) + return prune_current + + def _get_delta_each_iter(self, target: Dict, supernet: Dict, times: int): + """Get the structure change for pruning once.""" + delta = {} + for key in target: + one_target = target[key] + if isinstance(one_target, float): + delta[key] = (1.0 - one_target) / times + elif isinstance(one_target, int): + delta[key] = int((supernet[key] - one_target) / times) + else: + raise NotImplementedError() + return delta + + +@MODELS.register_module() +class ItePruneAlgorithm(BaseAlgorithm): + """ItePruneAlgorithm prunes a model iteratively until reaching a prune- + target. + + Args: + architecture (Union[BaseModel, Dict]): The model to be pruned. + mutator_cfg (Union[Dict, ChannelMutator], optional): The config + of a mutator. Defaults to dict( type='ChannelMutator', + channel_unit_cfg=dict( type='SequentialMutableChannelUnit')). + data_preprocessor (Optional[Union[Dict, nn.Module]], optional): + Defaults to None. + target_pruning_ratio (dict, optional): The prune-target. The template + of the prune-target can be get by calling + mutator.choice_template(). Defaults to {}. + step_freq (int, optional): The step between two pruning operations. + Defaults to 1. + prune_times (int, optional): The total times to prune a model. + Defaults to 1. + init_cfg (Optional[Dict], optional): init config for architecture. + Defaults to None. + linear_schedule (bool, optional): flag to set linear ratio schedule. + Defaults to True. + """ + + def __init__(self, + architecture: Union[BaseModel, Dict], + mutator_cfg: Union[Dict, ChannelMutator] = dict( + type='ChannelMutator', + channel_unit_cfg=dict( + type='SequentialMutableChannelUnit')), + data_preprocessor: Optional[Union[Dict, nn.Module]] = None, + target_pruning_ratio: Optional[Dict[str, float]] = None, + step_freq=1, + prune_times=1, + init_cfg: Optional[Dict] = None, + linear_schedule=True) -> None: + + super().__init__(architecture, data_preprocessor, init_cfg) + + # decided by EpochBasedRunner or IterBasedRunner + self.target_pruning_ratio = target_pruning_ratio + self.step_freq = step_freq + self.prune_times = prune_times + self.linear_schedule = linear_schedule + + self.mutator: ChannelMutator = MODELS.build(mutator_cfg) + self.mutator.prepare_from_supernet(self.architecture) + + def set_target_pruning_ratio( + self, target: Dict[str, float], + units: List[MutableChannelUnit]) -> Dict[str, float]: + """According to the target pruning ratio of each unit, set the target + ratio of each unit in units.""" + target_pruning_ratio: Dict[str, float] = dict() + for unit in units: + assert isinstance(unit, MutableChannelUnit), ( + f'unit should be `MutableChannelUnit`, but got {type(unit)}.') + unit_name = unit.name + # The config of target pruning ratio does not + # contain all units. + if unit_name not in target: + continue + unit_target = target[unit_name] + assert isinstance(unit_target, (float, int)) + target_pruning_ratio[unit_name] = unit_target + return target_pruning_ratio + + def check_prune_target(self, config: Dict): + """Check if the prune-target is supported.""" + for value in config.values(): + assert isinstance(value, int) or isinstance(value, float) + + def _init_prune_config_manager(self): + """init prune_config_manager and check step_freq & prune_times. + + message_hub['max_epoch/iter'] unaccessible when initiation. + """ + if self.target_pruning_ratio is None: + target_pruning_ratio = self.mutator.current_choices + else: + target_pruning_ratio = self.set_target_pruning_ratio( + self.target_pruning_ratio, self.mutator.mutable_units) + + if self.by_epoch: + # step_freq based on iterations + self.step_freq *= self._iters_per_epoch + + # config_manager move to forward. + # message_hub['max_epoch'] unaccessible when init + prune_config_manager = ItePruneConfigManager( + target_pruning_ratio, + self.mutator.current_choices, + self.step_freq, + prune_times=self.prune_times, + linear_schedule=self.linear_schedule) + + return prune_config_manager + + def forward(self, + inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + mode: str = 'tensor') -> ForwardResults: + """Forward.""" + + if self.training: + if not hasattr(self, 'prune_config_manager'): + # self._iters_per_epoch() only available after initiation + self.prune_config_manager = self._init_prune_config_manager() + if self.prune_config_manager.is_prune_time(self._iter): + + config = self.prune_config_manager.prune_at(self._iter) + + self.mutator.set_choices(config) + + logger = MMLogger.get_current_instance() + if (self.by_epoch): + logger.info( + f'The model is pruned at {self._epoch}th epoch once.') + else: + logger.info( + f'The model is pruned at {self._iter}th iter once.') + + return super().forward(inputs, data_samples, mode) + + def init_weights(self): + return self.architecture.init_weights() + + # private methods + + @property + def by_epoch(self): + """Get epoch/iter based train loop.""" + # IterBasedTrainLoop max_epochs default to 1 + # TO DO: Add by_epoch params or change default max_epochs? + return self._max_epochs != 1 + + @property + def _epoch(self): + """Get current epoch number.""" + message_hub = MessageHub.get_current_instance() + if 'epoch' in message_hub.runtime_info: + return message_hub.runtime_info['epoch'] + else: + raise RuntimeError('Use MessageHub before initiation.' + 'epoch is inited in before_run_epoch().') + + @property + def _iter(self): + """Get current sum iteration number.""" + message_hub = MessageHub.get_current_instance() + if 'iter' in message_hub.runtime_info: + return message_hub.runtime_info['iter'] + else: + raise RuntimeError('Use MessageHub before initiation.' + 'iter is inited in before_run_iter().') + + @property + def _max_epochs(self): + """Get max epoch number. + + Default 1 for IterTrainLoop + """ + message_hub = MessageHub.get_current_instance() + if 'max_epochs' in message_hub.runtime_info: + return message_hub.runtime_info['max_epochs'] + else: + raise RuntimeError('Use MessageHub before initiation.' + 'max_epochs is inited in before_run_epoch().') + + @property + def _max_iters(self): + """Get max iteration number.""" + message_hub = MessageHub.get_current_instance() + if 'max_iters' in message_hub.runtime_info: + return message_hub.runtime_info['max_iters'] + else: + raise RuntimeError('Use MessageHub before initiation.' + 'max_iters is inited in before_run_iter().') + + @property + def _iters_per_epoch(self): + """Get iter num per epoch.""" + return self._max_iters / self._max_epochs diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/slimmable_network.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/slimmable_network.py new file mode 100755 index 000000000..f57c223ee --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/slimmable_network.py @@ -0,0 +1,219 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +from pathlib import Path +from typing import Dict, List, Optional, Union + +import torch +from mmengine.model import BaseModel, MMDistributedDataParallel +from mmengine.optim import OptimWrapper +from mmengine.structures import BaseDataElement +from torch import nn + +from mmrazor.models.mutables import BaseMutable +from mmrazor.models.mutators import SlimmableChannelMutator +from mmrazor.models.utils import (add_prefix, + reinitialize_optim_wrapper_count_status) +from mmrazor.registry import MODEL_WRAPPERS, MODELS +from mmrazor.structures.subnet.fix_subnet import _dynamic_to_static +from ..base import BaseAlgorithm + +VALID_MUTATOR_TYPE = Union[SlimmableChannelMutator, Dict] +VALID_PATH_TYPE = Union[str, Path] +VALID_CHANNEL_CFG_PATH_TYPE = Union[VALID_PATH_TYPE, List[VALID_PATH_TYPE]] + + +@MODELS.register_module() +class SlimmableNetwork(BaseAlgorithm): + """Slimmable Neural Networks. + + Please refer to paper + [Slimmable Neural Networks](https://arxiv.org/abs/1812.08928) for details. + + Args: + mutator (dict | :obj:`SlimmableChannelMutator`): The config of + :class:`SlimmableChannelMutator` or built mutator. + About the config of mutator, please refer to + SlimmableChannelMutator + architecture (dict | :obj:`BaseModel`): The config of + :class:`BaseModel` or built model. + deploy_index (int): index of subnet to be deployed. + data_preprocessor (dict | :obj:`torch.nn.Module` | None): The + pre-process config of :class:`BaseDataPreprocessor`. + Defaults to None. + init_cfg (dict | None): The weight initialized config for + :class:`BaseModule`. Default to None. + """ + + def __init__(self, + architecture: Union[BaseModel, Dict], + mutator: VALID_MUTATOR_TYPE = None, + deploy_index=-1, + data_preprocessor: Optional[Union[Dict, nn.Module]] = None, + init_cfg: Optional[Dict] = None) -> None: + super().__init__(architecture, data_preprocessor, init_cfg) + + if isinstance(mutator, dict): + self.mutator = MODELS.build(mutator) + else: + self.mutator = mutator + self.mutator.prepare_from_supernet(self.architecture) + self.num_subnet = len(self.mutator.subnets) + + # must after `prepare_from_supernet` + if deploy_index != -1: + self._deploy(deploy_index) + else: + self.is_deployed = False + + # HACK + # reinitialize count status of `OptimWrapper` since + # `optim_wrapper.update_params` will be called multiple times + # in our slimmable train step. + self._optim_wrapper_count_status_reinitialized = False + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + """Train step.""" + input_data = self.data_preprocessor(data, True) + batch_inputs = input_data['inputs'] + data_samples = input_data['data_samples'] + train_kwargs = dict( + batch_inputs=batch_inputs, + data_samples=data_samples, + optim_wrapper=optim_wrapper) + if self.is_deployed: + return self._fixed_train_step(**train_kwargs) + else: + return self._slimmable_train_step(**train_kwargs) + + def _slimmable_train_step( + self, + batch_inputs: torch.Tensor, + data_samples: List[BaseDataElement], + optim_wrapper: OptimWrapper, + ) -> Dict[str, torch.Tensor]: + """Train step of Slimmable Network.""" + if not self._optim_wrapper_count_status_reinitialized: + reinitialize_optim_wrapper_count_status( + model=self, + optim_wrapper=optim_wrapper, + accumulative_counts=self.num_subnet) + self._optim_wrapper_count_status_reinitialized = True + total_losses = dict() + + for subnet_idx, subnet in enumerate(self.mutator.subnets): + self.mutator.set_choices(subnet) + with optim_wrapper.optim_context(self): + losses = self(batch_inputs, data_samples, mode='loss') + parsed_losses, _ = self.parse_losses(losses) + optim_wrapper.update_params(parsed_losses) + + total_losses.update(add_prefix(losses, f'subnet_{subnet_idx}')) + + return total_losses + + def _fixed_train_step( + self, + batch_inputs: torch.Tensor, + data_samples: List[BaseDataElement], + optim_wrapper: OptimWrapper, + ) -> Dict[str, torch.Tensor]: + """Train step of fixed network.""" + with optim_wrapper.optim_context(self): + losses = self(batch_inputs, data_samples, mode='loss') + parsed_losses, _ = self.parse_losses(losses) + optim_wrapper.update_params(parsed_losses) + + return losses + + def _fix_archtecture(self): + for module in self.architecture.modules(): + if isinstance(module, BaseMutable): + if not module.is_fixed: + module.fix_chosen(None) + + def _deploy(self, index: int): + self.mutator.set_choices(self.mutator.subnets[index]) + self.mutator.fix_channel_mutables() + self._fix_archtecture() + _dynamic_to_static(self.architecture) + self.is_deployed = True + + +@MODEL_WRAPPERS.register_module() +class SlimmableNetworkDDP(MMDistributedDataParallel): + """DDP wrapper for Slimmable Neural Network.""" + + def __init__(self, + *, + device_ids: Optional[Union[List, int, torch.device]] = None, + **kwargs) -> None: + if device_ids is None: + if os.environ.get('LOCAL_RANK') is not None: + device_ids = [int(os.environ['LOCAL_RANK'])] + super().__init__(device_ids=device_ids, **kwargs) + + def train_step(self, data: List[dict], + optim_wrapper: OptimWrapper) -> Dict[str, torch.Tensor]: + """Train step.""" + input_data = self.module.data_preprocessor(data, True) + batch_inputs = input_data['inputs'] + data_samples = input_data['data_samples'] + train_kwargs = dict( + batch_inputs=batch_inputs, + data_samples=data_samples, + optim_wrapper=optim_wrapper) + if self.module.is_deployed: + return self._fixed_train_step(**train_kwargs) + else: + return self._slimmable_train_step(**train_kwargs) + + def _slimmable_train_step( + self, + batch_inputs: torch.Tensor, + data_samples: List[BaseDataElement], + optim_wrapper: OptimWrapper, + ) -> Dict[str, torch.Tensor]: + """Train step of Slimmable Network.""" + if not self._optim_wrapper_count_status_reinitialized: + reinitialize_optim_wrapper_count_status( + model=self, + optim_wrapper=optim_wrapper, + accumulative_counts=self.module.num_subnet) + self._optim_wrapper_count_status_reinitialized = True + total_losses = dict() + + for subnet_idx, subnet in enumerate(self.module.mutator.subnets): + self.module.mutator.set_choices(subnet) + with optim_wrapper.optim_context(self): + losses = self(batch_inputs, data_samples, mode='loss') + parsed_losses, _ = self.module.parse_losses(losses) + optim_wrapper.update_params(parsed_losses) + + total_losses.update(add_prefix(losses, f'subnet_{subnet_idx}')) + + return total_losses + + def _fixed_train_step( + self, + batch_inputs: torch.Tensor, + data_samples: List[BaseDataElement], + optim_wrapper: OptimWrapper, + ) -> Dict[str, torch.Tensor]: + """Train step of fixed network.""" + with optim_wrapper.optim_context(self): + losses = self(batch_inputs, data_samples, mode='loss') + parsed_losses, _ = self.module.parse_losses(losses) + optim_wrapper.update_params(parsed_losses) + + return losses + + @property + def _optim_wrapper_count_status_reinitialized(self) -> bool: + return self.module._optim_wrapper_count_status_reinitialized + + @_optim_wrapper_count_status_reinitialized.setter + def _optim_wrapper_count_status_reinitialized(self, val: bool) -> None: + assert isinstance(val, bool) + + self.module._optim_wrapper_count_status_reinitialized = val diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/__init__.py new file mode 100755 index 000000000..03a9538e2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .mm_architecture import MMArchitectureQuant, MMArchitectureQuantDDP + +__all__ = ['MMArchitectureQuant', 'MMArchitectureQuantDDP'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/mm_architecture.py b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/mm_architecture.py new file mode 100755 index 000000000..ce6d926d0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/mm_architecture.py @@ -0,0 +1,427 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +from typing import Any, Dict, List, Optional, Tuple, Union + +import torch +from mmengine.config import Config +from mmengine.model import MMDistributedDataParallel +from mmengine.runner import load_checkpoint +from mmengine.structures import BaseDataElement +from torch import nn + +from mmrazor.models.utils import pop_rewriter_function_record +from mmrazor.registry import MODEL_WRAPPERS, MODELS +from mmrazor.structures.quantization import QConfigHandler +from ..base import BaseAlgorithm, BaseModel + +try: + from torch.ao.quantization import (FakeQuantizeBase, MinMaxObserver, + PerChannelMinMaxObserver, + disable_observer) +except ImportError: + from mmrazor.utils import get_placeholder + + FakeQuantizeBase = get_placeholder('torch>=1.13') + MinMaxObserver = get_placeholder('torch>=1.13') + PerChannelMinMaxObserver = get_placeholder('torch>=1.13') + disable_observer = get_placeholder('torch>=1.13') + +LossResults = Dict[str, torch.Tensor] +TensorResults = Union[Tuple[torch.Tensor], torch.Tensor] +PredictResults = List[BaseDataElement] +ForwardResults = Union[LossResults, TensorResults, PredictResults] + + +@MODELS.register_module() +class MMArchitectureQuant(BaseAlgorithm): + """General quantization for OpenMMLab's models. + + Args: + architecture (Union[Dict, BaseModel]): The config of model to be + quantized. + quantizer (Union[Dict, BaseModel]): The quantizer to support different + backend type. + deploy_cfg (Union[str, Dict]): Deployment config file or Config object. + qmodel_modes (List): The available mode of runner. + data_preprocessor (Optional[Dict]): The pre-process + config of :class:`BaseDataPreprocessor`. Defaults to None. + forward_modes (Tuple): The modes in forward method in OpenMMLab + architecture could be tensor, predict, or loss. It can generate + different graph of quantized model. + float_checkpoint (Optional[str]): The path of pretrained FP checkpoint. + Quantization is different from or task, we recommend to use + `float_checkpoint` as pretrain model. Defaults to None. + init_cfg (Optional[Dict]): The weight initialized config for: + class:`BaseModule`. + + Note: + forward_modes (Tuple): In OpenMMLab architecture, differenet modes + will trace a different graph of quantized model. + """ + + def __init__(self, + architecture: Union[Dict, BaseModel], + quantizer: Union[Dict, BaseModel], + deploy_cfg: Optional[Union[str, Dict]] = None, + data_preprocessor: Optional[Dict] = None, + forward_modes: Tuple = ('tensor', 'predict', 'loss'), + float_checkpoint: Optional[str] = None, + input_shapes: Tuple = (1, 3, 224, 224), + init_cfg: Optional[Dict] = None): + + super().__init__(architecture, data_preprocessor, init_cfg) + + self.quantizer = MODELS.build(quantizer) + self.input_shapes = input_shapes + self.forward_modes = forward_modes + if isinstance(deploy_cfg, str): + deploy_cfg = Config.fromfile(deploy_cfg) + self.deploy_cfg = deploy_cfg + + # Replace syncbn and _BatchNormXd (in mmengine) with batchnorm2d + self.quantizer.convert_batchnorm2d(self.architecture) + + # If we have a float_checkpoint, we load it as pretrain. + if float_checkpoint: + _ = load_checkpoint(self.architecture, float_checkpoint) + self.architecture._is_init = True + + self.qmodels = self._build_qmodels(self.architecture) + self.sync_qparams('tensor') + self.reset_observer_and_fakequant_statistics(self) + + def reset_observer_and_fakequant_statistics(self, model): + """Reset the statistics in observers and fake quantizers. + + The forward computation in `_build_qmodels` can modify the original + statistics in observers and fake quantizers. + """ + for module in model.modules(): + if isinstance(module, (MinMaxObserver, PerChannelMinMaxObserver)): + module.reset_min_max_vals() + elif isinstance(module, FakeQuantizeBase): + module.scale.data = torch.ones_like(module.scale) + module.zero_point.data = torch.zeros_like(module.zero_point) + + def sync_qparams(self, src_mode: str): + """Sync all quantize parameters in different `forward_modes`. We could + have more than one forward mode to generate graphs, each mode will + generate one graph. But in training, only one graph will be update, so + we need to sync qparams in the other graphs. + + Args: + src_mode (str): The modes of forward method. + + Note: + `traverse()` method recursively traverses all modules to sync + quantized graph generated from different `forward_modes`. + This is because We have different mode ('tensor', 'predict', + 'loss') in OpenMMLab architecture which have different graph + in some subtle ways, so we need to sync them here. + """ + + def traverse(module, prefix): + for name, child in module._modules.items(): + if module is None: + continue + child_name = f'{prefix}{name}' + if isinstance(child, FakeQuantizeBase): + for name, param in child.named_parameters(): + param_name = f'{child_name}.{name}' + src_param = src_state_dict[param_name] + if src_param.shape == param.shape: + param.data.copy_(src_param) + else: + requirs_grad = param.requires_grad + param.requires_grad = False + param.resize_(src_param.shape) + param.requires_grad = requirs_grad + param.data.copy_(src_param) + for name, buffer in child.named_buffers(): + buffer_name = f'{child_name}.{name}' + src_buffer = src_state_dict[buffer_name] + if src_buffer.shape == buffer.shape: + buffer.data.copy_(src_buffer) + else: + buffer.resize_(src_buffer.shape) + buffer.data.copy_(src_buffer) + else: + traverse(child, f'{child_name}.') + + src_state_dict = self.qmodels[src_mode].state_dict() + for mode in self.forward_modes: + if mode == src_mode: + continue + traverse(self.qmodels[mode], '') + + def _get_rewriter_context_in_mmdeploy(self, deploy_cfg): + """Get rewriter context in mmdeploy according to the deploy related + config.""" + from mmdeploy.apis.onnx.passes import optimize_onnx + from mmdeploy.codebase import import_codebase + from mmdeploy.core import RewriterContext + from mmdeploy.utils import (IR, Backend, get_backend, get_codebase, + get_dynamic_axes, get_ir_config, + get_onnx_config) + from mmdeploy.utils.config_utils import get_codebase_external_module + + codebase = get_codebase(deploy_cfg) + custom_module_list = get_codebase_external_module(deploy_cfg) + import_codebase(codebase, custom_module_list) + + def _add_or_update(cfg: dict, key: str, val: Any): + if key in cfg and isinstance(cfg[key], dict) and isinstance( + val, dict): + cfg[key].update(val) + else: + cfg[key] = val + + context_info = dict() + deploy_cfg = copy.deepcopy(deploy_cfg) + + backend = get_backend(deploy_cfg).value + + onnx_cfg = get_onnx_config(deploy_cfg) + opset_version = onnx_cfg.get('opset_version', 11) + + input_names = onnx_cfg['input_names'] + output_names = onnx_cfg['output_names'] + axis_names = input_names + output_names + dynamic_axes = get_dynamic_axes(deploy_cfg, axis_names) + + verbose = not onnx_cfg.get('strip_doc_string', True) or onnx_cfg.get( + 'verbose', False) + keep_initializers_as_inputs = onnx_cfg.get( + 'keep_initializers_as_inputs', True) + optimize = onnx_cfg.get('optimize', False) + if backend == Backend.NCNN.value: + """NCNN backend needs a precise blob counts, while using onnx + optimizer will merge duplicate initilizers without reference + count.""" + optimize = False + + ir_config = dict( + type='onnx', + input_names=input_names, + output_names=output_names, + opset_version=opset_version, + dynamic_axes=dynamic_axes, + verbose=verbose, + keep_initializers_as_inputs=keep_initializers_as_inputs) + + _add_or_update(deploy_cfg, 'ir_config', ir_config) + ir = IR.get(get_ir_config(deploy_cfg)['type']) + if isinstance(backend, Backend): + backend = backend.value + backend_config = dict(type=backend) + _add_or_update(deploy_cfg, 'backend_config', backend_config) + + context_info['cfg'] = deploy_cfg + context_info['ir'] = ir + if 'backend' not in context_info: + context_info['backend'] = backend + if 'opset' not in context_info: + context_info['opset'] = opset_version + + if 'onnx_custom_passes' not in context_info: + onnx_custom_passes = optimize_onnx if optimize else None + context_info['onnx_custom_passes'] = onnx_custom_passes + + return RewriterContext(**context_info) + + def _pop_function_record_in_rewriter_context(self, rewriter_context): + """Delete user-specific rewriters from + `RewriterContext._rewriter_manager`. We use the model which is + rewritten by mmdeploy to build quantized models. However not all the + functions rewritten by mmdeploy need to be rewritten in mmrazor. For + example, mmdeploy rewrite + `mmcls.models.classifiers.ImageClassifier.forward` and + `mmcls.models.classifiers.BaseClassifier.forward` for deployment. But + they can't be rewritten by mmrazor as ptq and qat are done in mmrazor. + So to ensure ptq and qat proceed normally, we have to remove these + record from `RewriterContext._rewriter_manager`. + + Args: + rewriter_context (RewriterContext): The RewriterContext used in + mmdeploy. + """ + skipped_methods = getattr(self.quantizer.tracer, 'skipped_methods', []) + function_record_to_pop = self.deploy_cfg.get('function_record_to_pop', + []) + function_record_to_pop.extend(skipped_methods) + return pop_rewriter_function_record(rewriter_context, + function_record_to_pop) + + def _build_qmodels(self, model: BaseModel): + """Build quantized models from the given model. + + Args: + model (BaseModel): the given fp model. + + Example: + The main body of the graph is all the same, but the last one or two + op will have difference, as shown below. + + self.qmodels['tensor'].graph.print_tabular() + opcode target args + call_module head.fc (activation_post_process_38,) + output output (head_fc,) + + self.qmodels['loss'].graph.print_tabular() + opcode target args + call_method _get_loss (head, head_fc, data_samples) + output output (_get_loss,) + + self.qmodels['predict'].graph.print_tabular() + opcode target args + call_method _get_predictions (head, head_fc, data_samples) + output output (_get_predictions,) + """ + + rewriter_context = self._get_rewriter_context_in_mmdeploy( + self.deploy_cfg) if self.deploy_cfg is not None else None + + if rewriter_context is not None: + # Pop function records in `quantizer.tracer.skipped_method` + # temporarily + function_record_backup = \ + self._pop_function_record_in_rewriter_context(rewriter_context) + + qmodels = nn.ModuleDict() + for mode in self.forward_modes: + concrete_args = {'mode': mode} + + if rewriter_context is not None: + with rewriter_context: + observed_module = self.quantizer.prepare( + model, concrete_args) + else: + observed_module = self.quantizer.prepare(model, concrete_args) + + qmodels[mode] = observed_module + + if rewriter_context is not None: + # Add these popped function records back. + rewriter_context._rewriter_manager.function_rewriter. \ + _registry._rewrite_records.update(function_record_backup) + + # data_samples can not be None in detectors during prediction. + # But we need to make the dummy prediction in _build_qmodels. + # It is more convenient to use `tensor` mode. + is_training = qmodels['tensor'].training + # Avoid random input changing bn's statistics + qmodels['tensor'].eval() + # Originally, the steps to train a qat model is as follows: + # 1. build qmodels 2. convert the model to ddpmodel 3. forward backward + # The shape of `scale` and `zero_point` can be modified during forward. + # We initialize these parameters with per-tensor mode by default for + # convenience. Their shape will be modified during forward if + # per-channel mode is used. It's hacky. Hence we need to input a + # dummy input to make sure the shape has been modified. + device = next(qmodels.parameters()).device + dummy_input = torch.randn(self.input_shapes).to(device) + qmodels['tensor'](dummy_input, None, 'tensor') + qmodels['tensor'].train(mode=is_training) + + return qmodels + + def forward(self, + inputs: torch.Tensor, + data_samples: Optional[List[BaseDataElement]] = None, + mode: str = 'tensor') -> ForwardResults: + """Forward with qmodels in quantization.""" + + if mode in self.qmodels: + qmodel = self.qmodels[mode] + return qmodel(inputs, data_samples, mode) + else: + return self.architecture(inputs, data_samples, mode) + + def calibrate_step(self, data: Union[Dict, Tuple, List]): + """PTQ method need calibrate by cali data.""" + + data = self.data_preprocessor(data, False) + return self._run_forward(data, mode='predict') + + def get_deploy_model(self): + """Prepare for deploy to the backend with mmdeploy, which will be used + in mmdeploy, and usually includes as follows: + + 1. prepare for the float model rewritten by mmdeploy. + 2. load checkpoint consists of float weight and quantized params in + mmrazor. + 3. post process weight fakequant for exporting .onnx that meet + the backend's requirement. + """ + device = next(self.parameters()).device + quantized_state_dict = self.qmodels['predict'].state_dict() + fp32_model = self.architecture + self.quantizer.convert_batchnorm2d(fp32_model) + observed_model = self.quantizer.prepare(fp32_model) + observed_model.load_state_dict(quantized_state_dict) + + self.quantizer.post_process_for_deploy( + observed_model, + device=device, + keep_w_fake_quant=True, + update_weight_with_fakequant=True) + + # replace various activation fakequant with base fakequant, which + # contributes to deploy our model to various backends. + for node in observed_model.graph.nodes: + if 'activation_post_process_' in node.name: + module_name = node.target + module = getattr(observed_model, module_name) + fakequant_new = QConfigHandler.replace_fakequant( + module, + self.quantizer.qconfig.a_qscheme, + update_qparams=True) + setattr(observed_model, module_name, fakequant_new) + + observed_model.apply(disable_observer) + + return observed_model + + +@MODEL_WRAPPERS.register_module() +class MMArchitectureQuantDDP(MMDistributedDataParallel): + """DDPwapper for MMArchitectureQuant. + + Args: + device_ids (Optional[Union[List, int, torch.device]]): devices to run + ddp. + """ + + def __init__(self, + *, + device_ids: Optional[Union[List, int, torch.device]] = None, + **kwargs) -> None: + + if device_ids is None: + if os.environ.get('LOCAL_RANK') is not None: + device_ids = [int(os.environ['LOCAL_RANK'])] + super().__init__(device_ids=device_ids, **kwargs) + # After moving all model parameters and buffers to the GPU + # (`model.cuda()`), the buffers in model are different. + self.module.qmodels = self.module._build_qmodels( + self.module.architecture) + self.module.sync_qparams('tensor') + self.module.reset_observer_and_fakequant_statistics(self) + + def calibrate_step(self, data: Union[Dict, Tuple, List]): + """PTQ method need calibrate by cali data.""" + + return self.module.calibrate_step(data) + + def sync_qparams(self, src_mode: str): + """Same as in 'MMArchitectureQuant'. Sync all quantize parameters in + different `forward_modes`. We could have several modes to generate + graphs, but in training, only one graph will be update, so we need to + sync qparams on the other graphs. + + Args: + src_mode (str): The src modes of forward method. + """ + + self.module.sync_qparams(src_mode) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/__init__.py new file mode 100755 index 000000000..1db10e906 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/__init__.py @@ -0,0 +1,10 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .backbones import * # noqa: F401,F403 +from .classifiers import * # noqa: F401,F403 +from .connectors import * # noqa: F401,F403 +from .dynamic_ops import * # noqa: F401,F403 +from .generators import * # noqa: F401,F403 +from .heads import * # noqa: F401,F403 +from .necks import * # noqa: F401,F403 +from .ops import * # noqa: F401,F403 +from .utils import * # noqa: F401,F403 diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/__init__.py new file mode 100755 index 000000000..99313ee7e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/__init__.py @@ -0,0 +1,12 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .darts_backbone import DartsBackbone +from .searchable_autoformer import AutoformerBackbone +from .searchable_mobilenet_v2 import SearchableMobileNetV2 +from .searchable_mobilenet_v3 import AttentiveMobileNetV3 +from .searchable_shufflenet_v2 import SearchableShuffleNetV2 +from .wideresnet import WideResNet + +__all__ = [ + 'DartsBackbone', 'AutoformerBackbone', 'SearchableMobileNetV2', + 'AttentiveMobileNetV3', 'SearchableShuffleNetV2', 'WideResNet' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/darts_backbone.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/darts_backbone.py new file mode 100755 index 000000000..a2c4f0689 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/darts_backbone.py @@ -0,0 +1,376 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict, List, Optional, Tuple, Union + +import torch +import torch.nn as nn +from mmcv.cnn import build_activation_layer, build_norm_layer +from torch import Tensor + +from mmrazor.registry import MODELS + + +class FactorizedReduce(nn.Module): + """Reduce feature map size by factorized pointwise (stride=2). + + Args: + in_channels (int): number of channels of input tensor. + out_channels (int): number of channels of output tensor. + act_cfg (Dict): config to build activation layer. + norm_cfg (Dict): config to build normalization layer. + """ + + def __init__( + self, + in_channels: int, + out_channels: int, + act_cfg: Dict = dict(type='ReLU'), + norm_cfg: Dict = dict(type='BN') + ) -> None: + super().__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.act_cfg = act_cfg + self.norm_cfg = norm_cfg + self.relu = build_activation_layer(self.act_cfg) + self.conv1 = nn.Conv2d( + self.in_channels, + self.out_channels // 2, + 1, + stride=2, + padding=0, + bias=False) + self.conv2 = nn.Conv2d( + self.in_channels, + self.out_channels // 2, + 1, + stride=2, + padding=0, + bias=False) + self.bn = build_norm_layer(self.norm_cfg, self.out_channels)[1] + + def forward(self, x: Tensor) -> Tensor: + """Forward with factorized reduce.""" + x = self.relu(x) + out = torch.cat([self.conv1(x), self.conv2(x[:, :, 1:, 1:])], dim=1) + out = self.bn(out) + return out + + +class StandardConv(nn.Module): + """Standard Convolution in Darts. Basic structure is ReLU-Conv-BN. + + Args: + in_channels (int): number of channels of input tensor. + out_channels (int): number of channels of output tensor. + kernel_size (Union[int, Tuple]): size of the convolving kernel. + stride (Union[int, Tuple]): controls the stride for the + cross-correlation, a single number or a one-element tuple. + Default to 1. + padding (Union[str, int, Tuple]): Padding added to both sides + of the input. Default to 0. + act_cfg (Dict): config to build activation layer. + norm_cfg (Dict): config to build normalization layer. + """ + + def __init__( + self, + in_channels: int, + out_channels: int, + kernel_size: Union[int, Tuple], + stride: Union[int, Tuple] = 1, + padding: Union[str, int, Tuple] = 0, + act_cfg: Dict = dict(type='ReLU'), + norm_cfg: Dict = dict(type='BN') + ) -> None: + super().__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.kernel_size = kernel_size + self.stride = stride + self.padding = padding + self.act_cfg = act_cfg + self.norm_cfg = norm_cfg + self.net = nn.Sequential( + build_activation_layer(self.act_cfg), + nn.Conv2d( + self.in_channels, + self.out_channels, + self.kernel_size, + self.stride, + self.padding, + bias=False), + build_norm_layer(self.norm_cfg, self.out_channels)[1]) + + def forward(self, x: Tensor) -> Tensor: + """Forward the standard convolution.""" + return self.net(x) + + +class Node(nn.Module): + """Node structure of DARTS. + + Args: + node_id (str): key of the node. + num_prev_nodes (int): number of previous nodes. + channels (int): number of channels of current node. + num_downsample_nodes (int): index of downsample node. + mutable_cfg (Dict): config of `DiffMutableModule`. + route_cfg (Dict): config of `DiffChoiceRoute`. + """ + + def __init__(self, node_id: str, num_prev_nodes: int, channels: int, + num_downsample_nodes: int, mutable_cfg: Dict, + route_cfg: Dict) -> None: + super().__init__() + edges = nn.ModuleDict() + for i in range(num_prev_nodes): + stride = 2 if i < num_downsample_nodes else 1 + edge_id = f'{node_id}_p{i}' + + module_kwargs = dict( + in_channels=channels, + out_channels=channels, + stride=stride, + ) + + mutable_cfg.update(module_kwargs=module_kwargs) + mutable_cfg.update(alias=edge_id) + edges.add_module(edge_id, MODELS.build(mutable_cfg)) + + route_cfg.update(alias=node_id) + route_cfg.update(edges=edges) + self.route = MODELS.build(route_cfg) + + def forward(self, prev_nodes: Union[List[Tensor], + Tuple[Tensor]]) -> Tensor: + """Forward with the previous nodes list.""" + return self.route(prev_nodes) + + +class Cell(nn.Module): + """Darts cell structure. + + Args: + num_nodes (int): number of nodes. + channels (int): number of channels of current cell. + prev_channels (int): number of channel of previous input. + prev_prev_channels (int): number of channel of previous previous input. + reduction (bool): whether to reduce the feature map size. + prev_reduction (bool): whether to reduce the previous feature map size. + mutable_cfg (Optional[Dict]): config of `DiffMutableModule`. + route_cfg (Optional[Dict]): config of `DiffChoiceRoute`. + act_cfg (Dict): config to build activation layer. + Defaults to dict(type='ReLU'). + norm_cfg (Dict): config to build normalization layer. + Defaults to dict(type='BN'). + """ + + def __init__( + self, + num_nodes: int, + channels: int, + prev_channels: int, + prev_prev_channels: int, + reduction: bool, + prev_reduction: bool, + mutable_cfg: Dict, + route_cfg: Dict, + act_cfg: Dict = dict(type='ReLU'), + norm_cfg: Dict = dict(type='BN'), + ) -> None: + + super().__init__() + self.act_cfg = act_cfg + self.norm_cfg = norm_cfg + self.reduction = reduction + self.num_nodes = num_nodes + + # If previous cell is reduction cell, current input size does not match + # with output size of cell[k-2]. So the output[k-2] should be reduced + # by preprocessing. + if prev_reduction: + self.preproc0 = FactorizedReduce(prev_prev_channels, channels, + self.act_cfg, self.norm_cfg) + else: + self.preproc0 = StandardConv(prev_prev_channels, channels, 1, 1, 0, + self.act_cfg, self.norm_cfg) + self.preproc1 = StandardConv(prev_channels, channels, 1, 1, 0, + self.act_cfg, self.norm_cfg) + + # generate dag + self.nodes = nn.ModuleList() + for depth in range(2, self.num_nodes + 2): + if reduction: + node_id = f'reduce_n{depth}' + num_downsample_nodes = 2 + else: + node_id = f'normal_n{depth}' + num_downsample_nodes = 0 + self.nodes.append( + Node(node_id, depth, channels, num_downsample_nodes, + mutable_cfg, route_cfg)) + + def forward(self, s0: Tensor, s1: Tensor) -> Tensor: + """Forward with the outputs of previous previous cell and previous + cell.""" + tensors = [self.preproc0(s0), self.preproc1(s1)] + for node in self.nodes: + cur_tensor = node(tensors) + tensors.append(cur_tensor) + + return torch.cat(tensors[2:], dim=1) + + +class AuxiliaryModule(nn.Module): + """Auxiliary head in 2/3 place of network to let the gradient flow well. + + Args: + in_channels (int): number of channels of inputs. + base_channels (int): number of middle channels of the auxiliary module. + out_channels (int): number of channels of outputs. + norm_cfg (Dict): config to build normalization layer. + Defaults to dict(type='BN'). + """ + + def __init__(self, + in_channels: int, + base_channels: int, + out_channels: int, + norm_cfg: Dict = dict(type='BN')) -> None: + super().__init__() + self.norm_cfg = norm_cfg + self.net = nn.Sequential( + nn.ReLU(), + nn.AvgPool2d(5, stride=2, padding=0, + count_include_pad=False), # 2x2 out + nn.Conv2d(in_channels, base_channels, kernel_size=1, bias=False), + build_norm_layer(self.norm_cfg, base_channels)[1], + nn.ReLU(inplace=True), + nn.Conv2d(base_channels, out_channels, kernel_size=2, + bias=False), # 1x1 out + build_norm_layer(self.norm_cfg, out_channels)[1], + nn.ReLU(inplace=True)) + + def forward(self, x: Tensor) -> Tensor: + """Forward the auxiliary module.""" + return self.net(x) + + +@MODELS.register_module() +class DartsBackbone(nn.Module): + """Backbone of Differentiable Architecture Search (DARTS). + + Args: + in_channels (int): number of channels of input tensor. + base_channels (int): number of middle channels. + mutable_cfg (Optional[Dict]): config of `DiffMutableModule`. + route_cfg (Optional[Dict]): config of `DiffChoiceRoute`. + num_layers (Optional[int]): number of layers. + Defaults to 8. + num_nodes (Optional[int]): number of nodes. + Defaults to 4. + stem_multiplier (Optional[int]): multiplier for stem. + Defaults to 3. + out_indices (tuple, optional): output indices for auxliary module. + Defaults to (7, ). + auxliary (bool, optional): whether use auxliary module. + Defaults to False. + aux_channels (Optional[int]): number of middle channels of + auxliary module. Defaults to None. + aux_out_channels (Optional[int]): number of output channels of + auxliary module. Defaults to None. + act_cfg (Dict): config to build activation layer. + Defaults to dict(type='ReLU'). + norm_cfg (Dict): config to build normalization layer. + Defaults to dict(type='BN'). + """ + + def __init__( + self, + in_channels: int, + base_channels: int, + mutable_cfg: Dict, + route_cfg: Dict, + num_layers: int = 8, + num_nodes: int = 4, + stem_multiplier: int = 3, + out_indices: Union[Tuple, List] = (7, ), + auxliary: bool = False, + aux_channels: Optional[int] = None, + aux_out_channels: Optional[int] = None, + act_cfg: Dict = dict(type='ReLU'), + norm_cfg: Dict = dict(type='BN'), + ) -> None: + super().__init__() + + self.in_channels = in_channels + self.base_channels = base_channels + self.num_layers = num_layers + self.num_nodes = num_nodes + self.stem_multiplier = stem_multiplier + self.out_indices = out_indices + assert self.out_indices[-1] == self.num_layers - 1 + if auxliary: + assert aux_channels is not None + assert aux_out_channels is not None + self.aux_channels = aux_channels + self.aux_out_channels = aux_out_channels + self.auxliary_indice = 2 * self.num_layers // 3 + + else: + self.auxliary_indice = -1 + self.norm_cfg = norm_cfg + self.act_cfg = act_cfg + self.out_channels = self.stem_multiplier * self.base_channels + stem_norm_cfg = copy.deepcopy(self.norm_cfg) + stem_norm_cfg.update(dict(affine=True)) + self.stem = nn.Sequential( + nn.Conv2d( + self.in_channels, self.out_channels, 3, 1, 1, bias=False), + build_norm_layer(self.norm_cfg, self.out_channels)[1]) + + # for the first cell, stem is used for both s0 and s1 + # prev_prev_channels and prev_channels is output channel size, + # but c_cur is input channel size. + prev_prev_channels = self.out_channels + prev_channels = self.out_channels + self.out_channels = self.base_channels + + self.cells = nn.ModuleList() + prev_reduction, reduction = False, False + for i in range(self.num_layers): + prev_reduction, reduction = reduction, False + # Reduce featuremap size and double channels in 1/3 + # and 2/3 layer. + if i in [self.num_layers // 3, 2 * self.num_layers // 3]: + self.out_channels *= 2 + reduction = True + + cell = Cell(self.num_nodes, self.out_channels, prev_channels, + prev_prev_channels, reduction, prev_reduction, + mutable_cfg, route_cfg, self.act_cfg, self.norm_cfg) + self.cells.append(cell) + + prev_prev_channels = prev_channels + prev_channels = self.out_channels * self.num_nodes + + if i == self.auxliary_indice: + self.auxliary_module = AuxiliaryModule(prev_channels, + self.aux_channels, + self.aux_out_channels, + self.norm_cfg) + + def forward(self, x: Tensor) -> Tensor: + """Forward the darts backbone.""" + outs = [] + s0 = s1 = self.stem(x) + for i, cell in enumerate(self.cells): + s0, s1 = s1, cell(s0, s1) + if i in self.out_indices: + outs.append(s1) + if i == self.auxliary_indice and self.training: + aux_feature = self.auxliary_module(s1) + outs.insert(0, aux_feature) + + return tuple(outs) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_autoformer.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_autoformer.py new file mode 100755 index 000000000..28bd85dc8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_autoformer.py @@ -0,0 +1,375 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List + +import numpy as np +import torch +import torch.nn as nn +from mmcv.cnn import build_activation_layer, build_norm_layer + +from mmrazor.models.architectures.dynamic_ops.bricks import ( + DynamicLinear, DynamicMultiheadAttention, DynamicPatchEmbed, + DynamicSequential) +from mmrazor.models.mutables import (BaseMutable, BaseMutableChannel, + MutableChannelContainer, + OneShotMutableChannel, + OneShotMutableValue) +from mmrazor.models.mutables.mutable_channel import OneShotMutableChannelUnit +from mmrazor.registry import MODELS + +try: + from mmcls.models.backbones.base_backbone import BaseBackbone +except ImportError: + from mmrazor.utils import get_placeholder + BaseBackbone = get_placeholder('mmcls') + + +class TransformerEncoderLayer(BaseBackbone): + """Autoformer block. + + Args: + embed_dims (int): Number of input channels. + num_heads (int): Number of attention heads. + mlp_ratio (List): Ratio of ffn. + attn_drop_rate (float): Dropout rate of the dropout layer after the + attention calculation of query and key. Defaults to 0. + proj_drop_rate (float): Dropout rate of the dropout layer after the + output projection. Defaults to 0. + out_drop_rate (dict): Dropout rate of the dropout layer before adding + the shortcut. Defaults to 0. + qkv_bias (bool, optional): Whether to keep bias of qkv. + Defaults to True. + act_cfg (Dict, optional): The config for acitvation function. + Defaults to dict(type='GELU'). + norm_cfg (Dict, optional): The config for normalization. + Defaults to dict(type='mmrazor.DynamicLayerNorm'). + init_cfg (Dict, optional): The config for initialization. + Defaults to None. + """ + + def __init__(self, + embed_dims: int, + num_heads: int, + mlp_ratio: float, + proj_drop_rate: float = 0., + attn_drop_rate: float = 0., + out_drop_rate: float = 0., + qkv_bias: bool = True, + act_cfg: Dict = dict(type='GELU'), + norm_cfg: Dict = dict(type='mmrazor.DynamicLayerNorm'), + init_cfg: Dict = None) -> None: + super().__init__(init_cfg) + + self.norm1_name, norm1 = build_norm_layer( + norm_cfg, embed_dims, postfix=1) + self.add_module(self.norm1_name, norm1) + + self.attn = DynamicMultiheadAttention( + embed_dims=embed_dims, + num_heads=num_heads, + attn_drop_rate=attn_drop_rate, + proj_drop_rate=proj_drop_rate, + out_drop_rate=out_drop_rate, + qkv_bias=qkv_bias) + + self.norm2_name, norm2 = build_norm_layer( + norm_cfg, embed_dims, postfix=2) + self.add_module(self.norm2_name, norm2) + + middle_channels = int(embed_dims * mlp_ratio) + self.fc1 = DynamicLinear(embed_dims, middle_channels) + self.fc2 = DynamicLinear(middle_channels, embed_dims) + self.act = build_activation_layer(act_cfg) + + @property + def norm1(self): + """The first normalization.""" + return getattr(self, self.norm1_name) + + @property + def norm2(self): + """The second normalization.""" + return getattr(self, self.norm2_name) + + def register_mutables(self, mutable_num_heads: BaseMutable, + mutable_mlp_ratios: BaseMutable, + mutable_q_embed_dims: BaseMutable, + mutable_head_dims: BaseMutable, + mutable_embed_dims: BaseMutable): + """Mutate the mutables of encoder layer.""" + # record the mutables + self.mutable_num_heads = mutable_num_heads + self.mutable_mlp_ratios = mutable_mlp_ratios + self.mutable_q_embed_dims = mutable_q_embed_dims + self.mutable_embed_dims = mutable_embed_dims + self.mutable_head_dims = mutable_head_dims + # handle the mutable of FFN + self.middle_channels = mutable_mlp_ratios * mutable_embed_dims + + self.attn.register_mutable_attr('num_heads', mutable_num_heads) + + # handle the mutable of the first dynamic LN + MutableChannelContainer.register_mutable_channel_to_module( + self.norm1, self.mutable_embed_dims, True) + # handle the mutable of the second dynamic LN + MutableChannelContainer.register_mutable_channel_to_module( + self.norm2, self.mutable_embed_dims, True) + + # handle the mutable of attn + MutableChannelContainer.register_mutable_channel_to_module( + self.attn, self.mutable_embed_dims, False) + MutableChannelContainer.register_mutable_channel_to_module( + self.attn, + self.mutable_q_embed_dims, + True, + end=self.mutable_q_embed_dims.current_choice) + MutableChannelContainer.register_mutable_channel_to_module( + self.attn.rel_pos_embed_k, self.mutable_head_dims, False) + MutableChannelContainer.register_mutable_channel_to_module( + self.attn.rel_pos_embed_v, self.mutable_head_dims, False) + + # handle the mutable of fc + MutableChannelContainer.register_mutable_channel_to_module( + self.fc1, mutable_embed_dims, False) + MutableChannelContainer.register_mutable_channel_to_module( + self.fc1, + self.middle_channels, + True, + start=0, + end=self.middle_channels.current_choice) + MutableChannelContainer.register_mutable_channel_to_module( + self.fc2, + self.middle_channels, + False, + start=0, + end=self.middle_channels.current_choice) + MutableChannelContainer.register_mutable_channel_to_module( + self.fc2, mutable_embed_dims, True) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + """Forward of Transformer Encode Layer.""" + residual = x + x = self.norm1(x) + x = self.attn(x) + x = residual + x + residual = x + x = self.norm2(x) + x = self.fc1(x) + x = self.act(x) + x = self.fc2(x) + return residual + x + + +@MODELS.register_module() +class AutoformerBackbone(BaseBackbone): + """Autoformer backbone. + + A PyTorch implementation of Autoformer introduced by: + `AutoFormer: Searching Transformers for Visual Recognition + `_ + + Modified from the `official repo + `. + + Args: + arch_setting (Dict[str, List]): Architecture settings. + img_size (int, optional): The image size of input. + Defaults to 224. + patch_size (int, optional): The patch size of autoformer. + Defaults to 16. + in_channels (int, optional): The input channel dimension. + Defaults to 3. + drop_rate (float): Probability of an element to be zeroed. + Defaults to 0. + drop_path_rate (float): stochastic depth rate. Defaults to 0. + qkv_bias (bool, optional): Whether to keep bias of qkv. + Defaults to True. + norm_cfg (Dict, optional): The config of normalization. + Defaults to dict(type='mmrazor.DynamicLayerNorm'). + act_cfg (Dict, optional): The config of activation functions. + Defaults to dict(type='GELU'). + use_final_norm (bool, optional): Whether use final normalization. + Defaults to True. + init_cfg (Dict, optional): The config for initialization. + Defaults to None. + + Excamples: + >>> arch_setting = dict( + ... mlp_ratios=[3.0, 3.5, 4.0], + ... num_heads=[8, 9, 10], + ... depth=[14, 15, 16], + ... embed_dims=[528, 576, 624] + ... ) + >>> model = AutoformerBackbone(arch_setting=arch_setting) + """ + + def __init__(self, + arch_setting: Dict[str, List], + img_size: int = 224, + patch_size: int = 16, + in_channels: int = 3, + drop_rate: float = 0., + drop_path_rate: float = 0., + qkv_bias: bool = True, + norm_cfg: Dict = dict(type='mmrazor.DynamicLayerNorm'), + act_cfg: Dict = dict(type='GELU'), + use_final_norm: bool = True, + init_cfg: Dict = None) -> None: + + super().__init__(init_cfg) + + self.arch_setting = arch_setting + self.img_size = img_size + self.patch_size = patch_size + self.qkv_bias = qkv_bias + self.in_channels = in_channels + self.drop_rate = drop_rate + self.use_final_norm = use_final_norm + self.act_cfg = act_cfg + + # adapt mutable settings + self.mlp_ratio_range: List = self.arch_setting['mlp_ratios'] + self.num_head_range: List = self.arch_setting['num_heads'] + self.depth_range: List = self.arch_setting['depth'] + self.embed_dim_range: List = self.arch_setting['embed_dims'] + + # mutable variables of autoformer + self.mutable_depth = OneShotMutableValue( + value_list=self.depth_range, default_value=self.depth_range[-1]) + + self.mutable_embed_dims = OneShotMutableChannel( + num_channels=self.embed_dim_range[-1], + candidate_choices=self.embed_dim_range) + + # handle the mutable in multihead attention + self.base_embed_dims = OneShotMutableChannel( + num_channels=64, candidate_choices=[64]) + + self.mutable_num_heads = [ + OneShotMutableValue( + value_list=self.num_head_range, + default_value=self.num_head_range[-1]) + for _ in range(self.depth_range[-1]) + ] + self.mutable_mlp_ratios = [ + OneShotMutableValue( + value_list=self.mlp_ratio_range, + default_value=self.mlp_ratio_range[-1]) + for _ in range(self.depth_range[-1]) + ] + + self.mutable_q_embed_dims = [ + i * self.base_embed_dims for i in self.mutable_num_heads + ] + + # patch embeddings + self.patch_embed = DynamicPatchEmbed( + img_size=self.img_size, + in_channels=self.in_channels, + embed_dims=self.mutable_embed_dims.num_channels) + + # num of patches + self.patch_resolution = [ + img_size // patch_size, img_size // patch_size + ] + num_patches = self.patch_resolution[0] * self.patch_resolution[1] + + # cls token and pos embed + self.pos_embed = nn.Parameter( + torch.zeros(1, num_patches + 1, + self.mutable_embed_dims.num_channels)) + + self.cls_token = nn.Parameter( + torch.zeros(1, 1, self.mutable_embed_dims.num_channels)) + + self.drop_after_pos = nn.Dropout(p=drop_rate) + + # stochastic depth decay rule + self.dpr = np.linspace(0, drop_path_rate, + self.mutable_depth.max_choice) + + # main body + self.blocks = self._make_layer( + embed_dims=self.mutable_embed_dims.num_channels, + depth=self.mutable_depth.max_choice) + + # final norm + if self.use_final_norm: + self.norm1_name, norm1 = build_norm_layer( + norm_cfg, self.mutable_embed_dims.num_channels) + self.add_module(self.norm1_name, norm1) + + self.last_mutable = self.mutable_embed_dims + + self.register_mutables() + + @property + def norm1(self): + """The first normalization.""" + return getattr(self, self.norm1_name) + + def _make_layer(self, embed_dims, depth): + """Build multiple TransformerEncoderLayers.""" + layers = [] + for i in range(depth): + layer = TransformerEncoderLayer( + embed_dims=embed_dims, + num_heads=self.mutable_num_heads[i].max_choice, + mlp_ratio=self.mutable_mlp_ratios[i].max_choice, + proj_drop_rate=self.drop_rate, + out_drop_rate=self.dpr[i], + qkv_bias=self.qkv_bias, + act_cfg=self.act_cfg) + layers.append(layer) + return DynamicSequential(*layers) + + def register_mutables(self): + """Mutate the autoformer.""" + OneShotMutableChannelUnit._register_channel_container( + self, MutableChannelContainer) + + # handle the mutation of depth + self.blocks.register_mutable_attr('depth', self.mutable_depth) + + # handle the mutation of patch embed + MutableChannelContainer.register_mutable_channel_to_module( + self.patch_embed, self.mutable_embed_dims, True) + + # handle the dependencies of TransformerEncoderLayers + for i in range(self.mutable_depth.max_choice): # max depth here + layer = self.blocks[i] + layer.register_mutables( + mutable_num_heads=self.mutable_num_heads[i], + mutable_mlp_ratios=self.mutable_mlp_ratios[i], + mutable_q_embed_dims=self.mutable_q_embed_dims[i], + mutable_head_dims=self.base_embed_dims, + mutable_embed_dims=self.last_mutable) + + # handle the mutable of final norm + if self.use_final_norm: + MutableChannelContainer.register_mutable_channel_to_module( + self.norm1, self.last_mutable, True) + + def forward(self, x: torch.Tensor): + """Forward of Autoformer.""" + B = x.shape[0] + x = self.patch_embed(x) + + embed_dims = int(self.mutable_embed_dims.current_choice) if isinstance( + self.mutable_embed_dims, + BaseMutableChannel) else self.embed_dim_range[-1] + + # cls token + cls_tokens = self.cls_token[..., :embed_dims].expand(B, -1, -1) + x = torch.cat((cls_tokens, x), dim=1) + + # pos embed + x = x + self.pos_embed[..., :embed_dims] + x = self.drop_after_pos(x) + + # dynamic depth + x = self.blocks(x) + + if self.use_final_norm: + x = self.norm1(x) + + return (torch.mean(x[:, 1:], dim=1), ) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v2.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v2.py new file mode 100755 index 000000000..640dde29a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v2.py @@ -0,0 +1,229 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict, List, Optional, Sequence, Tuple, Union + +from mmcv.cnn import ConvModule +from mmengine.model import Sequential +from torch import Tensor +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.registry import MODELS + +try: + from mmcls.models.backbones.base_backbone import BaseBackbone + from mmcls.models.utils import make_divisible +except ImportError: + from mmrazor.utils import get_placeholder + BaseBackbone = get_placeholder('mmcls') + make_divisible = get_placeholder('mmcls') + + +@MODELS.register_module() +class SearchableMobileNetV2(BaseBackbone): + """Searchable MobileNetV2 backbone. + + Args: + arch_setting (list[list]): Architecture settings. + first_channels (int): Channel width of first ConvModule. Default: 32. + last_channels (int): Channel width of last ConvModule. Default: 1200. + widen_factor (float): Width multiplier, multiply number of + channels in each layer by this amount. Default: 1.0. + out_indices (Sequence[int]): Output from which stages. + Default: (7, ). + frozen_stages (int): Stages to be frozen (all param fixed). + Default: -1, which means not freezing any parameters. + conv_cfg (dict, optional): Config dict for convolution layer. + Default: None, which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN'). + act_cfg (dict): Config dict for activation layer. + Default: dict(type='ReLU6'). + norm_eval (bool): Whether to set norm layers to eval mode, namely, + freeze running stats (mean and var). Note: Effect on Batch Norm + and its variants only. Default: False. + with_cp (bool): Use checkpoint or not. Using checkpoint will save some + memory while slowing down the training speed. Default: False. + init_cfg (dict | list[dict], optional): initialization configuration + dict to define initializer. OpenMMLab has implemented + 6 initializers, including ``Constant``, ``Xavier``, ``Normal``, + ``Uniform``, ``Kaiming``, and ``Pretrained``. + + Excamples: + >>> mutable_cfg = dict( + ... type='OneShotMutableOP', + ... candidates=dict( + ... mb_k3e1=dict( + ... type='MBBlock', + ... kernel_size=3, + ... expand_ratio=1, + ... norm_cfg=dict(type='BN'), + ... act_cfg=dict(type='ReLU6')))) + >>> arch_setting = [ + ... # Parameters to build layers. 4 parameters are needed to + ... # construct a layer, from left to right: + ... # channel, num_blocks, stride, mutable cfg. + ... [16, 1, 1, mutable_cfg], + ... [24, 2, 2, mutable_cfg], + ... [32, 3, 2, mutable_cfg], + ... [64, 4, 2, mutable_cfg], + ... [96, 3, 1, mutable_cfg], + ... [160, 3, 2, mutable_cfg], + ... [320, 1, 1, mutable_cfg] + ... ] + >>> model = SearchableMobileNetV2(arch_setting=arch_setting) + """ + + def __init__( + self, + arch_setting: List[List], + first_channels: int = 32, + last_channels: int = 1280, + widen_factor: float = 1., + out_indices: Sequence[int] = (7, ), + frozen_stages: int = -1, + conv_cfg: Optional[Dict] = None, + norm_cfg: Dict = dict(type='BN'), + act_cfg: Dict = dict(type='ReLU6'), + norm_eval: bool = False, + with_cp: bool = False, + init_cfg: Optional[Union[Dict, List[Dict]]] = [ + dict(type='Kaiming', layer=['Conv2d']), + dict(type='Constant', val=1, layer=['_BatchNorm', 'GroupNorm']) + ] + ) -> None: + for index in out_indices: + if index not in range(8): + raise ValueError('the item in out_indices must in ' + f'range(0, 8). But received {index}') + + if frozen_stages not in range(-1, 8): + raise ValueError('frozen_stages must be in range(-1, 8). ' + f'But received {frozen_stages}') + + super().__init__(init_cfg) + + self.arch_setting = arch_setting + self.widen_factor = widen_factor + self.out_indices = out_indices + self.frozen_stages = frozen_stages + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.act_cfg = act_cfg + self.norm_eval = norm_eval + self.with_cp = with_cp + + self.in_channels = make_divisible(first_channels * widen_factor, 8) + + self.conv1 = ConvModule( + in_channels=3, + out_channels=self.in_channels, + kernel_size=3, + stride=2, + padding=1, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=self.act_cfg) + + self.layers = [] + + for i, layer_cfg in enumerate(arch_setting): + channel, num_blocks, stride, mutable_cfg = layer_cfg + out_channels = make_divisible(channel * widen_factor, 8) + inverted_res_layer = self._make_layer( + out_channels=out_channels, + num_blocks=num_blocks, + stride=stride, + mutable_cfg=copy.deepcopy(mutable_cfg)) + layer_name = f'layer{i + 1}' + self.add_module(layer_name, inverted_res_layer) + self.layers.append(layer_name) + + if widen_factor > 1.0: + self.out_channel = int(last_channels * widen_factor) + else: + self.out_channel = last_channels + + layer = ConvModule( + in_channels=self.in_channels, + out_channels=self.out_channel, + kernel_size=1, + stride=1, + padding=0, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=self.act_cfg) + + self.add_module('conv2', layer) + self.layers.append('conv2') + + def _make_layer(self, out_channels: int, num_blocks: int, stride: int, + mutable_cfg: Dict) -> Sequential: + """Stack mutable blocks to build a layer for SearchableMobileNetV2. + + Note: + Here we use ``module_kwargs`` to pass dynamic parameters such as + ``in_channels``, ``out_channels`` and ``stride`` + to build the mutable. + + Args: + out_channels (int): out_channels of block. + num_blocks (int): number of blocks. + stride (int): stride of the first block. + mutable_cfg (dict): Config of mutable. + + Returns: + mmengine.model.Sequential: The layer made. + """ + layers = [] + for i in range(num_blocks): + if i >= 1: + stride = 1 + + mutable_cfg.update( + module_kwargs=dict( + in_channels=self.in_channels, + out_channels=out_channels, + stride=stride)) + layers.append(MODELS.build(mutable_cfg)) + + self.in_channels = out_channels + + return Sequential(*layers) + + def forward(self, x: Tensor) -> Tuple[Tensor, ...]: + """Forward computation. + + Args: + x (tensor): x contains input data for forward computation. + """ + x = self.conv1(x) + + outs = [] + for i, layer_name in enumerate(self.layers): + layer = getattr(self, layer_name) + x = layer(x) + if i in self.out_indices: + outs.append(x) + + return tuple(outs) + + def _freeze_stages(self) -> None: + """Freeze params not to update in the specified stages.""" + if self.frozen_stages >= 0: + for param in self.conv1.parameters(): + param.requires_grad = False + for i in range(1, self.frozen_stages + 1): + layer = getattr(self, f'layer{i}') + layer.eval() + for param in layer.parameters(): + param.requires_grad = False + + def train(self, mode: bool = True) -> None: + """Set module status before forward computation.""" + super().train(mode) + + self._freeze_stages() + if mode and self.norm_eval: + for m in self.modules(): + if isinstance(m, _BatchNorm): + m.eval() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v3.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v3.py new file mode 100755 index 000000000..b5fe373d7 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v3.py @@ -0,0 +1,366 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from collections import OrderedDict +from typing import Dict, List, Optional, Sequence, Union + +import torch.nn as nn +from mmcv.cnn import ConvModule +from mmengine.logging import MMLogger +from mmengine.model import Sequential, constant_init +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.models.architectures.dynamic_ops.bricks import DynamicSequential +from mmrazor.models.architectures.ops.mobilenet_series import MBBlock +from mmrazor.models.architectures.utils.mutable_register import ( + mutate_conv_module, mutate_mobilenet_layer) +from mmrazor.models.mutables import (MutableChannelContainer, + OneShotMutableChannel, + OneShotMutableChannelUnit, + OneShotMutableValue) +from mmrazor.models.utils.parse_values import parse_values +from mmrazor.registry import MODELS + +try: + from mmcls.models.backbones.base_backbone import BaseBackbone + from mmcls.models.utils import make_divisible +except ImportError: + from mmrazor.utils import get_placeholder + BaseBackbone = get_placeholder('mmcls') + make_divisible = get_placeholder('mmcls') + +logger = MMLogger.get_current_instance() + + +@MODELS.register_module() +class AttentiveMobileNetV3(BaseBackbone): + """Searchable MobileNetV3 backbone. + + Args: + arch_setting (Dict[str, List]): Architecture settings. + widen_factor (float): Width multiplier, multiply number of + channels in each layer by this amount. Defaults to 1.0. + out_indices (Sequence[int]): Output from which stages. + Defaults to (7, ). + frozen_stages (int): Stages to be frozen (all param fixed). + Defaults to -1, which means not freezing any parameters. + conv_cfg (dict, optional): Config dict for convolution layer. + Defaults to None, which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Defaults to dict(type='BN'). + act_cfg_list (List): Config dict for activation layer. + Defaults to None. + stride_list (list): stride setting in each stage. + Defaults to None. + with_se_list (list): Whether to use se-layer in each stage. + Defaults to None. + norm_eval (bool): Whether to set norm layers to eval mode, namely, + freeze running stats (mean and var). Note: Effect on Batch Norm + and its variants only. Defaults to False. + with_cp (bool): Use checkpoint or not. Using checkpoint will save some + memory while slowing down the training speed. Defaults to False. + zero_init_residual (bool): Zero norm param in linear conv of MBBlock + or not when there is a shortcut. Defaults to True. + fine_grained_mode (bool): Whether to use fine-grained mode (search + kernel size & expand ratio for each MB block in each layers). + Defaults to False. + with_attentive_shortcut (bool): Use shortcut in AttentiveNAS or not. + Defaults to True. + init_cfg (dict | list[dict], optional): initialization configuration + dict to define initializer. OpenMMLab has implemented + 6 initializers, including ``Constant``, ``Xavier``, ``Normal``, + ``Uniform``, ``Kaiming``, and ``Pretrained``. + """ + + def __init__(self, + arch_setting: Dict[str, List], + widen_factor: float = 1., + out_indices: Sequence[int] = (7, ), + frozen_stages: int = -1, + conv_cfg: Dict = dict(type='BigNasConv2d'), + norm_cfg: Dict = dict(type='DynamicBatchNorm2d'), + act_cfg_list: List = None, + stride_list: List = None, + with_se_list: List = None, + norm_eval: bool = False, + with_cp: bool = False, + zero_init_residual: bool = True, + fine_grained_mode: bool = False, + with_attentive_shortcut: bool = True, + init_cfg: Optional[Union[Dict, List[Dict]]] = None): + + super().__init__(init_cfg) + + self.arch_setting = arch_setting + self.widen_factor = widen_factor + self.out_indices = out_indices + for index in out_indices: + if index not in range(0, 8): + raise ValueError('the item in out_indices must in ' + f'range(0, 8). But received {index}') + if frozen_stages not in range(-1, 8): + raise ValueError('frozen_stages must in range(-1, 8). ' + f'But received {frozen_stages}') + self.out_indices = out_indices + self.frozen_stages = frozen_stages + + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.norm_eval = norm_eval + self.zero_init_residual = zero_init_residual + self.with_cp = with_cp + self.fine_grained_mode = fine_grained_mode + self.with_attentive_shortcut = with_attentive_shortcut + + self.act_cfg_list = act_cfg_list if act_cfg_list \ + else ['Swish'] * 9 + self.stride_list = stride_list if stride_list \ + else [1, 2, 2, 2, 1, 2, 1] + self.with_se_list = with_se_list if with_se_list \ + else [False, False, True, False, True, True, True] + + # adapt mutable settings + self.kernel_size_list = parse_values(self.arch_setting['kernel_size']) + self.num_blocks_list = parse_values(self.arch_setting['num_blocks']) + self.expand_ratio_list = \ + parse_values(self.arch_setting['expand_ratio']) + self.num_channels_list = \ + parse_values(self.arch_setting['num_out_channels']) + + self.num_channels_list = [[ + make_divisible(c * widen_factor, 8) for c in channels + ] for channels in self.num_channels_list] + + self.first_act = self.act_cfg_list.pop(0) + self.last_act = self.act_cfg_list.pop(-1) + + self.first_out_channels_list = self.num_channels_list.pop(0) + self.last_out_channels_list = self.num_channels_list.pop(-1) + self.last_expand_ratio_list = self.expand_ratio_list.pop(-1) + assert len(self.kernel_size_list) == len(self.num_blocks_list) == \ + len(self.expand_ratio_list) == len(self.num_channels_list) + + self.layers = self._make_layer() + + self.register_mutables() + + def _make_layer(self): + """Build multiple mobilenet layers.""" + layers = [] + self.in_channels = max(self.first_out_channels_list) + + self.first_conv = ConvModule( + in_channels=3, + out_channels=self.in_channels, + kernel_size=3, + stride=2, + padding=1, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=dict(type=self.first_act)) + + for i, (num_blocks, kernel_sizes, expand_ratios, num_channels) in \ + enumerate(zip(self.num_blocks_list, self.kernel_size_list, + self.expand_ratio_list, self.num_channels_list)): + inverted_res_layer = self._make_single_layer( + out_channels=num_channels, + num_blocks=num_blocks, + kernel_sizes=kernel_sizes, + expand_ratios=expand_ratios, + stride=self.stride_list[i], + use_se=self.with_se_list[i], + act=self.act_cfg_list[i]) + layer_name = f'layer{i + 1}' + self.add_module(layer_name, inverted_res_layer) + layers.append(inverted_res_layer) + + last_expand_channels = \ + self.in_channels * max(self.last_expand_ratio_list) + self.out_channels = max(self.last_out_channels_list) + last_layers = Sequential( + OrderedDict([('final_expand_layer', + ConvModule( + in_channels=self.in_channels, + out_channels=last_expand_channels, + kernel_size=1, + padding=0, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=dict(type=self.last_act))), + ('pool', nn.AdaptiveAvgPool2d((1, 1))), + ('feature_mix_layer', + ConvModule( + in_channels=last_expand_channels, + out_channels=self.out_channels, + kernel_size=1, + padding=0, + bias=False, + conv_cfg=self.conv_cfg, + norm_cfg=None, + act_cfg=dict(type=self.last_act)))])) + self.add_module('last_conv', last_layers) + layers.append(last_layers) + return layers + + def _make_single_layer(self, out_channels: List, num_blocks: List, + kernel_sizes: List, expand_ratios: List, + stride: int, act: str, use_se: bool): + """Stack InvertedResidual blocks (MBBlocks) to build a layer for + MobileNetV3. + + Args: + out_channels (List): out_channels of block. + num_blocks (List): num of blocks. + kernel_sizes (List): num of kernel sizes. + expand_ratios (int): Expand the number of channels of the + hidden layer in InvertedResidual by this ratio. + stride (int): stride of the first block. + use_se (bool): Use SE layer in MBBlock or not. + """ + _layers = [] + for i in range(max(num_blocks)): + if i >= 1: + stride = 1 + if use_se: + se_cfg = dict( + act_cfg=(dict(type='ReLU'), dict(type='HSigmoid')), + ratio=4, + conv_cfg=self.conv_cfg) + else: + se_cfg = None # type: ignore + + mb_layer = MBBlock( + in_channels=self.in_channels, + out_channels=max(out_channels), + kernel_size=max(kernel_sizes), + stride=stride, + expand_ratio=max(expand_ratios), + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=dict(type=act), + with_cp=self.with_cp, + se_cfg=se_cfg, + with_attentive_shortcut=self.with_attentive_shortcut) + + _layers.append(mb_layer) + self.in_channels = max(out_channels) + + dynamic_seq = DynamicSequential(*_layers) + return dynamic_seq + + def register_mutables(self): + """Mutate the BigNAS-style MobileNetV3.""" + OneShotMutableChannelUnit._register_channel_container( + self, MutableChannelContainer) + + self.first_mutable_channels = OneShotMutableChannel( + alias='backbone.first_channels', + num_channels=max(self.first_out_channels_list), + candidate_choices=self.first_out_channels_list) + + mutate_conv_module( + self.first_conv, mutable_out_channels=self.first_mutable_channels) + + mid_mutable = self.first_mutable_channels + # mutate the built mobilenet layers + for i, layer in enumerate(self.layers[:-1]): + num_blocks = self.num_blocks_list[i] + kernel_sizes = self.kernel_size_list[i] + expand_ratios = self.expand_ratio_list[i] + out_channels = self.num_channels_list[i] + + prefix = 'backbone.layers.' + str(i + 1) + '.' + + mutable_out_channels = OneShotMutableChannel( + alias=prefix + 'out_channels', + candidate_choices=out_channels, + num_channels=max(out_channels)) + + if not self.fine_grained_mode: + mutable_kernel_size = OneShotMutableValue( + alias=prefix + 'kernel_size', value_list=kernel_sizes) + + mutable_expand_ratio = OneShotMutableValue( + alias=prefix + 'expand_ratio', value_list=expand_ratios) + + mutable_depth = OneShotMutableValue( + alias=prefix + 'depth', value_list=num_blocks) + layer.register_mutable_attr('depth', mutable_depth) + + for k in range(max(self.num_blocks_list[i])): + + if self.fine_grained_mode: + mutable_kernel_size = OneShotMutableValue( + alias=prefix + str(k) + '.kernel_size', + value_list=kernel_sizes) + + mutable_expand_ratio = OneShotMutableValue( + alias=prefix + str(k) + '.expand_ratio', + value_list=expand_ratios) + + mutate_mobilenet_layer(layer[k], mid_mutable, + mutable_out_channels, + mutable_expand_ratio, + mutable_kernel_size, + self.fine_grained_mode) + mid_mutable = mutable_out_channels + + self.last_mutable_channels = OneShotMutableChannel( + alias='backbone.last_channels', + num_channels=self.out_channels, + candidate_choices=self.last_out_channels_list) + + last_mutable_expand_value = OneShotMutableValue( + value_list=self.last_expand_ratio_list, + default_value=max(self.last_expand_ratio_list)) + + derived_expand_channels = mid_mutable * last_mutable_expand_value + mutate_conv_module( + self.layers[-1].final_expand_layer, + mutable_in_channels=mid_mutable, + mutable_out_channels=derived_expand_channels) + mutate_conv_module( + self.layers[-1].feature_mix_layer, + mutable_in_channels=derived_expand_channels, + mutable_out_channels=self.last_mutable_channels) + + def forward(self, x): + x = self.first_conv(x) + outs = [] + for i, layer in enumerate(self.layers): + x = layer(x) + if i in self.out_indices: + outs.append(x) + + return tuple(outs) + + def train(self, mode=True): + super().train(mode) + self._freeze_stages() + if mode and self.norm_eval: + for m in self.modules(): + if isinstance(m, _BatchNorm): + m.eval() + + def init_weights(self) -> None: + super().init_weights() + + if self.zero_init_residual: + for name, module in self.named_modules(): + if isinstance(module, MBBlock): + if module.with_res_shortcut or \ + module.with_attentive_shortcut: + norm_layer = module.linear_conv.norm + constant_init(norm_layer, val=0) + logger.debug( + f'init {type(norm_layer)} of linear_conv in ' + f'`{name}` to zero') + + def _freeze_stages(self): + if self.frozen_stages >= 0: + for param in self.first_conv.parameters(): + param.requires_grad = False + + for i in range(1, self.frozen_stages + 1): + layer = getattr(self, f'layer{i}') + layer.eval() + for param in layer.parameters(): + param.requires_grad = False diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_shufflenet_v2.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_shufflenet_v2.py new file mode 100755 index 000000000..db9e300a4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_shufflenet_v2.py @@ -0,0 +1,225 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict, List, Optional, Sequence, Tuple, Union + +import torch.nn as nn +from mmcv.cnn import ConvModule +from mmengine.model import ModuleList, Sequential +from mmengine.model.weight_init import constant_init, normal_init +from torch import Tensor +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.registry import MODELS + +try: + from mmcls.models.backbones.base_backbone import BaseBackbone +except ImportError: + from mmrazor.utils import get_placeholder + BaseBackbone = get_placeholder('mmcls') + + +@MODELS.register_module() +class SearchableShuffleNetV2(BaseBackbone): + """Based on ShuffleNetV2 backbone. + + Args: + arch_setting (list[list]): Architecture settings. + stem_multiplier (int): Stem multiplier - adjusts the number of + channels in the first layer. Default: 1. + widen_factor (float): Width multiplier - adjusts the number of + channels in each layer by this amount. Default: 1.0. + out_indices (Sequence[int]): Output from which stages. + Default: (4, ). + frozen_stages (int): Stages to be frozen (all param fixed). + Default: -1, which means not freezing any parameters. + with_last_layer (bool): Whether is last layer. + Default: True, which means not need to add `Placeholder``. + conv_cfg (dict, optional): Config dict for convolution layer. + Default: None, which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN'). + act_cfg (dict): Config dict for activation layer. + Default: dict(type='ReLU'). + norm_eval (bool): Whether to set norm layers to eval mode, namely, + freeze running stats (mean and var). Note: Effect on Batch Norm + and its variants only. Default: False. + with_cp (bool): Use checkpoint or not. Using checkpoint will save some + memory while slowing down the training speed. Default: False. + init_cfg (dict | list[dict], optional): initialization configuration + dict to define initializer. OpenMMLab has implemented + 6 initializers, including ``Constant``, ``Xavier``, ``Normal``, + ``Uniform``, ``Kaiming``, and ``Pretrained``. + + Examples: + >>> mutable_cfg = dict( + ... type='OneShotMutableOP', + ... candidates=dict( + ... shuffle_3x3=dict( + ... type='ShuffleBlock', + ... kernel_size=3, + ... norm_cfg=dict(type='BN')))) + >>> arch_setting = [ + ... # Parameters to build layers. 3 parameters are needed to + ... # construct a layer, from left to right: + ... # channel, num_blocks, mutable cfg. + ... [64, 4, mutable_cfg], + ... [160, 4, mutable_cfg], + ... [320, 8, mutable_cfg], + ... [640, 4, mutable_cfg] + ... ] + >>> model = SearchableShuffleNetV2(arch_setting=arch_setting) + """ + + def __init__(self, + arch_setting: List[List], + stem_multiplier: int = 1, + widen_factor: float = 1.0, + out_indices: Sequence[int] = (4, ), + frozen_stages: int = -1, + with_last_layer: bool = True, + conv_cfg: Optional[Dict] = None, + norm_cfg: Dict = dict(type='BN'), + act_cfg: Dict = dict(type='ReLU'), + norm_eval: bool = False, + with_cp: bool = False, + init_cfg: Optional[Union[Dict, List[Dict]]] = None) -> None: + layers_nums = 5 if with_last_layer else 4 + for index in out_indices: + if index not in range(0, layers_nums): + raise ValueError('the item in out_indices must in ' + f'range(0, 5). But received {index}') + + self.frozen_stages = frozen_stages + if frozen_stages not in range(-1, layers_nums): + raise ValueError('frozen_stages must be in range(-1, 5). ' + f'But received {frozen_stages}') + + super().__init__(init_cfg) + + self.arch_setting = arch_setting + self.widen_factor = widen_factor + self.out_indices = out_indices + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.act_cfg = act_cfg + self.norm_eval = norm_eval + self.with_cp = with_cp + + last_channels = 1024 + self.in_channels = 16 * stem_multiplier + self.conv1 = ConvModule( + in_channels=3, + out_channels=self.in_channels, + kernel_size=3, + stride=2, + padding=1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + + self.layers = ModuleList() + for channel, num_blocks, mutable_cfg in arch_setting: + out_channels = round(channel * widen_factor) + layer = self._make_layer(out_channels, num_blocks, + copy.deepcopy(mutable_cfg)) + self.layers.append(layer) + + if with_last_layer: + self.layers.append( + ConvModule( + in_channels=self.in_channels, + out_channels=last_channels, + kernel_size=1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg)) + + def _make_layer(self, out_channels: int, num_blocks: int, + mutable_cfg: Dict) -> Sequential: + """Stack mutable blocks to build a layer for ShuffleNet V2. + + Note: + Here we use ``module_kwargs`` to pass dynamic parameters such as + ``in_channels``, ``out_channels`` and ``stride`` + to build the mutable. + + Args: + out_channels (int): out_channels of the block. + num_blocks (int): number of blocks. + mutable_cfg (dict): Config of mutable. + + Returns: + mmengine.model.Sequential: The layer made. + """ + layers = [] + for i in range(num_blocks): + stride = 2 if i == 0 else 1 + + mutable_cfg.update( + module_kwargs=dict( + in_channels=self.in_channels, + out_channels=out_channels, + stride=stride)) + layers.append(MODELS.build(mutable_cfg)) + self.in_channels = out_channels + + return Sequential(*layers) + + def _freeze_stages(self) -> None: + """Freeze params not to update in the specified stages.""" + if self.frozen_stages >= 0: + for param in self.conv1.parameters(): + param.requires_grad = False + + for i in range(self.frozen_stages): + m = self.layers[i] + m.eval() + for param in m.parameters(): + param.requires_grad = False + + def init_weights(self) -> None: + """Init weights of ``SearchableShuffleNetV2``.""" + super().init_weights() + + if (isinstance(self.init_cfg, dict) + and self.init_cfg['type'] == 'Pretrained'): + # Suppress default init if use pretrained model. + return + + for name, m in self.named_modules(): + if isinstance(m, nn.Conv2d): + if 'conv1' in name: + normal_init(m, mean=0, std=0.01) + else: + normal_init(m, mean=0, std=1.0 / m.weight.shape[1]) + elif isinstance(m, (_BatchNorm, nn.GroupNorm)): + constant_init(m, val=1, bias=0.0001) + if isinstance(m, _BatchNorm): + if m.running_mean is not None: + nn.init.constant_(m.running_mean, 0) + + def forward(self, x: Tensor) -> Tuple[Tensor, ...]: + """Forward computation. + + Args: + x (tensor): x contains input data for forward computation. + """ + x = self.conv1(x) + + outs = [] + for i, layer in enumerate(self.layers): + x = layer(x) + if i in self.out_indices: + outs.append(x) + + return tuple(outs) + + def train(self, mode: bool = True) -> None: + """Set module status before forward computation.""" + super().train(mode) + + self._freeze_stages() + if mode and self.norm_eval: + for m in self.modules(): + if isinstance(m, _BatchNorm): + m.eval() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/wideresnet.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/wideresnet.py new file mode 100755 index 000000000..5350d8f7b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/wideresnet.py @@ -0,0 +1,403 @@ +# Copyright (c) OpenMMLab. All rights reserved. +# This file is modified from `mmcls.models.backbones.resnet` + +import warnings +from typing import Dict, Tuple + +import torch +import torch.nn as nn +import torch.nn.functional as F +from mmcv.cnn import build_conv_layer, build_norm_layer +from mmengine.model import BaseModule +from mmengine.model.weight_init import constant_init + +from mmrazor.registry import MODELS + + +class BasicBlock(nn.Module): + """BasicBlock for WideResNet. The differences from ResNet are in: + 1. The forward path + 2. The position of residual path + 3. Different downsample + + Args: + in_channels (int): Input channels of this block. + out_channels (int): Output channels of this block. + expansion (int): The ratio of ``out_channels/mid_channels`` where + ``mid_channels`` is the output channels of conv1. This is a + reserved argument in BasicBlock and should always be 1. Default: 1. + stride (int): stride of the block. Default: 1 + stride (int): stride of the block. Default: 1 + dilation (int): dilation of convolution. Default: 1 + downsample (nn.Module, optional): downsample operation on identity + branch. Default: None. + droprate (float, optional): droprate of the block. Defaults to 0. + conv_cfg (dict, optional): dictionary to construct and config conv + layer. Default: None + norm_cfg (dict): dictionary to construct and config norm layer. + Default: dict(type='BN') + """ + + def __init__( + self, + in_channels: int, + out_channels: int, + expansion: int = 1, + stride: int = 1, + dilation: int = 1, + downsample: nn.Module = None, + droprate: float = 0, + conv_cfg: Dict = None, + norm_cfg: Dict = dict(type='BN') + ) -> None: # noqa: E125 + super(BasicBlock, self).__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.expansion = expansion + self.stride = stride + self.dilation = dilation + self.droprate = droprate + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + + self.norm1_name, norm1 = build_norm_layer( + norm_cfg, in_channels, postfix=1) + self.norm2_name, norm2 = build_norm_layer( + norm_cfg, out_channels, postfix=2) + + self.add_module(self.norm1_name, norm1) + self.relu1 = nn.ReLU(inplace=True) + self.conv1 = build_conv_layer( + conv_cfg, + in_channels, + out_channels, + 3, + stride=stride, + padding=dilation, + dilation=dilation, + bias=False) + + self.add_module(self.norm2_name, norm2) + self.relu2 = nn.ReLU(inplace=True) + self.conv2 = build_conv_layer( + conv_cfg, + out_channels, + out_channels, + kernel_size=3, + stride=1, + padding=1, + bias=False) + self.downsample = downsample + + @property + def norm1(self): + return getattr(self, self.norm1_name) + + @property + def norm2(self): + return getattr(self, self.norm2_name) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + """forward func. + + Args: + x (torch.Tensor): input. + + Returns: + torch.Tensor: output. + """ + + identity = self.relu1(self.bn1(x)) + out = self.conv1(identity) + out = self.bn2(out) + out = self.relu2(out) + if self.droprate > 0: + out = F.dropout(out, p=self.droprate, training=self.training) + out = self.conv2(out) + if self.downsample: + out += self.downsample(identity) + else: + out += x + return out + + +def get_expansion(block: nn.Module, + widen_factor: int, + expansion: int = None) -> int: + """Get the expansion of a residual block. + The block expansion will be obtained by the following order: + 1. If ``expansion`` is given, just return it. + 2. If ``block`` has the attribute ``expansion``, then return + ``block.expansion``. + 3. If ``block`` is ``BaseBlock``, then return ``widen_factor``. + 3. Return the default value according the the block type: + 4 for ``Bottleneck``. + + Args: + block (class): The block class. + widen_factor (int): The given widen factor. + expansion (int | None): The given expansion ratio. + Returns: + int: The expansion of the block. + """ + if isinstance(expansion, int): + assert expansion > 0 + elif expansion is None: + if hasattr(block, 'expansion'): + expansion = block.expansion + elif issubclass(block, BasicBlock): + expansion = widen_factor + else: + raise TypeError(f'expansion is not specified for {block.__name__}') + else: + raise TypeError('expansion must be an integer or None') + + return expansion + + +class ResLayer(nn.Sequential): + """ResLayer to build ResNet style backbone. + + Args: + block (nn.Module): Residual block used to build ResLayer. + num_blocks (int): Number of blocks. + in_channels (int): Input channels of this block. + out_channels (int): Output channels of this block. + expansion (int): The expansion for BasicBlock/Bottleneck. + If not specified, it will firstly be obtained via + ``block.expansion``. If the block has no attribute "expansion", + the following default values will be used: 1 for BasicBlock and + 4 for Bottleneck. + droprate (float, optional): droprate of the layer. Defaults to 0. + stride (int): stride of the first block. Default: 1. + conv_cfg (Dict, optional): dictionary to construct and config conv + layer. Default: None + norm_cfg (Dict): dictionary to construct and config norm layer. + Default: dict(type='BN') + """ + + def __init__(self, + block: nn.Module, + num_blocks: int, + in_channels: int, + out_channels: int, + expansion: int, + droprate: float = 0, + stride: int = 1, + conv_cfg: Dict = None, + norm_cfg: Dict = dict(type='BN'), + **kwargs): + self.block = block + self.droprate = droprate + self.expansion = expansion + + downsample = None + if stride != 1 or in_channels != out_channels: + downsample = build_conv_layer( + conv_cfg, + in_channels, + out_channels, + kernel_size=1, + stride=stride, + bias=False) + + layers = [] + layers.append( + block( + in_channels=in_channels, + out_channels=out_channels, + expansion=self.expansion, + stride=stride, + downsample=downsample, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + **kwargs)) + in_channels = out_channels + for _ in range(1, num_blocks): + layers.append( + block( + in_channels=in_channels, + out_channels=out_channels, + expansion=self.expansion, + stride=1, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + **kwargs)) + super(ResLayer, self).__init__(*layers) + + +@MODELS.register_module() +class WideResNet(BaseModule): + """WideResNet backbone. Only support 3-stage WideResNet, which is usually + for tiny images. E.g., CIFAR10 and CIFAR100. + + WRN50 and WRN101 are now officially supported in + MMClassification. See link below: + https://github.com/open-mmlab/mmclassification/pull/715 + + Please refer to the `paper `__ for + details. + + Args: + depth (int): Network depth, from {10, 16, 22, 28, 40, 50, 101, 152}. + widen_factor (int): Width multiplier of mid-channel in blocks. + in_channels (int): Number of input image channels. Default: 3. + stem_channels (int): Output channels of the stem layer. Default: 64. + base_channels (int): Middle channels of the first stage. Default: 64. + num_stages (int): Stages of the network. Default: 4. + strides (Sequence[int]): Strides of the first block of each stage. + Default: ``(1, 2, 2, 2)``. + dilations (Sequence[int]): Dilation of each stage. + Default: ``(1, 1, 1, 1)``. + frozen_stages (int): Stages to be frozen (stop grad and set eval mode). + -1 means not freezing any parameters. Default: -1. + conv_cfg (dict | None): The config dict for conv layers. Default: None. + norm_cfg (dict): The config dict for norm layers. + norm_eval (bool): Whether to set norm layers to eval mode, namely, + freeze running stats (mean and var). Note: Effect on Batch Norm + and its variants only. Default: False. + zero_init_residual (bool): Whether to use zero init for last norm layer + in resblocks to let them behave as identity. Default: True. + """ + arch_setting = { + 10: (BasicBlock, (1, 1, 1)), + 16: (BasicBlock, (2, 2, 2)), + 22: (BasicBlock, (3, 3, 3)), + 28: (BasicBlock, (4, 4, 4)), + 40: (BasicBlock, (6, 6, 6)), + } + + def __init__(self, + depth: int, + widen_factor: int = 4, + in_channels: int = 3, + stem_channels: int = 16, + base_channels: int = 16, + expansion: int = None, + num_stages: int = 3, + strides: Tuple[int, ...] = (1, 2, 2), + dilations: Tuple[int, ...] = (1, 1, 1), + frozen_stages: int = -1, + conv_cfg: Dict = None, + norm_cfg: Dict = dict(type='BN', requires_grad=True), + norm_eval: bool = False, + zero_init_residual: bool = False, + init_cfg=[ + dict(type='Kaiming', layer=['Conv2d']), + dict( + type='Constant', + val=1, + layer=['_BatchNorm', 'GroupNorm']) + ]): + super(WideResNet, self).__init__(init_cfg) + if depth > 40: + """MMClassication now supports WRN-50 and 101 officially. + + Refer to: + https://github.com/open-mmlab/mmclassification/pull/715/files + """ + warnings.warn('`WiderResNet` deep than 40 now is deprecated') + if depth not in self.arch_setting: + raise KeyError(f'invalid depth {depth} for WideResNet') + self.depth = depth + self.widen_factor = widen_factor + self.stem_channels = stem_channels + self.base_channels = base_channels + self.num_stages = num_stages + self.strides = strides + self.dilations = dilations + self.frozen_stages = frozen_stages + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.norm_eval = norm_eval + self.zero_init_residual = zero_init_residual + self.block, stage_blocks = self.arch_setting[depth] + self.stage_blocks = stage_blocks[:num_stages] + self.expansion = get_expansion(self.block, widen_factor, expansion) + + self._make_stem_layer(in_channels, stem_channels) + + self.res_layers = [] + _in_channels = stem_channels + _out_channels = base_channels * self.expansion + for i, num_blocks in enumerate(self.stage_blocks): + stride = strides[i] + dilation = dilations[i] + res_layer = self.make_res_layer( + block=self.block, + num_blocks=num_blocks, + in_channels=_in_channels, + out_channels=_out_channels, + expansion=self.expansion, + stride=stride, + dilation=dilation, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + ) + _in_channels = _out_channels + _out_channels *= 2 + layer_name = f'layer{i + 1}' + self.add_module(layer_name, res_layer) + self.res_layers.append(layer_name) + + self._freeze_stages() + + self.feat_dim = res_layer[-1].out_channels + + self.norm1_name, norm1 = build_norm_layer( + self.norm_cfg, _out_channels // 2, postfix=1) + self.add_module(self.norm1_name, norm1) + self.relu = nn.ReLU(inplace=True) + + @property + def norm1(self): + return getattr(self, self.norm1_name) + + def make_res_layer(self, **kwargs): + return ResLayer(**kwargs) + + def _make_stem_layer(self, in_channels, base_channels): + self.conv1 = build_conv_layer( + self.conv_cfg, + in_channels, + base_channels, + kernel_size=3, + stride=1, + padding=1, + bias=False) + + def _freeze_stages(self): + if self.frozen_stages >= 0: + self.norm1.eval() + for m in [self.conv1, self.norm1]: + for param in m.parameters(): + param.requires_grad = False + + for i in range(1, self.frozen_stages + 1): + m = getattr(self, f'layer{i}') + m.eval() + for param in m.parameters(): + param.requires_grad = False + + def init_weights(self): + super(WideResNet, self).init_weights() + + if (isinstance(self.init_cfg, dict) + and self.init_cfg['type'] == 'Pretrained'): + # Suppress zero_init_residual if use pretrained model. + return + + if self.zero_init_residual: + for m in self.modules(): + if isinstance(m, BasicBlock): + constant_init(m.norm2, 0) + + def forward(self, x): + # TODO: return multi-stage features. + x = self.conv1(x) + for layer_name in self.res_layers: + res_layer = getattr(self, layer_name) + x = res_layer(x) + x = self.norm1(x) + x = self.relu(x) + return tuple([x]) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/__init__.py new file mode 100755 index 000000000..6bbd245ff --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .image import SearchableImageClassifier + +__all__ = ['SearchableImageClassifier'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/image.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/image.py new file mode 100755 index 000000000..016d40e7a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/image.py @@ -0,0 +1,104 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional + +try: + from mmcls.models import ImageClassifier +except ImportError: + from mmrazor.utils import get_placeholder + ImageClassifier = get_placeholder('mmcls') +from torch import Tensor + +from mmrazor.models.architectures.dynamic_ops import DynamicInputResizer +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class SearchableImageClassifier(ImageClassifier): + """SearchableImageClassifier for sliceable networks. + + Args: + backbone (dict): The same as ImageClassifier. + neck (dict, optional): The same as ImageClassifier. Defaults to None. + head (dict, optional): The same as ImageClassifier. Defaults to None. + pretrained (dict, optional): The same as ImageClassifier. Defaults to + None. + train_cfg (dict, optional): The same as ImageClassifier. Defaults to + None. + data_preprocessor (dict, optional): The same as ImageClassifier. + Defaults to None. + init_cfg (dict, optional): The same as ImageClassifier. Defaults to + None. + input_resizer_cfg (dict, optional): Configs for a input resizer, which + is designed for dynamically changing the input size, making the + input size as a searchable part. Defaults to None. + connect_head (dict, optional): Dimensions are aligned in head will be + substitute to it's `str type` value, so that search_space of the + first components can be connets to the next. e.g: + {'connect_with_backbone': 'backbone.last_mutable'} means that + func:`connect_with_backbone` will be substitute to backbones + last_mutable. Defaults to None. + """ + + def __init__(self, + backbone: dict, + neck: Optional[dict] = None, + head: Optional[dict] = None, + pretrained: Optional[str] = None, + train_cfg: Optional[dict] = None, + data_preprocessor: Optional[dict] = None, + init_cfg: Optional[dict] = None, + input_resizer_cfg: Optional[dict] = None, + connect_head: Optional[dict] = None): + super().__init__(backbone, neck, head, pretrained, train_cfg, + data_preprocessor, init_cfg) + + if self.with_head and connect_head is not None: + for kh, vh in connect_head.items(): + component, attr = vh.split('.') + value = getattr(getattr(self, component), attr) + getattr(self.head, kh)(value) + + if input_resizer_cfg is not None: + input_resizer: Optional[DynamicInputResizer] = \ + self._build_input_resizer(input_resizer_cfg) + else: + input_resizer = None + self.input_resizer = input_resizer + + def extract_feat(self, + batch_inputs: Tensor, + stage: str = 'neck', + input_resizer: bool = True) -> Tensor: + """Extract features with resizing inputs first.""" + if self.input_resizer is not None and input_resizer: + batch_inputs = self.input_resizer(batch_inputs) + + return super().extract_feat(batch_inputs, stage) + + def _build_input_resizer(self, + input_resizer_cfg: Dict) -> DynamicInputResizer: + """Build a input resizer.""" + mutable_shape_cfg = dict(type='OneShotMutableValue') + + mutable_shape_cfg['alias'] = \ + input_resizer_cfg.get('alias', 'input_shape') + + assert 'input_sizes' in input_resizer_cfg and \ + isinstance(input_resizer_cfg['input_sizes'][0], list), ( + 'input_resizer_cfg[`input_sizes`] should be List[list].') + mutable_shape_cfg['value_list'] = \ + input_resizer_cfg.get('input_sizes') # type: ignore + + mutable_shape = MODELS.build(mutable_shape_cfg) + + input_resizer = MODELS.build(dict(type='DynamicInputResizer')) + input_resizer.register_mutable_attr('shape', mutable_shape) + + return input_resizer + + def simple_test(self, img, img_metas=None, **kwargs): + """Test without augmentation.""" + x = self.extract_feat(img, input_resizer=False) + res = self.head.simple_test(x, **kwargs) + + return res diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/__init__.py new file mode 100755 index 000000000..fd4c91e77 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/__init__.py @@ -0,0 +1,17 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .byot_connector import BYOTConnector +from .convmodule_connector import ConvModuleConnector +from .crd_connector import CRDConnector +from .factor_transfer_connectors import Paraphraser, Translator +from .fbkd_connector import FBKDStudentConnector, FBKDTeacherConnector +from .mgd_connector import MGDConnector +from .norm_connector import NormConnector +from .ofd_connector import OFDTeacherConnector +from .torch_connector import TorchFunctionalConnector, TorchNNConnector + +__all__ = [ + 'ConvModuleConnector', 'Translator', 'Paraphraser', 'BYOTConnector', + 'FBKDTeacherConnector', 'FBKDStudentConnector', 'TorchFunctionalConnector', + 'CRDConnector', 'TorchNNConnector', 'OFDTeacherConnector', 'MGDConnector', + 'NormConnector' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/base_connector.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/base_connector.py new file mode 100755 index 000000000..629af1940 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/base_connector.py @@ -0,0 +1,43 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import ABCMeta, abstractmethod +from typing import Dict, Optional, Tuple, Union + +import torch +from mmengine.model import BaseModule + + +class BaseConnector(BaseModule, metaclass=ABCMeta): + """Base class of connectors. + + Connector is mainly used for distillation, it usually converts the channel + number of input feature to align features of student and teacher. + + All subclasses should implement the following APIs: + + - ``forward_train()`` + + Args: + init_cfg (dict, optional): The config to control the initialization. + """ + + def __init__(self, init_cfg: Optional[Dict] = None) -> None: + super().__init__(init_cfg=init_cfg) + + def forward(self, feature: torch.Tensor) -> torch.Tensor: + """Forward computation. + + Args: + feature (torch.Tensor): Input feature. + """ + return self.forward_train(feature) + + @abstractmethod + def forward_train( + self, feature: torch.Tensor + ) -> Union[Tuple[torch.Tensor, ...], torch.Tensor]: + """Abstract train computation. + + Args: + feature (torch.Tensor): Input feature. + """ + pass diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/byot_connector.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/byot_connector.py new file mode 100755 index 000000000..af27dfe44 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/byot_connector.py @@ -0,0 +1,82 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from math import log +from typing import Dict, Optional, Tuple, Union + +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS +from ..ops.darts_series import DartsSepConv +from .base_connector import BaseConnector + + +@MODELS.register_module() +class BYOTConnector(BaseConnector): + """BYOTConnector connector that adds a self-attention with DartsSepConv. + + Args: + in_channel (int): The input channel of the DartsSepConv. + Use like input_tensor_channel = in_channel * expansion. + out_channel (int): The output channel of the DartsSepConv. + Use like output_tensor_channel = out_channel * expansion. + num_classes (int): The classification class num. + expansion (int): Expansion of DartsSepConv. Default to 4. + pool_size (int | tuple[int]): Average 2D pool size. Default to 4. + kernel_size (int | tuple[int]): Size of the convolving kernel in + DartsSepConv. Same as that in ``nn._ConvNd``. Default to 3. + stride (int | tuple[int]): Stride of the first layer in DartsSepConv. + Same as that in ``nn._ConvNd``. Default to 1. + init_cfg (dict, optional): The config to control the initialization. + """ + + def __init__( + self, + in_channel: int, + out_channel: int, + num_classes: int, + expansion: int = 4, + pool_size: Union[int, Tuple[int]] = 4, + kernel_size: Union[int, Tuple[int]] = 3, + stride: Union[int, Tuple[int]] = 1, + init_cfg: Optional[Dict] = None, + ) -> None: + super().__init__(init_cfg) + self.attention = nn.Sequential( + DartsSepConv( + in_channels=in_channel * expansion, + out_channels=in_channel * expansion, + kernel_size=kernel_size, + stride=stride), nn.BatchNorm2d(in_channel * expansion), + nn.ReLU(), nn.Upsample(scale_factor=2, mode='bilinear'), + nn.Sigmoid()) + scala_num = log(out_channel / in_channel, 2) + assert scala_num.is_integer() + scala = [] + + _in_channel = in_channel + + for _ in range(int(scala_num)): + scala.append( + DartsSepConv( + in_channels=_in_channel * expansion, + out_channels=_in_channel * 2 * expansion, + kernel_size=kernel_size, + stride=stride)) + _in_channel *= 2 + scala.append(nn.AvgPool2d(pool_size)) + self.scala = nn.Sequential(*scala) + self.fc = nn.Linear(out_channel * expansion, num_classes) + + def forward_train(self, feature: torch.Tensor) -> Tuple[torch.Tensor, ...]: + """Forward computation. + + Args: + feature (torch.Tensor): Input feature. + """ + feat = self.attention(feature) + feat = feat * feature + + feat = self.scala(feat) + feat = feat.view(feature.size(0), -1) + logits = self.fc(feat) + return (feat, logits) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/convmodule_connector.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/convmodule_connector.py new file mode 100755 index 000000000..44d596377 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/convmodule_connector.py @@ -0,0 +1,92 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional, Tuple, Union + +import torch +from mmcv.cnn import ConvModule + +from mmrazor.registry import MODELS +from .base_connector import BaseConnector + + +@MODELS.register_module() +class ConvModuleConnector(BaseConnector): + """Convolution connector that bundles conv/norm/activation layers. + + Args: + in_channel (int): The input channel of the connector. + out_channel (int): The output channel of the connector. + kernel_size (int | tuple[int, int]): Size of the convolving kernel. + Same as that in ``nn._ConvNd``. + stride (int | tuple[int, int]): Stride of the convolution. + Same as that in ``nn._ConvNd``. + padding (int | tuple[int, int]): Zero-padding added to both sides of + the input. Same as that in ``nn._ConvNd``. + dilation (int | tuple[int, int]): Spacing between kernel elements. + Same as that in ``nn._ConvNd``. + groups (int): Number of blocked connections from input channels to + output channels. Same as that in ``nn._ConvNd``. + bias (bool | str): If specified as `auto`, it will be decided by the + norm_cfg. Bias will be set as True if `norm_cfg` is None, otherwise + False. Default: "auto". + conv_cfg (dict): Config dict for convolution layer. Default: None, + which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. Default: None. + act_cfg (dict): Config dict for activation layer. + Default: dict(type='ReLU'). + inplace (bool): Whether to use inplace mode for activation. + Default: True. + with_spectral_norm (bool): Whether use spectral norm in conv module. + Default: False. + padding_mode (str): If the `padding_mode` has not been supported by + current `Conv2d` in PyTorch, we will use our own padding layer + instead. Currently, we support ['zeros', 'circular'] with official + implementation and ['reflect'] with our own implementation. + Default: 'zeros'. + order (tuple[str]): The order of conv/norm/activation layers. It is a + sequence of "conv", "norm" and "act". Common examples are + ("conv", "norm", "act") and ("act", "conv", "norm"). + Default: ('conv', 'norm', 'act'). + init_cfg (dict, optional): The config to control the initialization. + """ + + def __init__( + self, + in_channel: int, + out_channel: int, + kernel_size: Union[int, Tuple[int, int]] = 1, + stride: Union[int, Tuple[int, int]] = 1, + padding: Union[int, Tuple[int, int]] = 0, + dilation: Union[int, Tuple[int, int]] = 1, + groups: int = 1, + bias: Union[str, bool] = 'auto', + conv_cfg: Optional[Dict] = None, + norm_cfg: Optional[Dict] = None, + act_cfg: Dict = dict(type='ReLU'), + inplace: bool = True, + with_spectral_norm: bool = False, + padding_mode: str = 'zeros', + order: tuple = ('conv', 'norm', 'act'), + init_cfg: Optional[Dict] = None, + ) -> None: + super().__init__(init_cfg) + self.conv_module = ConvModule(in_channel, out_channel, kernel_size, + stride, padding, dilation, groups, bias, + conv_cfg, norm_cfg, act_cfg, inplace, + with_spectral_norm, padding_mode, order) + + def forward_train(self, feature: torch.Tensor) -> torch.Tensor: + """Forward computation. + + Args: + feature (torch.Tensor): Input feature. + """ + for layer in self.conv_module.order: + if layer == 'conv': + if self.conv_module.with_explicit_padding: + feature = self.conv_module.padding_layer(feature) + feature = self.conv_module.conv(feature) + elif layer == 'norm' and self.conv_module.with_norm: + feature = self.conv_module.norm(feature) + elif layer == 'act' and self.conv_module.with_activation: + feature = self.conv_module.activate(feature) + return feature diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/crd_connector.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/crd_connector.py new file mode 100755 index 000000000..48648c75d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/crd_connector.py @@ -0,0 +1,47 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS +from .base_connector import BaseConnector + + +@MODELS.register_module() +class CRDConnector(BaseConnector): + """Connector with linear layer. + + Args: + dim_in (int, optional): input channels. Defaults to 1024. + dim_out (int, optional): output channels. Defaults to 128. + """ + + def __init__(self, + dim_in: int = 1024, + dim_out: int = 128, + **kwargs) -> None: + super(CRDConnector, self).__init__(**kwargs) + self.linear = nn.Linear(dim_in, dim_out) + self.l2norm = Normalize(2) + + def forward_train(self, x: torch.Tensor) -> torch.Tensor: + x = x.view(x.size(0), -1) + x = self.linear(x) + x = self.l2norm(x) + return x + + +class Normalize(nn.Module): + """normalization layer. + + Args: + power (int, optional): power. Defaults to 2. + """ + + def __init__(self, power: int = 2) -> None: + super(Normalize, self).__init__() + self.power = power + + def forward(self, x: torch.Tensor) -> torch.Tensor: + norm = x.pow(self.power).sum(1, keepdim=True).pow(1. / self.power) + out = x.div(norm) + return out diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/factor_transfer_connectors.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/factor_transfer_connectors.py new file mode 100755 index 000000000..536649003 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/factor_transfer_connectors.py @@ -0,0 +1,133 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional + +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS +from .base_connector import BaseConnector + + +@MODELS.register_module() +class Paraphraser(BaseConnector): + """Paraphrasing Complex Network: Network Compression via Factor Transfer, + NeurIPS 2018. https://arxiv.org/pdf/1802.04977.pdf. + + teacher connector of FT. + + Args: + in_channel ([int]): number of input channels. + out_channel ([int]): number of output channels. + use_bn (bool, optional): Defaults to False. + phase (str, optional): Training phase. Defaults to 'pretrain'. + use_bn (Optional[bool], optional): use BN or not. Defaults to False. + init_cfg (Optional[Dict], optional): The weight initialized config for + :class:`BaseModule`. Defaults to None. + """ + + def __init__(self, + in_channel: int, + out_channel: int, + phase='pretrain', + use_bn: Optional[bool] = False, + init_cfg: Optional[Dict] = None) -> None: + + super(Paraphraser, self).__init__(init_cfg) + self._build_modules(in_channel, out_channel, use_bn) + + assert phase in ['pretrain', 'train'], f'Unexpect `phase`: {phase}' + self.phase = phase + + def _build_modules(self, + in_channel: int, + out_channel: int, + use_bn: Optional[bool] = False) -> None: + """A helper func to build internal modules. + + Args: + in_channel (int): input channels + out_channel (int): output channels + use_bn (Optional[bool], optional): use BN or not. + Defaults to False. + """ + + self.encoder = nn.Sequential( + nn.Conv2d(in_channel, in_channel, 3, 1, 1), + nn.BatchNorm2d(in_channel) if use_bn else nn.Sequential(), + nn.LeakyReLU(0.1, inplace=True), + nn.Conv2d(in_channel, out_channel, 3, 1, 1), + nn.BatchNorm2d(out_channel) if use_bn else nn.Sequential(), + nn.LeakyReLU(0.1, inplace=True), + nn.Conv2d(out_channel, out_channel, 3, 1, 1), + nn.BatchNorm2d(out_channel) if use_bn else nn.Sequential(), + nn.LeakyReLU(0.1, inplace=True)) + self.decoder = nn.Sequential( + nn.ConvTranspose2d(out_channel, out_channel, 3, 1, 1), + nn.BatchNorm2d(out_channel) if use_bn else nn.Sequential(), + nn.LeakyReLU(0.1, inplace=True), + nn.ConvTranspose2d(out_channel, in_channel, 3, 1, 1), + nn.BatchNorm2d(in_channel) if use_bn else nn.Sequential(), + nn.LeakyReLU(0.1, inplace=True), + nn.ConvTranspose2d(in_channel, in_channel, 3, 1, 1), + nn.BatchNorm2d(in_channel) if use_bn else nn.Sequential(), + nn.LeakyReLU(0.1, inplace=True)) + + def forward_train(self, x: torch.Tensor) -> torch.Tensor: + """Forward func for training.""" + with torch.no_grad(): + factor = self.encoder(x) + return factor + + def forward_pretrain(self, t_feat: torch.Tensor) -> torch.Tensor: + """Forward func for pretraining.""" + factor = self.encoder(t_feat) + t_feat_rec = self.decoder(factor) + + return t_feat_rec + + def forward(self, x: torch.Tensor) -> torch.Tensor: + """Omitted.""" + if self.phase == 'train': + return self.forward_train(x) + elif self.phase == 'pretrain': + return self.forward_pretrain(x) + else: + raise NotImplementedError( + f'phase: `{self.phase}` is not supported.') + + +@MODELS.register_module() +class Translator(BaseConnector): + """Paraphrasing Complex Network: Network Compression via Factor Transfer, + NeurIPS 2018. https://arxiv.org/pdf/1802.04977.pdf. + + student connector of FT. + + Args: + in_channel ([int]): number of input channels. + out_channel ([int]): number of output channels. + use_bn (bool, optional): Defaults to False. + init_cfg (Optional[Dict], optional): The weight initialized config for + :class:`BaseModule`. Defaults to None. + """ + + def __init__(self, + in_channel: int, + out_channel: int, + use_bn: Optional[bool] = True, + init_cfg: Optional[Dict] = None) -> None: + super(Translator, self).__init__(init_cfg) + self.encoder = nn.Sequential( + nn.Conv2d(in_channel, in_channel, 3, 1, 1), + nn.BatchNorm2d(in_channel) if use_bn else nn.Sequential(), + nn.LeakyReLU(0.1, inplace=True), + nn.Conv2d(in_channel, out_channel, 3, 1, 1), + nn.BatchNorm2d(out_channel) if use_bn else nn.Sequential(), + nn.LeakyReLU(0.1, inplace=True), + nn.Conv2d(out_channel, out_channel, 3, 1, 1), + nn.BatchNorm2d(out_channel) if use_bn else nn.Sequential(), + nn.LeakyReLU(0.1, inplace=True)) + + def forward_train(self, x: torch.Tensor) -> torch.Tensor: + """Forward func for training.""" + return self.encoder(x) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/fbkd_connector.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/fbkd_connector.py new file mode 100755 index 000000000..db9007ee6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/fbkd_connector.py @@ -0,0 +1,298 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional, Tuple + +import torch +import torch.nn as nn +from mmcv.cnn import NonLocal2d + +from mmrazor.registry import MODELS +from .base_connector import BaseConnector + + +class NonLocal2dMaxpoolNstride(NonLocal2d): + """Nonlocal block for 2-dimension inputs, with a configurable + maxpool_stride. + + This module is proposed in + "Non-local Neural Networks" + Paper reference: https://arxiv.org/abs/1711.07971 + Code reference: https://github.com/AlexHex7/Non-local_pytorch + + Args: + in_channels (int): Channels of the input feature map. + reduction (int): Channel reduction ratio. Defaults to 2. + conv_cfg (dict): The config dict for convolution layers. + Defaults to `nn.Conv2d`. + norm_cfg (dict): The config dict for normalization layers. + Defaults to `BN`. (This parameter is only applicable to conv_out.) + mode (str): Options are `gaussian`, `concatenation`, + `embedded_gaussian` and `dot_product`. Default: dot_product. + sub_sample (bool): Whether to apply max pooling after pairwise + function (Note that the `sub_sample` is applied on spatial only). + Default: False. + maxpool_stride (int): The stride of the maxpooling module. + Defaults to 2. + zeros_init (bool): Whether to use zero to initialize weights of + `conv_out`. Defaults to True. + """ + + def __init__(self, + in_channels: int, + reduction: int = 2, + conv_cfg: Dict = dict(type='Conv2d'), + norm_cfg: Dict = dict(type='BN'), + mode: str = 'embedded_gaussian', + sub_sample: bool = False, + maxpool_stride: int = 2, + zeros_init: bool = True, + **kwargs) -> None: + """Inits the NonLocal2dMaxpoolNstride module.""" + super().__init__( + in_channels=in_channels, + sub_sample=sub_sample, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + reduction=reduction, + mode=mode, + zeros_init=zeros_init, + **kwargs) + self.norm_cfg = norm_cfg + + if sub_sample: + max_pool_layer = nn.MaxPool2d( + kernel_size=(maxpool_stride, maxpool_stride)) + self.g: nn.Sequential = nn.Sequential(self.g, max_pool_layer) + if self.mode != 'gaussian': + self.phi: nn.Sequential = nn.Sequential( + self.phi, max_pool_layer) + else: + self.phi = max_pool_layer + + +@MODELS.register_module() +class FBKDStudentConnector(BaseConnector): + """Improve Object Detection with Feature-based Knowledge Distillation: + Towards Accurate and Efficient Detectors, ICLR2021. + https://openreview.net/pdf?id=uKhGRvM8QNH. + + Student connector for FBKD. + + Args: + in_channels (int): Channels of the input feature map. + reduction (int): Channel reduction ratio. Defaults to 2. + conv_cfg (dict): The config dict for convolution layers. + Defaults to `nn.Conv2d`. + norm_cfg (dict): The config dict for normalization layers. + Defaults to `BN`. (This parameter is only applicable to conv_out.) + mode (str): Options are `gaussian`, `concatenation`, + `embedded_gaussian` and `dot_product`. Default: dot_product. + sub_sample (bool): Whether to apply max pooling after pairwise + function (Note that the `sub_sample` is applied on spatial only). + Default: False. + maxpool_stride (int): The stride of the maxpooling module. + Defaults to 2. + zeros_init (bool): Whether to use zero to initialize weights of + `conv_out`. Defaults to True. + spatial_T (float): Temperature used in spatial-wise pooling. + Defaults to 0.5. + channel_T (float): Temperature used in channel-wise pooling. + Defaults to 0.5. + init_cfg (dict, optional): The config to control the initialization. + """ + + def __init__(self, + in_channels: int, + reduction: int = 2, + conv_cfg: Dict = dict(type='Conv2d'), + norm_cfg: Dict = dict(type='BN'), + mode: str = 'dot_product', + sub_sample: bool = False, + maxpool_stride: int = 2, + zeros_init: bool = True, + spatial_T: float = 0.5, + channel_T: float = 0.5, + init_cfg: Optional[Dict] = None, + **kwargs) -> None: + """Inits the FBKDStuConnector.""" + super().__init__(init_cfg) + self.channel_wise_adaptation = nn.Linear(in_channels, in_channels) + + self.spatial_wise_adaptation = nn.Conv2d( + 1, 1, kernel_size=3, stride=1, padding=1) + + self.adaptation_layers = nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0) + + self.student_non_local = NonLocal2dMaxpoolNstride( + in_channels=in_channels, + reduction=reduction, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + mode=mode, + sub_sample=sub_sample, + maxpool_stride=maxpool_stride, + zeros_init=zeros_init, + **kwargs) + + self.non_local_adaptation = nn.Conv2d( + in_channels, in_channels, kernel_size=1, stride=1, padding=0) + + self.in_channels = in_channels + self.spatial_T = spatial_T + self.channel_T = channel_T + + def forward_train(self, x: torch.Tensor) -> Tuple[torch.Tensor, ...]: + """Frorward function for training. + + Args: + x (torch.Tensor): Input student features. + + Returns: + s_spatial_mask (torch.Tensor): Student spatial-wise mask. + s_channel_mask (torch.Tensor): Student channel-wise mask. + s_feat_adapt (torch.Tensor): Adaptative student feature. + s_channel_pool_adapt (torch.Tensor): Student feature which through + channel-wise pooling and adaptation_layers. + s_spatial_pool_adapt (torch.Tensor): Student feature which through + spatial-wise pooling and adaptation_layers. + s_relation_adapt (torch.Tensor): Adaptative student relations. + """ + # Calculate spatial-wise mask. + s_spatial_mask = torch.mean(torch.abs(x), [1], keepdim=True) + size = s_spatial_mask.size() + s_spatial_mask = s_spatial_mask.view(x.size(0), -1) + + # Soften or sharpen the spatial-wise mask by temperature. + s_spatial_mask = torch.softmax( + s_spatial_mask / self.spatial_T, dim=1) * size[-1] * size[-2] + s_spatial_mask = s_spatial_mask.view(size) + + # Calculate channel-wise mask. + s_channel_mask = torch.mean(torch.abs(x), [2, 3], keepdim=True) + channel_mask_size = s_channel_mask.size() + s_channel_mask = s_channel_mask.view(x.size(0), -1) + + # Soften or sharpen the channel-wise mask by temperature. + s_channel_mask = torch.softmax( + s_channel_mask / self.channel_T, dim=1) * self.in_channels + s_channel_mask = s_channel_mask.view(channel_mask_size) + + # Adaptative and pool student feature through channel-wise. + s_feat_adapt = self.adaptation_layers(x) + s_channel_pool_adapt = self.channel_wise_adaptation( + torch.mean(x, [2, 3])) + + # Adaptative and pool student feature through spatial-wise. + s_spatial_pool = torch.mean(x, [1]).view( + x.size(0), 1, x.size(2), x.size(3)) + s_spatial_pool_adapt = self.spatial_wise_adaptation(s_spatial_pool) + + # Calculate non_local_adaptation. + s_relation = self.student_non_local(x) + s_relation_adapt = self.non_local_adaptation(s_relation) + + return (s_spatial_mask, s_channel_mask, s_channel_pool_adapt, + s_spatial_pool_adapt, s_relation_adapt, s_feat_adapt) + + +@MODELS.register_module() +class FBKDTeacherConnector(BaseConnector): + """Improve Object Detection with Feature-based Knowledge Distillation: + Towards Accurate and Efficient Detectors, ICLR2021. + https://openreview.net/pdf?id=uKhGRvM8QNH. + + Teacher connector for FBKD. + + Args: + in_channels (int): Channels of the input feature map. + reduction (int): Channel reduction ratio. Defaults to 2. + conv_cfg (dict): The config dict for convolution layers. + Defaults to `nn.Conv2d`. + norm_cfg (dict): The config dict for normalization layers. + Defaults to `BN`. (This parameter is only applicable to conv_out.) + mode (str): Options are `gaussian`, `concatenation`, + `embedded_gaussian` and `dot_product`. Default: dot_product. + sub_sample (bool): Whether to apply max pooling after pairwise + function (Note that the `sub_sample` is applied on spatial only). + Default: False. + maxpool_stride (int): The stride of the maxpooling module. + Defaults to 2. + zeros_init (bool): Whether to use zero to initialize weights of + `conv_out`. Defaults to True. + spatial_T (float): Temperature used in spatial-wise pooling. + Defaults to 0.5. + channel_T (float): Temperature used in channel-wise pooling. + Defaults to 0.5. + init_cfg (dict, optional): The config to control the initialization. + """ + + def __init__(self, + in_channels, + reduction=2, + conv_cfg: Dict = dict(type='Conv2d'), + norm_cfg: Dict = dict(type='BN'), + mode: str = 'dot_product', + sub_sample: bool = False, + maxpool_stride: int = 2, + zeros_init: bool = True, + spatial_T: float = 0.5, + channel_T: float = 0.5, + init_cfg: Optional[Dict] = None, + **kwargs) -> None: + super().__init__(init_cfg) + self.teacher_non_local = NonLocal2dMaxpoolNstride( + in_channels=in_channels, + reduction=reduction, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + mode=mode, + sub_sample=sub_sample, + maxpool_stride=maxpool_stride, + zeros_init=zeros_init, + **kwargs) + + self.in_channels = in_channels + self.spatial_T = spatial_T + self.channel_T = channel_T + + def forward_train(self, x: torch.Tensor) -> Tuple[torch.Tensor, ...]: + """Frorward function for training. + + Args: + x (torch.Tensor): Input teacher features. + + Returns: + t_spatial_mask (torch.Tensor): Teacher spatial-wise mask. + t_channel_mask (torch.Tensor): Teacher channel-wise mask. + t_spatial_pool (torch.Tensor): Teacher features which through + spatial-wise pooling. + t_relation (torch.Tensor): Teacher relation matrix. + """ + # Calculate spatial-wise mask. + t_spatial_mask = torch.mean(torch.abs(x), [1], keepdim=True) + size = t_spatial_mask.size() + t_spatial_mask = t_spatial_mask.view(x.size(0), -1) + + # Soften or sharpen the spatial-wise mask by temperature. + t_spatial_mask = torch.softmax( + t_spatial_mask / self.spatial_T, dim=1) * size[-1] * size[-2] + t_spatial_mask = t_spatial_mask.view(size) + + # Calculate channel-wise mask. + t_channel_mask = torch.mean(torch.abs(x), [2, 3], keepdim=True) + channel_mask_size = t_channel_mask.size() + t_channel_mask = t_channel_mask.view(x.size(0), -1) + + # Soften or sharpen the channel-wise mask by temperature. + t_channel_mask = torch.softmax( + t_channel_mask / self.channel_T, dim=1) * self.in_channels + t_channel_mask = t_channel_mask.view(channel_mask_size) + + # Adaptative and pool student feature through spatial-wise. + t_spatial_pool = torch.mean(x, [1]).view( + x.size(0), 1, x.size(2), x.size(3)) + + # Calculate non_local relation. + t_relation = self.teacher_non_local(x) + + return (t_spatial_mask, t_channel_mask, t_spatial_pool, t_relation, x) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/mgd_connector.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/mgd_connector.py new file mode 100755 index 000000000..9b53fed1d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/mgd_connector.py @@ -0,0 +1,71 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional + +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS +from .base_connector import BaseConnector + + +@MODELS.register_module() +class MGDConnector(BaseConnector): + """PyTorch version of `Masked Generative Distillation. + + ` + + Args: + student_channels(int): Number of channels in the student's feature map. + teacher_channels(int): Number of channels in the teacher's feature map. + lambda_mgd (float, optional): masked ratio. Defaults to 0.65 + init_cfg (Optional[Dict], optional): The weight initialized config for + :class:`BaseModule`. Defaults to None. + """ + + def __init__( + self, + student_channels: int, + teacher_channels: int, + lambda_mgd: float = 0.65, + mask_on_channel: bool = False, + init_cfg: Optional[Dict] = None, + ) -> None: + super().__init__(init_cfg) + self.lambda_mgd = lambda_mgd + self.mask_on_channel = mask_on_channel + if student_channels != teacher_channels: + self.align = nn.Conv2d( + student_channels, + teacher_channels, + kernel_size=1, + stride=1, + padding=0) + else: + self.align = None + + self.generation = nn.Sequential( + nn.Conv2d( + teacher_channels, teacher_channels, kernel_size=3, padding=1), + nn.ReLU(inplace=True), + nn.Conv2d( + teacher_channels, teacher_channels, kernel_size=3, padding=1)) + + def forward_train(self, feature: torch.Tensor) -> torch.Tensor: + if self.align is not None: + feature = self.align(feature) + + N, C, H, W = feature.shape + + device = feature.device + if not self.mask_on_channel: + mat = torch.rand((N, 1, H, W)).to(device) + else: + mat = torch.rand((N, C, 1, 1)).to(device) + + mat = torch.where(mat > 1 - self.lambda_mgd, + torch.zeros(1).to(device), + torch.ones(1).to(device)).to(device) + + masked_fea = torch.mul(feature, mat) + new_fea = self.generation(masked_fea) + return new_fea diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/norm_connector.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/norm_connector.py new file mode 100755 index 000000000..5d65da7dc --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/norm_connector.py @@ -0,0 +1,19 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional + +import torch +from mmcv.cnn import build_norm_layer + +from mmrazor.registry import MODELS +from .base_connector import BaseConnector + + +@MODELS.register_module() +class NormConnector(BaseConnector): + + def __init__(self, in_channels, norm_cfg, init_cfg: Optional[Dict] = None): + super(NormConnector, self).__init__(init_cfg) + _, self.norm = build_norm_layer(norm_cfg, in_channels) + + def forward_train(self, feature: torch.Tensor) -> torch.Tensor: + return self.norm(feature) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/ofd_connector.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/ofd_connector.py new file mode 100755 index 000000000..280ec3c4f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/ofd_connector.py @@ -0,0 +1,38 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional + +import torch + +from mmrazor.registry import MODELS +from .base_connector import BaseConnector + + +@MODELS.register_module() +class OFDTeacherConnector(BaseConnector): + """Connector designed for ``OverhaulFeatureDistillation`` + + Args: + init_cfg (Optional[Dict], optional): Initialization config dict. + Defaults to None. + """ + + def __init__(self, init_cfg: Optional[Dict] = None) -> None: + super().__init__(init_cfg) + self.margin: torch.Tensor = None + + def init_margin(self, margin: torch.Tensor) -> None: + """Initializing margin, will be called by + ``OverhaulFeatureDistillation``. + + Args: + margin (torch.Tensor): margin + """ + self.margin = margin + + def forward_train(self, feature: torch.Tensor) -> torch.Tensor: + """forward func for training.""" + assert self.margin is not None, ( + 'margin must be initialized before training.') + self.margin = self.margin.to(feature.device) + feature = torch.max(feature.detach(), self.margin) + return feature diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/torch_connector.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/torch_connector.py new file mode 100755 index 000000000..9b64d33ae --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/torch_connector.py @@ -0,0 +1,135 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS +from .base_connector import BaseConnector + +FUNCTION_LIST = [ + 'adaptive_avg_pool2d', + 'adaptive_max_pool2d', + 'avg_pool2d', + 'dropout', + 'dropout2d', + 'max_pool2d', + 'normalize', + 'relu', + 'softmax', + 'interpolate', +] + + +@MODELS.register_module() +class TorchFunctionalConnector(BaseConnector): + """TorchFunctionalConnector: Call function in torch.nn.functional + to process input data + + usage: + tensor1 = torch.rand(3,3,16,16) + pool_connector = TorchFunctionalConnector( + function_name='avg_pool2d', + func_args=dict(kernel_size=4), + ) + tensor2 = pool_connector.forward_train(tensor1) + tensor2.size() + # torch.Size([3, 3, 4, 4]) + + which is equal to torch.nn.functional.avg_pool2d(kernel_size=4) + Args: + function_name (str, optional): function. Defaults to None. + func_args (dict): args parsed to function. Defaults to {}. + init_cfg (dict, optional): The config to control the initialization. + """ + + def __init__(self, + function_name: Optional[str] = None, + func_args: Dict = {}, + init_cfg: Optional[Dict] = None) -> None: + super().__init__(init_cfg) + assert function_name is not None, 'Arg `function_name` cannot be None' + if function_name not in FUNCTION_LIST: + raise ValueError( + ' Arg `function_name` are not available, See this list', + FUNCTION_LIST) + self.func = getattr(F, function_name) + self.func_args = func_args + + def forward_train(self, x: torch.Tensor) -> torch.Tensor: + """Frorward function for training. + + Args: + x (torch.Tensor): Input features. + """ + x = self.func(x, **self.func_args) + return x + + +MODULE_LIST = [ + 'AdaptiveAvgPool2d', + 'AdaptiveMaxPool2d', + 'AvgPool2d', + 'BatchNorm2d', + 'Conv2d', + 'Dropout', + 'Dropout2d', + 'Linear', + 'MaxPool2d', + 'ReLU', + 'Softmax', +] + + +@MODELS.register_module() +class TorchNNConnector(BaseConnector): + """TorchNNConnector: create nn.module in torch.nn to process input data + + usage: + tensor1 = torch.rand(3,3,16,16) + pool_connector = TorchNNConnector( + module_name='AvgPool2d', + module_args=dict(kernel_size=4), + ) + tensor2 = pool_connector.forward_train(tensor1) + tensor2.size() + # torch.Size([3, 3, 4, 4]) + + which is equal to torch.nn.AvgPool2d(kernel_size=4) + Args: + module_name (str, optional): + module name. Defaults to None. + possible_values:['AvgPool2d', + 'Dropout2d', + 'AdaptiveAvgPool2d', + 'AdaptiveMaxPool2d', + 'ReLU', + 'Softmax', + 'BatchNorm2d', + 'Linear',] + module_args (dict): + args parsed to nn.Module().__init__(). Defaults to {}. + init_cfg (dict, optional): The config to control the initialization. + """ + + def __init__(self, + module_name: Optional[str] = None, + module_args: Dict = {}, + init_cfg: Optional[Dict] = None) -> None: + super().__init__(init_cfg) + assert module_name is not None, 'Arg `module_name` cannot be None' + if module_name not in MODULE_LIST: + raise ValueError( + ' Arg `module_name` are not available, See this list', + MODULE_LIST) + self.func = getattr(nn, module_name)(**module_args) + + def forward_train(self, x: torch.Tensor) -> torch.Tensor: + """Frorward function for training. + + Args: + x (torch.Tensor): Input features. + """ + x = self.func(x) + return x diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/__init__.py new file mode 100755 index 000000000..b49693855 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .bricks import * # noqa: F401,F403 +from .head import * # noqa: F401,F403 +from .mixins import * # noqa: F401,F403 diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/__init__.py new file mode 100755 index 000000000..d3abe4fd8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/__init__.py @@ -0,0 +1,35 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .dynamic_container import DynamicSequential +from .dynamic_conv import (BigNasConv2d, DynamicConv2d, + DynamicConv2dAdaptivePadding, FuseConv2d, OFAConv2d) +from .dynamic_embed import DynamicPatchEmbed +from .dynamic_function import DynamicInputResizer +from .dynamic_linear import DynamicLinear +from .dynamic_multi_head_attention import DynamicMultiheadAttention +from .dynamic_norm import (DMCPBatchNorm2d, DynamicBatchNorm1d, + DynamicBatchNorm2d, DynamicBatchNorm3d, + DynamicBatchNormXd, DynamicLayerNorm, + DynamicSyncBatchNorm, SwitchableBatchNorm2d) +from .dynamic_relative_position import DynamicRelativePosition2D + +__all__ = [ + 'BigNasConv2d', + 'DynamicConv2d', + 'OFAConv2d', + 'DynamicLinear', + 'DynamicBatchNorm1d', + 'DynamicBatchNorm2d', + 'DynamicBatchNorm3d', + 'SwitchableBatchNorm2d', + 'DynamicSequential', + 'DynamicPatchEmbed', + 'DynamicRelativePosition2D', + 'FuseConv2d', + 'DynamicMultiheadAttention', + 'DynamicSyncBatchNorm', + 'DynamicConv2dAdaptivePadding', + 'DynamicBatchNormXd', + 'DynamicInputResizer', + 'DynamicLayerNorm', + 'DMCPBatchNorm2d', +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_container.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_container.py new file mode 100755 index 000000000..3696fe38e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_container.py @@ -0,0 +1,109 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Iterator, Optional, Set + +import torch.nn as nn +from mmengine.model import Sequential +from torch import Tensor +from torch.nn import Module + +from mmrazor.models.mutables import DerivedMutable, MutableValue +from mmrazor.models.mutables.base_mutable import BaseMutable +from ..mixins import DynamicMixin + + +class DynamicSequential(Sequential, DynamicMixin): + """Dynamic Sequential Container.""" + mutable_attrs: nn.ModuleDict + accepted_mutable_attrs: Set[str] = {'depth'} + + forward_ignored_module = (MutableValue, DerivedMutable, nn.ModuleDict) + + def __init__(self, *args, init_cfg: Optional[dict] = None): + super().__init__(*args, init_cfg=init_cfg) + + self.mutable_attrs: Dict[str, BaseMutable] = nn.ModuleDict() + + @property + def mutable_depth(self): + """Mutable depth.""" + assert hasattr(self, 'mutable_attrs') + return self.mutable_attrs['depth'] + + def register_mutable_attr(self: Sequential, attr: str, + mutable: BaseMutable): + """Register attribute of mutable.""" + if attr == 'depth': + self._register_mutable_depth(mutable) + else: + raise NotImplementedError + + def _register_mutable_depth(self: Sequential, mutable_depth: MutableValue): + """Register mutable depth.""" + assert hasattr(self, 'mutable_attrs') + assert mutable_depth.current_choice is not None + current_depth = mutable_depth.current_choice + if current_depth > len(self._modules): + raise ValueError(f'Expect depth of mutable to be smaller than ' + f'{len(self._modules)} as `depth`, ' + f'but got: {current_depth}.') + self.mutable_attrs['depth'] = mutable_depth + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return Sequential + + def to_static_op(self: Sequential) -> Sequential: + """Convert dynamic Sequential to static one.""" + self.check_if_mutables_fixed() + + if self.mutable_depth is None: + fixed_depth = len(self) + else: + fixed_depth = self.get_current_choice(self.mutable_depth) + + modules = [] + passed_module_nums = 0 + for module in self: + if isinstance(module, self.forward_ignored_module): + continue + else: + passed_module_nums += 1 + if passed_module_nums > fixed_depth: + break + + modules.append(module) + + return Sequential(*modules) + + def forward(self, x: Tensor) -> Tensor: + """Forward of Dynamic Sequential.""" + if self.mutable_depth is None: + return self(x) + + current_depth = self.get_current_choice(self.mutable_depth) + passed_module_nums = 0 + for module in self.pure_modules(): + passed_module_nums += 1 + if passed_module_nums > current_depth: + break + x = module(x) + return x + + @property + def pure_module_nums(self) -> int: + """Number of pure module.""" + return sum(1 for _ in self.pure_modules()) + + def pure_modules(self) -> Iterator[Module]: + """nn.Module would influence the forward of Sequential.""" + for module in self._modules.values(): + if isinstance(module, self.forward_ignored_module): + continue + yield module + + @classmethod + def convert_from(cls, module: Sequential): + """Convert the static Sequential to dynamic one.""" + dynamic_m = cls(module._modules) + return dynamic_m diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_conv.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_conv.py new file mode 100755 index 000000000..4604ccb36 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_conv.py @@ -0,0 +1,286 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import math +from typing import Callable, Dict + +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch import Tensor + +from mmrazor.models.mutables.base_mutable import BaseMutable +from mmrazor.registry import MODELS +from ..mixins.dynamic_conv_mixins import (BigNasConvMixin, DynamicConvMixin, + FuseConvMixin, OFAConvMixin) + +GroupWiseConvWarned = False + + +@MODELS.register_module() +class DynamicConv2d(nn.Conv2d, DynamicConvMixin): + """Dynamic Conv2d OP. + + Note: + Arguments for ``__init__`` of ``DynamicConv2d`` is totally same as + :obj:`torch.nn.Conv2d`. + + Attributes: + mutable_attrs (ModuleDict[str, BaseMutable]): Mutable attributes, + such as `in_channels`. The key of the dict must in + ``accepted_mutable_attrs``. + """ + mutable_attrs: nn.ModuleDict + accepted_mutable_attrs = {'in_channels', 'out_channels'} + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + # TODO + # https://pytorch.org/docs/stable/_modules/torch/nn/modules/conv.html#Conv2d + assert self.padding_mode == 'zeros' + self.mutable_attrs: Dict[str, BaseMutable] = nn.ModuleDict() + + @classmethod + def convert_from(cls, module: nn.Conv2d) -> 'DynamicConv2d': + """Convert an instance of nn.Conv2d to a new instance of + DynamicConv2d.""" + + return cls( + in_channels=module.in_channels, + out_channels=module.out_channels, + kernel_size=module.kernel_size, + stride=module.stride, + padding=module.padding, + dilation=module.dilation, + groups=module.groups, + bias=True if module.bias is not None else False, + padding_mode=module.padding_mode) + + @property + def conv_func(self) -> Callable: + """The function that will be used in ``forward_mixin``.""" + return F.conv2d + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return nn.Conv2d + + def forward(self, x: Tensor) -> Tensor: + """Forward of dynamic conv2d OP.""" + return self.forward_mixin(x) + + +@MODELS.register_module() +class BigNasConv2d(nn.Conv2d, BigNasConvMixin): + """Conv2d used in BigNas. + + Note: + Arguments for ``__init__`` of ``DynamicConv2d`` is totally same as + :obj:`torch.nn.Conv2d`. + + Attributes: + mutable_attrs (ModuleDict[str, BaseMutable]): Mutable attributes, + such as `in_channels`. The key of the dict must in + ``accepted_mutable_attrs``. + """ + mutable_attrs: nn.ModuleDict + accepted_mutable_attrs = {'in_channels', 'out_channels', 'kernel_size'} + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + # TODO + # https://pytorch.org/docs/stable/_modules/torch/nn/modules/conv.html#Conv2d + assert self.padding_mode == 'zeros' + self.mutable_attrs: Dict[str, BaseMutable] = nn.ModuleDict() + + @classmethod + def convert_from(cls, module: nn.Conv2d) -> 'BigNasConv2d': + """Convert an instance of `nn.Conv2d` to a new instance of + `BigNasConv2d`.""" + return cls( + in_channels=module.in_channels, + out_channels=module.out_channels, + kernel_size=module.kernel_size, + stride=module.stride, + padding=module.padding, + dilation=module.dilation, + groups=module.groups, + bias=True if module.bias is not None else False, + padding_mode=module.padding_mode) + + @property + def conv_func(self) -> Callable: + """The function that will be used in ``forward_mixin``.""" + return F.conv2d + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return nn.Conv2d + + def forward(self, x: Tensor) -> Tensor: + """Forward of bignas' conv2d.""" + return self.forward_mixin(x) + + +@MODELS.register_module() +class OFAConv2d(nn.Conv2d, OFAConvMixin): + """Conv2d used in `Once-for-All`. + + Refers to `Once-for-All: Train One Network and Specialize it for Efficient + Deployment `_. + """ + """Dynamic Conv2d OP. + + Note: + Arguments for ``__init__`` of ``OFAConv2d`` is totally same as + :obj:`torch.nn.Conv2d`. + + Attributes: + mutable_attrs (ModuleDict[str, BaseMutable]): Mutable attributes, + such as `in_channels`. The key of the dict must in + ``accepted_mutable_attrs``. + """ + mutable_attrs: nn.ModuleDict + accepted_mutable_attrs = {'in_channels', 'out_channels'} + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + # TODO + # https://pytorch.org/docs/stable/_modules/torch/nn/modules/conv.html#Conv2d + assert self.padding_mode == 'zeros' + self.mutable_attrs: Dict[str, BaseMutable] = nn.ModuleDict() + + @classmethod + def convert_from(cls, module: nn.Conv2d) -> 'OFAConv2d': + """Convert an instance of `nn.Conv2d` to a new instance of + `OFAConv2d`.""" + + return cls( + in_channels=module.in_channels, + out_channels=module.out_channels, + kernel_size=module.kernel_size, + stride=module.stride, + padding=module.padding, + dilation=module.dilation, + groups=module.groups, + bias=True if module.bias is not None else False, + padding_mode=module.padding_mode) + + @property + def conv_func(self) -> Callable: + """The function that will be used in ``forward_mixin``.""" + return F.conv2d + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return nn.Conv2d + + def forward(self, x: Tensor) -> Tensor: + """Forward of OFA's conv2d.""" + return self.forward_mixin(x) + + +@MODELS.register_module() +class FuseConv2d(nn.Conv2d, FuseConvMixin): + """FuseConv2d used in `DCFF`. + + Refers to `Training Compact CNNs for Image Classification + using Dynamic-coded Filter Fusion `_. + Attributes: + mutable_attrs (ModuleDict[str, BaseMutable]): Mutable attributes, + such as `in_channels`. The key of the dict must in + ``accepted_mutable_attrs``. + """ + mutable_attrs: nn.ModuleDict + accepted_mutable_attrs = {'in_channels', 'out_channels'} + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.mutable_attrs: Dict[str, BaseMutable] = nn.ModuleDict() + + @classmethod + def convert_from(cls, module: nn.Conv2d) -> 'FuseConv2d': + """Convert an instance of `nn.Conv2d` to a new instance of + `FuseConv2d`.""" + return cls( + in_channels=module.in_channels, + out_channels=module.out_channels, + kernel_size=module.kernel_size, + stride=module.stride, + padding=module.padding, + dilation=module.dilation, + groups=module.groups, + bias=True if module.bias is not None else False, + padding_mode=module.padding_mode) + + @property + def conv_func(self) -> Callable: + """The function that will be used in ``forward_mixin``.""" + return F.conv2d + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return nn.Conv2d + + def forward(self, x: Tensor) -> Tensor: + """Forward of fused conv2d.""" + return self.forward_mixin(x) + + +class DynamicConv2dAdaptivePadding(DynamicConv2d): + """Dynamic version of mmcv.cnn.bricks.Conv2dAdaptivePadding.""" + + def forward(self, x: torch.Tensor) -> torch.Tensor: + img_h, img_w = x.size()[-2:] + kernel_h, kernel_w = self.weight.size()[-2:] + stride_h, stride_w = self.stride + output_h = math.ceil(img_h / stride_h) + output_w = math.ceil(img_w / stride_w) + pad_h = ( + max((output_h - 1) * self.stride[0] + + (kernel_h - 1) * self.dilation[0] + 1 - img_h, 0)) + pad_w = ( + max((output_w - 1) * self.stride[1] + + (kernel_w - 1) * self.dilation[1] + 1 - img_w, 0)) + if pad_h > 0 or pad_w > 0: + x = F.pad(x, [ + pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2 + ]) + return super().forward(x) + + @property + def static_op_factory(self): + from mmcv.cnn.bricks import Conv2dAdaptivePadding + return Conv2dAdaptivePadding + + def to_static_op(self) -> nn.Conv2d: + self.check_if_mutables_fixed() + + weight, bias, padding = self.get_dynamic_params() + groups = self.groups + if groups == self.in_channels == self.out_channels and \ + self.mutable_in_channels is not None: + mutable_in_channels = self.mutable_attrs['in_channels'] + groups = mutable_in_channels.current_mask.sum().item() + out_channels = weight.size(0) + in_channels = weight.size(1) * groups + + kernel_size = tuple(weight.shape[2:]) + + static_conv = self.static_op_factory( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=self.stride, + padding=padding, + dilation=self.dilation, + groups=groups, + bias=True if bias is not None else False) + + static_conv.weight = nn.Parameter(weight) + if bias is not None: + static_conv.bias = nn.Parameter(bias) + + return static_conv diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_embed.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_embed.py new file mode 100755 index 000000000..f255d2402 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_embed.py @@ -0,0 +1,154 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import logging +from typing import Dict, Set, Tuple + +import torch.nn as nn +import torch.nn.functional as F + +try: + from mmcls.models.utils import PatchEmbed +except ImportError: + from mmrazor.utils import get_placeholder + PatchEmbed = get_placeholder('mmcls') +from mmengine import print_log +from torch import Tensor + +from mmrazor.models.mutables.base_mutable import BaseMutable +from mmrazor.registry import MODELS +from ..mixins import DynamicChannelMixin + + +@MODELS.register_module() +class DynamicPatchEmbed(PatchEmbed, DynamicChannelMixin): + """Dynamic Patch Embedding. + + Note: + Arguments for ``__init__`` of ``DynamicPatchEmbed`` is totally same as + :obj:`mmcls.models.utils.PatchEmbed`. + Attributes: + mutable_attrs (ModuleDict[str, BaseMutable]): Mutable attributes, + such as `embed_dims`. The key of the dict must in + ``accepted_mutable_attrs``. + """ + + mutable_attrs: nn.ModuleDict + accepted_mutable_attrs: Set[str] = {'embed_dims'} + attr_mappings: Dict[str, str] = { + 'in_channels': 'embed_dims', + 'out_channels': 'embed_dims' + } + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.mutable_attrs: Dict[str, BaseMutable] = nn.ModuleDict() + + @property + def mutable_embed_dims(self): + """Mutable embedding dimension.""" + assert hasattr(self, 'mutable_attrs') + return self.mutable_attrs['embed_dims'] + + def register_mutable_attr(self: PatchEmbed, attr: str, + mutable: BaseMutable): + """Register attribute of mutable.""" + self.check_mutable_attr_valid(attr) + if attr in self.attr_mappings: + attr_map = self.attr_mappings[attr] + assert attr_map in self.accepted_mutable_attrs + if attr_map in self.mutable_attrs: + print_log( + f'{attr_map}({attr}) is already in `mutable_attrs`', + level=logging.WARNING) + else: + self._register_mutable_attr(attr_map, mutable) + elif attr in self.accepted_mutable_attrs: + self._register_mutable_attr(attr, mutable) + else: + raise NotImplementedError + + def _register_mutable_attr(self, attr, mutable): + """Register `embed_dims`.""" + if attr == 'embed_dims': + self._register_embed_dims(mutable) + else: + raise NotImplementedError + + def _register_embed_dims(self: PatchEmbed, + mutable_patch_embedding: BaseMutable) -> None: + """Register mutable embedding dimension.""" + mask_size = mutable_patch_embedding.current_mask.size(0) + + if mask_size != self.embed_dims: + raise ValueError( + f'Expect mask size of mutable to be {self.embed_dims} as ' + f'`embed_dims`, but got: {mask_size}.') + + self.mutable_attrs['embed_dims'] = mutable_patch_embedding + + def _get_dynamic_params(self: PatchEmbed) -> Tuple[Tensor, Tensor]: + """Get mask of ``embed_dims``""" + if 'embed_dims' not in self.mutable_attrs: + return self.projection.weight, self.projection.bias + else: + out_mask = self.mutable_embed_dims.current_mask.to( + self.projection.weight.device) + weight = self.projection.weight[out_mask][:] + bias = self.projection.bias[ + out_mask] if self.projection.bias is not None else None # noqa: E501 + return weight, bias + + def to_static_op(self: PatchEmbed) -> nn.Module: + """Convert dynamic PatchEmbed to static PatchEmbed.""" + self.check_if_mutables_fixed() + assert self.mutable_embed_dims is not None + + weight, bias = self._get_dynamic_params() + static_patch_embed = self.static_op_factory( + img_size=self.img_size, + in_channels=3, + embed_dims=self.mutable_embed_dims.activated_channels) + + static_patch_embed.projection.weight = nn.Parameter(weight.clone()) + static_patch_embed.projection.bias = nn.Parameter(bias.clone()) + + return static_patch_embed + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return PatchEmbed + + @classmethod + def convert_from(cls, module) -> nn.Module: + """Convert a PatchEmbed to a DynamicPatchEmbed.""" + + dynamic_patch_embed = cls( + img_size=module.img_size, + in_channels=3, + embed_dims=module.embed_dims, + norm_cfg=None, + conv_cfg=None, + init_cfg=None) + + # TODO mutable_attr should be inherited from its `__base__` class + dynamic_patch_embed.projection = module.projection + dynamic_patch_embed.norm = module.norm + + return dynamic_patch_embed + + def forward(self, x: Tensor) -> Tensor: + """Forward of dynamic patch embed.""" + weight, bias = self._get_dynamic_params() + x = F.conv2d( + x, + weight, + bias, + stride=16, + padding=self.projection.padding, + dilation=self.projection.dilation).flatten(2).transpose(1, 2) + + if self.norm is not None: + x = self.norm(x) + + return x diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_function.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_function.py new file mode 100755 index 000000000..6e5761eac --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_function.py @@ -0,0 +1,61 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional, Tuple + +import torch +import torch.nn as nn + +from mmrazor.models.mutables.base_mutable import BaseMutable +from mmrazor.registry import MODELS +from ...ops import InputResizer +from ..mixins.dynamic_mixins import DynamicResizeMixin + + +@MODELS.register_module() +class DynamicInputResizer(InputResizer, DynamicResizeMixin): + """Dynamic InputResizer Module. + + Note: + Arguments for ``__init__`` of ``DynamicInputResizer`` is totally same + as :obj:`mmrazor.models.architectures.InputResizer`. + Attributes: + mutable_attrs (ModuleDict[str, BaseMutable]): Mutable attributes, + such as `InputResizer`. The key of the dict must in + ``accepted_mutable_attrs``. + """ + + mutable_attrs: nn.ModuleDict + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.mutable_attrs: Dict[str, Optional[BaseMutable]] = nn.ModuleDict() + + def forward(self, + x: torch.Tensor, + size=Optional[Tuple[int, int]]) -> torch.Tensor: + self._size = self.get_dynamic_shape() + + if not self._size: + self._size = size + + return super().forward(x, self._size) + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return InputResizer + + @classmethod + def convert_from(cls, module: InputResizer): + """Convert a InputResizer to a DynamicInputResizer. + + Args: + module (:obj:`mmrazor.models.architectures.InputResizer`): + The original InputResizer module. + """ + dynamic_seq = cls( + interpolation_type=module._interpolation_type, + align_corners=module._align_corners, + scale_factor=module._scale_factor) + + return dynamic_seq diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_linear.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_linear.py new file mode 100755 index 000000000..4faa0c8b7 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_linear.py @@ -0,0 +1,53 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict + +import torch.nn as nn +import torch.nn.functional as F +from torch import Tensor + +from mmrazor.models.mutables.base_mutable import BaseMutable +from ..mixins import DynamicLinearMixin + + +class DynamicLinear(nn.Linear, DynamicLinearMixin): + """Dynamic Linear OP. + + Note: + Arguments for ``__init__`` of ``DynamicLinear`` is totally same as + :obj:`torch.nn.Linear`. + + Attributes: + mutable_in_features (BaseMutable, optional): Mutable for controlling + ``in_features``. + mutable_out_features (BaseMutable, optional): Mutable for controlling + ``out_features``. + """ + accepted_mutable_attrs = {'in_features', 'out_features'} + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.mutable_attrs: Dict[str, BaseMutable] = nn.ModuleDict() + + @property + def static_op_factory(self): + return nn.Linear + + @classmethod + def convert_from(cls, module): + """Convert a nn.Linear module to a DynamicLinear. + + Args: + module (:obj:`torch.nn.Linear`): The original Linear module. + """ + dynamic_linear = cls( + in_features=module.in_features, + out_features=module.out_features, + bias=True if module.bias is not None else False) + return dynamic_linear + + def forward(self, input: Tensor) -> Tensor: + """Forward of dynamic linear OP.""" + weight, bias = self.get_dynamic_params() + + return F.linear(input, weight, bias) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_multi_head_attention.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_multi_head_attention.py new file mode 100755 index 000000000..8dcd6de3c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_multi_head_attention.py @@ -0,0 +1,279 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import logging +from typing import Dict, Set, Tuple + +import torch.nn as nn +import torch.nn.functional as F +from mmengine import print_log +from torch import Tensor + +from mmrazor.models.architectures.ops import MultiheadAttention +from mmrazor.models.mutables.base_mutable import BaseMutable +from ..mixins import DynamicChannelMixin +from .dynamic_relative_position import DynamicRelativePosition2D # noqa: E501 + + +class DynamicMultiheadAttention(MultiheadAttention, DynamicChannelMixin): + """Dynamic Multihead Attention with iRPE.. + + Note: + Arguments for ``__init__`` of ``DynamicMultiheadAttention`` is + totally same as + :obj:`mmrazor.models.architectures.MultiheadAttention`. + Attributes: + mutable_attrs (ModuleDict[str, BaseMutable]): Mutable attributes, + such as `num_heads`〠`embed_dims`〠`q_embed_dims`. + The key of the dict must in ``accepted_mutable_attrs``. + """ + + mutable_attrs: nn.ModuleDict + relative_position: bool + max_relative_position: int + w_qs: nn.Linear + w_ks: nn.Linear + w_vs: nn.Linear + embed_dims: int + q_embed_dims: int + proj: nn.Linear + attn_drop_rate: float + accepted_mutable_attrs: Set[str] = { + 'num_heads', 'embed_dims', 'q_embed_dims' + } + attr_mappings: Dict[str, str] = { + 'in_channels': 'embed_dims', + 'out_channels': 'q_embed_dims', + } + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.mutable_attrs: Dict[str, BaseMutable] = nn.ModuleDict() + + # dynamic image relative position encoding + if self.relative_position: + self.rel_pos_embed_k = DynamicRelativePosition2D( + self.head_dims, self.max_relative_position) + self.rel_pos_embed_v = DynamicRelativePosition2D( + self.head_dims, self.max_relative_position) + + @property + def mutable_num_heads(self): + """Mutable number of heads.""" + assert hasattr(self, 'mutable_attrs') + return self.mutable_attrs['num_heads'] + + @property + def mutable_embed_dims(self): + """Mutable embedding dimension.""" + assert hasattr(self, 'mutable_attrs') + return self.mutable_attrs['embed_dims'] + + @property + def mutable_q_embed_dims(self): + """Mutable intermediate embedding dimension.""" + assert hasattr(self, 'mutable_attrs') + return self.mutable_attrs['q_embed_dims'] + + def register_mutable_attr(self, attr: str, mutable: BaseMutable): + """Register attribute of mutable.""" + self.check_mutable_attr_valid(attr) + if attr in self.attr_mappings: + attr_map = self.attr_mappings[attr] + assert attr_map in self.accepted_mutable_attrs + # if hasattr(self, 'mutable_attrs'): + if attr_map in self.mutable_attrs: + print_log( + f'{attr_map}({attr}) is already in `mutable_attrs`', + level=logging.WARNING) + else: + self._register_mutable_attr(attr_map, mutable) + elif attr in self.accepted_mutable_attrs: + self._register_mutable_attr(attr, mutable) + else: + raise NotImplementedError + + def _register_mutable_attr(self, attr: str, mutable: BaseMutable): + """Register `embed_dims` `q_embed_dims` `num_heads`""" + if attr == 'num_heads': + self._register_mutable_num_heads(mutable) + elif attr == 'embed_dims': + self._register_mutable_embed_dims(mutable) + elif attr == 'q_embed_dims': + self._register_mutable_q_embed_dims(mutable) + else: + raise NotImplementedError + + def _register_mutable_num_heads(self, mutable_num_heads): + """Register the mutable number of heads.""" + assert hasattr(self, 'mutable_attrs') + current_choice = mutable_num_heads.current_choice + if current_choice > self.num_heads: + raise ValueError( + f'Expect value of mutable to be smaller or equal than ' + f'{self.num_heads} as `num_heads`, but got: {current_choice}.') + + self.mutable_attrs['num_heads'] = mutable_num_heads + + def _register_mutable_embed_dims(self, mutable_embed_dims): + """Register mutable embedding dimension.""" + assert hasattr(self, 'mutable_attrs') + mask_size = mutable_embed_dims.current_mask.size(0) + if mask_size != self.embed_dims: + raise ValueError( + f'Expect mask size of mutable to be {self.embed_dims} as ' + f'`embed_dims`, but got: {mask_size}.') + + self.mutable_attrs['embed_dims'] = mutable_embed_dims + + def _register_mutable_q_embed_dims(self, mutable_q_embed_dims): + """Register intermediate mutable embedding dimension.""" + assert hasattr(self, 'mutable_attrs') + self.mutable_attrs['q_embed_dims'] = mutable_q_embed_dims + + def _get_dynamic_proj_params(self, w: nn.Linear) -> Tuple[Tensor, Tensor]: + """Get parameters of dynamic projection. + + Note: + The input dimension is decided by `mutable_q_embed_dims`. + The output dimension is decided by `mutable_embed_dims`. + """ + # TODO support mask + if self.mutable_embed_dims is None and \ + self.mutable_q_embed_dims is None: + return w.weight, w.bias + + if self.mutable_q_embed_dims is not None: + in_features = self.mutable_q_embed_dims.activated_channels + else: + in_features = self.embed_dims + + if self.mutable_embed_dims is not None: + out_features = self.mutable_embed_dims.activated_channels + else: + out_features = self.embed_dims + + weight = w.weight[:out_features, :in_features] + bias = w.bias[:out_features] if w.bias is not None else None + + return weight, bias + + def _get_dynamic_qkv_params(self, w: nn.Linear) -> Tuple[Tensor, Tensor]: + """Get parameters of dynamic QKV. + + Note: + The output dimension is decided by `mutable_q_embed_dims`. + The input dimension is decided by `mutable_embed_dims`. + """ + # TODO support mask later + if self.mutable_q_embed_dims is None and \ + self.mutable_embed_dims is None: + return w.weight, w.bias + + if self.mutable_embed_dims is not None: + in_features = self.mutable_embed_dims.activated_channels + else: + in_features = self.embed_dims + + if self.mutable_q_embed_dims is not None: + out_features = self.mutable_q_embed_dims.activated_channels + else: + out_features = self.mutable_q_embed_dims + + weight = w.weight[:out_features, :in_features] + bias = w.bias[:out_features] if w.bias is not None else None + + return weight, bias + + def to_static_op(self) -> MultiheadAttention: + """Convert dynamic MultiheadAttention to static one.""" + self.check_if_mutables_fixed() + + embed_dims = self.mutable_embed_dims.activated_channels + num_heads = self.mutable_num_heads.current_choice + + q_w, q_b = self._get_dynamic_qkv_params(self.w_qs) + k_w, k_b = self._get_dynamic_qkv_params(self.w_ks) + v_w, v_b = self._get_dynamic_qkv_params(self.w_vs) + + proj_w, proj_b = self._get_dynamic_proj_params(self.proj) + + static_mha = MultiheadAttention( + embed_dims=embed_dims, + num_heads=num_heads, + input_dims=None, + relative_position=self.relative_position, + max_relative_position=self.max_relative_position) + + static_mha.w_qs.weight = nn.Parameter(q_w.clone()) + static_mha.w_qs.bias = nn.Parameter(q_b.clone()) + + static_mha.w_ks.weight = nn.Parameter(k_w.clone()) + static_mha.w_ks.bias = nn.Parameter(k_b.clone()) + + static_mha.w_vs.weight = nn.Parameter(v_w.clone()) + static_mha.w_vs.bias = nn.Parameter(v_b.clone()) + + static_mha.proj.weight = nn.Parameter(proj_w.clone()) + static_mha.proj.bias = nn.Parameter(proj_b.clone()) + + if self.relative_position: + static_mha.rel_pos_embed_k = self.rel_pos_embed_k.to_static_op() + static_mha.rel_pos_embed_v = self.rel_pos_embed_v.to_static_op() + + return static_mha + + @classmethod + def convert_from(cls, module): + """Convert the static module to dynamic one.""" + dynamic_mha = cls( + embed_dims=module.embed_dims, + num_heads=module.num_heads, + ) + return dynamic_mha + + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return MultiheadAttention + + def forward(self, x: Tensor) -> Tensor: + """Forward of dynamic MultiheadAttention.""" + B, N = x.shape[0], x.shape[1] + q_w, q_b = self._get_dynamic_qkv_params(self.w_qs) + k_w, k_b = self._get_dynamic_qkv_params(self.w_ks) + v_w, v_b = self._get_dynamic_qkv_params(self.w_vs) + + q_embed_dims = self.mutable_q_embed_dims.activated_channels + num_heads = self.mutable_num_heads.current_choice + + q = F.linear(x, q_w, q_b).view(B, N, num_heads, + q_embed_dims // num_heads) + k = F.linear(x, k_w, k_b).view(B, N, num_heads, + q_embed_dims // num_heads) + v = F.linear(x, v_w, v_b).view(B, N, num_heads, + q_embed_dims // num_heads) + + q, k, v = q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2) + + attn = (q @ k.transpose(-2, -1)) * self.scale + + if self.relative_position: + r_p_k = self.rel_pos_embed_k(N, N) + attn = attn + (q.permute(2, 0, 1, 3).reshape(N, num_heads * B, -1) # noqa: E501 + @ r_p_k.transpose(2, 1)) \ + .transpose(1, 0).reshape(B, num_heads, N, N) * self.scale + + attn = attn.softmax(dim=-1) + attn = self.attn_drop(attn) + x = (attn @ v).transpose(1, 2).reshape(B, N, -1) + + if self.relative_position: + r_p_v = self.rel_pos_embed_v(N, N) + attn_1 = attn.permute(2, 0, 1, 3).reshape(N, B * num_heads, -1) + x = x + (attn_1 @ r_p_v).transpose(1, 0).reshape( + B, num_heads, N, -1).transpose(2, 1).reshape(B, N, -1) + + # proj + weight, bias = self._get_dynamic_proj_params(self.proj) + x = F.linear(x, weight, bias) + x = self.proj_drop(x) + return x diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_norm.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_norm.py new file mode 100755 index 000000000..eb5dd3b75 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_norm.py @@ -0,0 +1,482 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from functools import partial +from typing import Any, Callable, Dict, List, Optional, Tuple + +import torch +import torch.nn as nn +import torch.nn.functional as F +from mmengine.model.utils import _BatchNormXd +from torch import Tensor +from torch.nn import LayerNorm +from torch.nn.modules._functions import SyncBatchNorm as sync_batch_norm +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.models.mutables.base_mutable import BaseMutable +from mmrazor.registry import MODELS +from ..mixins import DynamicBatchNormMixin, DynamicLayerNormMixin + +PartialType = Callable[[Any, Optional[nn.Parameter]], Tuple] + + +class _DynamicBatchNorm(_BatchNorm, DynamicBatchNormMixin): + """Dynamic BatchNormxd OP. + + Note: + Arguments for ``__init__`` of ``DynamicBatchNormxd`` is totally same as + :obj:`torch.nn.BatchNormxd`. + + Attributes: + mutable_attrs (ModuleDict[str, BaseMutable]): Mutable attributes, + such as `num_features`. The key of the dict must in + ``accepted_mutable_attrs``. + """ + accepted_mutable_attrs = {'num_features'} + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.mutable_attrs: Dict[str, Optional[BaseMutable]] = nn.ModuleDict() + + @classmethod + def convert_from(cls, module: _BatchNorm): + """Convert a _BatchNorm module to a DynamicBatchNorm. + + Args: + module (:obj:`torch.nn._BatchNorm`): The original BatchNorm module. + """ + dynamic_bn = cls( + num_features=module.num_features, + eps=module.eps, + momentum=module.momentum, + affine=module.affine, + track_running_stats=module.track_running_stats) + + return dynamic_bn + + def forward(self, input: Tensor) -> Tensor: + """Forward of dynamic BatchNormxd OP.""" + self._check_input_dim(input) + + if self.momentum is None: + exponential_average_factor = 0.0 + else: + exponential_average_factor = self.momentum + + if self.training and self.track_running_stats: + if self.num_batches_tracked is not None: # type: ignore + self.num_batches_tracked = \ + self.num_batches_tracked + 1 # type: ignore + if self.momentum is None: # use cumulative moving average + exponential_average_factor = 1.0 / float( + self.num_batches_tracked) + else: # use exponential moving average + exponential_average_factor = self.momentum + + if self.training: + bn_training = True + else: + bn_training = (self.running_mean is None) and (self.running_var is + None) + + running_mean, running_var, weight, bias = self.get_dynamic_params() + + out = F.batch_norm(input, running_mean, running_var, weight, bias, + bn_training, exponential_average_factor, self.eps) + + # copy changed running statistics + if self.training and self.track_running_stats: + out_mask = self._get_num_features_mask() + self.running_mean.masked_scatter_(out_mask, running_mean) + self.running_var.masked_scatter_(out_mask, running_var) + + return out + + +@MODELS.register_module() +class DynamicBatchNorm1d(_DynamicBatchNorm): + """Dynamic BatchNorm1d OP.""" + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return nn.BatchNorm1d + + def _check_input_dim(self, input: Tensor) -> None: + """Check if input dimension is valid.""" + if input.dim() != 2 and input.dim() != 3: + raise ValueError('expected 2D or 3D input (got {}D input)'.format( + input.dim())) + + +@MODELS.register_module() +class DynamicBatchNorm2d(_DynamicBatchNorm): + """Dynamic BatchNorm2d OP.""" + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return nn.BatchNorm2d + + def _check_input_dim(self, input: Tensor) -> None: + """Check if input dimension is valid.""" + if input.dim() != 4: + raise ValueError('expected 4D input (got {}D input)'.format( + input.dim())) + + +@MODELS.register_module() +class DynamicBatchNorm3d(_DynamicBatchNorm): + """Dynamic BatchNorm3d OP.""" + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return nn.BatchNorm3d + + def _check_input_dim(self, input: Tensor) -> None: + """Check if input dimension is valid.""" + if input.dim() != 5: + raise ValueError('expected 5D input (got {}D input)'.format( + input.dim())) + + +class SwitchableBatchNorm2d(DynamicBatchNorm2d): + """A switchable DynamicBatchNorm2d. It mmploys independent batch + normalization for different switches in a slimmable network. + + To train slimmable networks, ``SwitchableBatchNorm2d`` privatizes all batch + normalization layers for each switch in a slimmable network. Compared with + the naive training approach, it solves the problem of feature aggregation + inconsistency between different switches by independently normalizing the + feature mean and variance during testing. + """ + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.candidate_bn = nn.ModuleDict() + + def init_candidates(self, candidates: List): + """Initialize candicates.""" + assert len(self.candidate_bn) == 0 + self._check_candidates(candidates) + for num in candidates: + self.candidate_bn[str(num)] = nn.BatchNorm2d( + num, self.eps, self.momentum, self.affine, + self.track_running_stats) + + def forward(self, input: Tensor) -> Tensor: + """Forward.""" + choice_num = self.activated_channel_num() + if choice_num == self.num_features: + return super().forward(input) + else: + assert str(choice_num) in self.candidate_bn + return self.candidate_bn[str(choice_num)](input) + + def to_static_op(self: _BatchNorm) -> nn.Module: + """Convert to a normal BatchNorm.""" + choice_num = self.activated_channel_num() + if choice_num == self.num_features: + return super().to_static_op() + else: + assert str(choice_num) in self.candidate_bn + return self.candidate_bn[str(choice_num)] + + # private methods + + def activated_channel_num(self): + """The number of activated channels.""" + mask = self._get_num_features_mask() + choice_num = (mask == 1).sum().item() + return choice_num + + def _check_candidates(self, candidates: List): + """Check if candidates aviliable.""" + for value in candidates: + assert isinstance(value, int) + assert 0 < value <= self.num_features + + @property + def static_op_factory(self): + """Return initializer of static op.""" + return nn.BatchNorm2d + + +@MODELS.register_module() +class DynamicLayerNorm(LayerNorm, DynamicLayerNormMixin): + """Applies Layer Normalization over a mini-batch of inputs according to the + `mutable_num_channels` dynamically. + + Note: + Arguments for ``__init__`` of ``DynamicLayerNorm`` is totally same as + :obj:`torch.nn.LayerNorm`. + Attributes: + mutable_attrs (ModuleDict[str, BaseMutable]): Mutable attributes, + such as `num_features`. The key of the dict must in + ``accepted_mutable_attrs``. + """ + accepted_mutable_attrs = {'num_features'} + + def __init__(self, *args, **kwargs): + super(DynamicLayerNorm, self).__init__(*args, **kwargs) + + self.mutable_attrs: Dict[str, Optional[BaseMutable]] = nn.ModuleDict() + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return LayerNorm + + @classmethod + def convert_from(cls, module: LayerNorm): + """Convert a _BatchNorm module to a DynamicBatchNorm. + + Args: + module (:obj:`torch.nn._BatchNorm`): The original BatchNorm module. + """ + dynamic_ln = cls( + normalized_shape=module.normalized_shape, + eps=module.eps, + elementwise_affine=module.elementwise_affine) + + return dynamic_ln + + def forward(self, input: Tensor) -> Tensor: + """Slice the parameters according to `mutable_num_channels`, and + forward.""" + self._check_input_dim(input) + + weight, bias = self.get_dynamic_params() + self.normalized_shape = ( + self.mutable_num_features.activated_channels, ) + + return F.layer_norm(input, self.normalized_shape, weight, bias, + self.eps) + + def _check_input_dim(self, input: Tensor) -> None: + """Check if input dimension is valid.""" + if input.dim() != 3: + raise ValueError('expected 3D input (got {}D input)'.format( + input.dim())) + + +class DynamicSyncBatchNorm(nn.SyncBatchNorm, DynamicBatchNormMixin): + """DynamicOp for sync bn.""" + + def __init__(self, + num_features: int, + eps: float = 0.00001, + momentum: float = 0.1, + affine: bool = True, + track_running_stats: bool = True, + process_group: Optional[Any] = None) -> None: + super().__init__(num_features, eps, momentum, affine, + track_running_stats, process_group) + self.mutable_attrs: Dict[str, Optional[BaseMutable]] = nn.ModuleDict() + + @classmethod + def convert_from(cls, module): + return cls(module.num_features, module.eps, module.momentum, + module.affine, module.track_running_stats, + module.process_group) + + @property + def static_op_factory(self): + return nn.SyncBatchNorm + + def forward(self, input: Tensor) -> Tensor: + # currently only GPU input is supported + if not input.is_cuda: + raise ValueError( + 'SyncBatchNorm expected input tensor to be on GPU') + + self._check_input_dim(input) + if hasattr(self, '_check_non_zero_input_channels'): + self._check_non_zero_input_channels(input) + + # exponential_average_factor is set to self.momentum + # (when it is available) only so that it gets updated + # in ONNX graph when this node is exported to ONNX. + if self.momentum is None: + exponential_average_factor = 0.0 + else: + exponential_average_factor = self.momentum + + if self.training and self.track_running_stats: + assert self.num_batches_tracked is not None + self.num_batches_tracked.add_(1) + if self.momentum is None: # use cumulative moving average + exponential_average_factor = (1.0 / + self.num_batches_tracked.item()) + else: # use exponential moving average + exponential_average_factor = self.momentum + r""" + Decide whether the mini-batch stats should be used for normalization + rather than the buffers. + Mini-batch stats are used in training mode, and in eval mode when + buffers are None. + """ + if self.training: + bn_training = True + else: + bn_training = (self.running_mean is None) and (self.running_var is + None) + r""" + Buffers are only updated if they are to be tracked and we are in + training mode. Thus they only need to be + passed when the update should occur (i.e. in training mode when + they are tracked), or when buffer stats are + used for normalization (i.e. in eval mode when buffers are not None). + """ + # If buffers are not to be tracked, ensure that they won't be updated + running_mean = ( + self.running_mean + if not self.training or self.track_running_stats else None) + running_var = ( + self.running_var + if not self.training or self.track_running_stats else None) + + # Don't sync batchnorm stats in inference mode (model.eval()). + need_sync = (bn_training and self.training) + if need_sync: + process_group = torch.distributed.group.WORLD + if self.process_group: + process_group = self.process_group + world_size = torch.distributed.get_world_size(process_group) + need_sync = world_size > 1 + + running_mean, running_var, weight, bias = self.get_dynamic_params() + + # fallback to framework BN when synchronization is not necessary + if not need_sync: + out = F.batch_norm( + input, + running_mean, + running_var, + weight, + bias, + bn_training, + exponential_average_factor, + self.eps, + ) + else: + assert bn_training + out = sync_batch_norm.apply( + input, + weight, + bias, + running_mean, + running_var, + self.eps, + exponential_average_factor, + process_group, + world_size, + ) + + # copy changed running statistics + if self.training and self.track_running_stats: + out_mask = self._get_num_features_mask() + self.running_mean.masked_scatter_(out_mask, running_mean) + self.running_var.masked_scatter_(out_mask, running_var) + + return out + + +class DynamicBatchNormXd(_DynamicBatchNorm): + """Dynamic op for _DynamicBatchNorm.""" + + @property + def static_op_factory(self): + return _BatchNormXd + + def _check_input_dim(self, input: torch.Tensor): + return + + +@MODELS.register_module() +class DMCPBatchNorm2d(DynamicBatchNorm2d): + accepted_mutable_attrs = {'num_features'} + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.mutable_attrs: Dict[str, Optional[BaseMutable]] = nn.ModuleDict() + + def forward(self, + input: Tensor, + arch_param=None, + arch_attr=None) -> Tensor: + """Forward of dynamic DMCPBatchNorm2d.""" + out = self.forward_batchnorm(input) + if arch_param is not None: + out = self.forward_arch_param(out, arch_param, arch_attr) + return out + + def forward_batchnorm(self, input: Tensor) -> Tensor: + """Forward of BatchNorm2d.""" + self._check_input_dim(input) + + if self.momentum is None: + exponential_average_factor = 0.0 + else: + exponential_average_factor = self.momentum + + if self.training and self.track_running_stats: + if self.num_batches_tracked is not None: # type: ignore + self.num_batches_tracked = \ + self.num_batches_tracked + 1 # type: ignore + if self.momentum is None: # use cumulative moving average + exponential_average_factor = 1.0 / float( + self.num_batches_tracked) + else: # use exponential moving average + exponential_average_factor = self.momentum + + if self.training: + bn_training = True + else: + bn_training = (self.running_mean is None) and (self.running_var is + None) + + running_mean, running_var, weight, bias = self.get_dynamic_params() + + out = F.batch_norm(input, running_mean, running_var, weight, bias, + bn_training, exponential_average_factor, self.eps) + + # copy changed running statistics + if self.training and self.track_running_stats: + out_mask = self._get_num_features_mask() + self.running_mean.masked_scatter_(out_mask, running_mean) + self.running_var.masked_scatter_(out_mask, running_var) + + return out + + def forward_arch_param(self, input: Tensor, arch_param, + arch_attr) -> Tensor: + """Forward of arch parameters.""" + size_x = input.size() + (group_size, num_groups, min_ch) = arch_attr + + if num_groups == 0 or size_x[1] == min_ch: + return input + + arch = torch.clamp(arch_param, min=0) + prob_distribute = torch.exp(-arch) + + prob = torch.cumprod(prob_distribute, dim=0).view(num_groups, 1) + tp_x = input.transpose(0, 1).contiguous() + tp_group_x = tp_x[min_ch:] + + size_tp_group = tp_group_x.size() + num_groups = size_tp_group[0] // group_size + tp_group_x = tp_group_x.view(num_groups, -1) * prob[:num_groups] + tp_group_x = tp_group_x.view(size_tp_group) + + out = torch.cat([tp_x[:min_ch], tp_group_x]).transpose(0, + 1).contiguous() + return out + + def set_forward_args(self, arch_param: nn.Parameter, + arch_attr: Optional[Tuple]) -> None: + """Interface for modifying the arch_param using partial.""" + forward_with_default_args: PartialType = \ + partial(self.forward, arch_param=arch_param, arch_attr=arch_attr) + setattr(self, 'forward', forward_with_default_args) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_relative_position.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_relative_position.py new file mode 100755 index 000000000..572880a43 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_relative_position.py @@ -0,0 +1,154 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import logging +from typing import Dict, Set + +import torch +from mmengine import print_log +from torch import Tensor, nn + +from mmrazor.models.architectures.ops import RelativePosition2D +from mmrazor.models.mutables.base_mutable import BaseMutable +from ..mixins import DynamicChannelMixin + + +class DynamicRelativePosition2D(RelativePosition2D, DynamicChannelMixin): + """Searchable RelativePosition module. + + Note: + Arguments for ``__init__`` of ``DynamicRelativePosition2D`` is totally + same as :obj:`mmrazor.models.architectures.RelativePosition2D`. + Attributes: + mutable_attrs (ModuleDict[str, BaseMutable]): Mutable attributes, + such as `head_dims`. The key of the dict must in + ``accepted_mutable_attrs``. + """ + + mutable_attrs: nn.ModuleDict + head_dims: int + max_relative_position: int + embeddings_table_v: nn.Parameter + embeddings_table_h: nn.Parameter + accepted_mutable_attrs: Set[str] = {'head_dims'} + attr_mappings: Dict[str, str] = { + 'in_channels': 'head_dims', + 'out_channels': 'head_dims', + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.mutable_attrs: Dict[str, BaseMutable] = nn.ModuleDict() + + @property + def mutable_head_dims(self): + """Mutable head dimension.""" + assert hasattr(self, 'mutable_attrs') + return self.mutable_attrs['head_dims'] + + def register_mutable_attr(self, attr: str, mutable: BaseMutable): + """Register attribute of mutable.""" + self.check_mutable_attr_valid(attr) + if attr in self.attr_mappings: + attr_map = self.attr_mappings[attr] + assert attr_map in self.accepted_mutable_attrs + if attr_map in self.mutable_attrs: + print_log( + f'{attr_map}({attr}) is already in `mutable_attrs`', + level=logging.WARNING) + else: + self._register_mutable_attr(attr_map, mutable) + elif attr in self.accepted_mutable_attrs: + self._register_mutable_attr(attr, mutable) + else: + raise NotImplementedError + + def _register_mutable_attr(self, attr, mutable): + """Register `head_dims`""" + if attr == 'head_dims': + self._registry_mutable_head_dims(mutable) + else: + raise NotImplementedError + + def _registry_mutable_head_dims(self, + mutable_head_dims: BaseMutable) -> None: + """Register head dimension.""" + assert hasattr(self, 'mutable_attrs') + self.mutable_attrs['head_dims'] = mutable_head_dims + + def to_static_op(self) -> nn.Module: + """Convert dynamic RelativePosition2D to static One.""" + self.check_if_mutables_fixed() + assert self.mutable_head_dims is not None + + self.current_head_dim = self.mutable_head_dims.activated_channels + static_relative_position = self.static_op_factory( + self.current_head_dim) + static_relative_position.embeddings_table_v = \ + nn.Parameter( + self.embeddings_table_v[:, :self.current_head_dim].clone()) + static_relative_position.embeddings_table_h = \ + nn.Parameter( + self.embeddings_table_h[:, :self.current_head_dim].clone()) + + return static_relative_position + + @property + def static_op_factory(self): + """Corresponding Pytorch OP.""" + return RelativePosition2D + + @classmethod + def convert_from(cls, module): + """Convert a RP to a dynamic RP.""" + dynamic_rp = cls( + head_dims=module.head_dims, + max_relative_position=module.max_relative_position) + return dynamic_rp + + def forward(self, length_q, length_k) -> Tensor: + """Forward of Dynamic Relative Position.""" + if self.mutable_head_dims is None: + self.current_head_dim = self.head_dims + else: + self.current_head_dim = self.mutable_head_dims.activated_channels + + self.sample_eb_table_h = self.embeddings_table_h[:, :self. + current_head_dim] + self.sample_eb_table_v = self.embeddings_table_v[:, :self. + current_head_dim] + + # remove the first cls token distance computation + length_q = length_q - 1 + length_k = length_k - 1 + range_vec_q = torch.arange(length_q) + range_vec_k = torch.arange(length_k) + # compute the row and column distance + distance_mat_v = ( + range_vec_k[None, :] // int(length_q**0.5) - + range_vec_q[:, None] // int(length_q**0.5)) + distance_mat_h = ( + range_vec_k[None, :] % int(length_q**0.5) - + range_vec_q[:, None] % int(length_q**0.5)) + distance_mat_clipped_v = torch.clamp(distance_mat_v, + -self.max_relative_position, + self.max_relative_position) + distance_mat_clipped_h = torch.clamp(distance_mat_h, + -self.max_relative_position, + self.max_relative_position) + + final_mat_v = distance_mat_clipped_v + self.max_relative_position + 1 + final_mat_h = distance_mat_clipped_h + self.max_relative_position + 1 + # pad the 0 which represent the cls token + final_mat_v = torch.nn.functional.pad(final_mat_v, (1, 0, 1, 0), + 'constant', 0) + final_mat_h = torch.nn.functional.pad(final_mat_h, (1, 0, 1, 0), + 'constant', 0) + + final_mat_v = torch.LongTensor(final_mat_v) + final_mat_h = torch.LongTensor(final_mat_h) + # get the embeddings with the corresponding distance + + embeddings = self.sample_eb_table_v[final_mat_v] + \ + self.sample_eb_table_h[final_mat_h] + + return embeddings diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/group_fisher_ops.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/group_fisher_ops.py new file mode 100755 index 000000000..c4a635607 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/group_fisher_ops.py @@ -0,0 +1,11 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This file includes the modules in the impl folder. + +As it only records impl modules, it is not initialized automatically. +""" +from mmrazor.implementations.pruning.group_fisher import \ + GroupFisherConv2d # noqa +from mmrazor.implementations.pruning.group_fisher import \ + GroupFisherLinear # noqa +from mmrazor.implementations.pruning.group_fisher import \ + GroupFisherMixin # noqa diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/__init__.py new file mode 100755 index 000000000..a9da44d6e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .dynamic_linear_head import DynamicLinearClsHead # noqa: F401 + +__all__ = ['DynamicLinearClsHead'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/dynamic_linear_head.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/dynamic_linear_head.py new file mode 100755 index 000000000..6a6a21d4c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/dynamic_linear_head.py @@ -0,0 +1,85 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import abstractmethod +from typing import Optional, Tuple + +import torch + +try: + from mmcls.models import ClsHead +except ImportError: + from mmrazor.utils import get_placeholder + ClsHead = get_placeholder('mmcls') + +from mmrazor.models.mutables.base_mutable import BaseMutable +from mmrazor.models.mutables.mutable_channel import MutableChannelContainer +from mmrazor.models.mutables.mutable_channel.units import \ + OneShotMutableChannelUnit +from mmrazor.registry import MODELS +from ..bricks.dynamic_linear import DynamicLinear + + +class DynamicHead: + + @abstractmethod + def connect_with_backbone(self, + backbone_output_mutable: BaseMutable) -> None: + """Connect with Dynamic Backbone.""" + ... + + +@MODELS.register_module() +class DynamicLinearClsHead(ClsHead, DynamicHead): + """Dynamic Linear classification head for Autoformer. + + Args: + num_classes (int): Number of classes. + in_channels (int): Number of input channels. + init_cfg (Optional[dict], optional): Init config. + Defaults to dict(type='Normal', + layer='DynamicLinear', std=0.01). + """ + + def __init__(self, + num_classes: int = 1000, + in_channels: int = 624, + init_cfg: Optional[dict] = dict( + type='Normal', layer='DynamicLinear', std=0.01), + **kwargs): + super().__init__(init_cfg=init_cfg, **kwargs) + + self.in_channels = in_channels + self.num_classes = num_classes + + if self.num_classes <= 0: + raise ValueError( + f'num_classes={num_classes} must be a positive integer') + + self.fc = DynamicLinear(self.in_channels, self.num_classes) + + def pre_logits(self, feats: Tuple[torch.Tensor]) -> torch.Tensor: + """The process before the final classification head. + + The input ``feats`` is a tuple of tensor, and each tensor is the + feature of a backbone stage. In ``LinearClsHead``, we just obtain the + feature of the last stage. + """ + # The LinearClsHead doesn't have other module, just return after + # unpacking. + return feats[-1] + + def forward(self, feats: Tuple[torch.Tensor]) -> torch.Tensor: + """The forward process.""" + pre_logits = self.pre_logits(feats) + # The final classification head. + cls_score = self.fc(pre_logits) + return cls_score + + def connect_with_backbone(self, + backbone_output_mutable: BaseMutable) -> None: + """Connect dynamic backbone.""" + + OneShotMutableChannelUnit._register_channel_container( + self, MutableChannelContainer) + + MutableChannelContainer.register_mutable_channel_to_module( + self.fc, backbone_output_mutable, False) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/__init__.py new file mode 100755 index 000000000..e97f7ad78 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/__init__.py @@ -0,0 +1,14 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .dynamic_conv_mixins import DynamicConvMixin +from .dynamic_layernorm_mixins import DynamicLayerNormMixin +from .dynamic_mixins import (DynamicBatchNormMixin, DynamicChannelMixin, + DynamicLinearMixin, DynamicMixin) + +__all__ = [ + 'DynamicChannelMixin', + 'DynamicBatchNormMixin', + 'DynamicLinearMixin', + 'DynamicMixin', + 'DynamicConvMixin', + 'DynamicLayerNormMixin', +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_conv_mixins.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_conv_mixins.py new file mode 100755 index 000000000..cf63ec11c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_conv_mixins.py @@ -0,0 +1,572 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import abstractmethod +from functools import partial +from itertools import repeat +from typing import Any, Callable, Iterable, Optional, Tuple, Union + +import torch +import torch.nn.functional as F +from torch import Tensor, nn +from torch.nn.modules.conv import _ConvNd + +from mmrazor.models.mutables.base_mutable import BaseMutable +from .dynamic_mixins import DynamicChannelMixin + +PartialType = Callable[[Any, Optional[nn.Parameter]], Any] + + +def _ntuple(n: int) -> Callable: # pragma: no cover + """Repeat a number n times.""" + + def parse(x): + if isinstance(x, Iterable): + return tuple(x) + return tuple(repeat(x, n)) + + return parse + + +def _get_current_kernel_pos(source_kernel_size: int, + target_kernel_size: int) -> Tuple[int, int]: + """Get position of current kernel size. + + Returns: + Tuple[int, int]: (upper left position, bottom right position) + """ + assert source_kernel_size >= target_kernel_size, \ + '`source_kernel_size` must greater or equal than `target_kernel_size`' + + center = source_kernel_size >> 1 + current_offset = target_kernel_size >> 1 + + start_offset = center - current_offset + end_offset = center + current_offset + 1 + + return start_offset, end_offset + + +def _get_same_padding(kernel_size: int, n_dims: int) -> Tuple[int]: + """Get same padding according to kernel size.""" + assert kernel_size & 1 + _pair = _ntuple(n_dims) + + return _pair(kernel_size >> 1) + + +class DynamicConvMixin(DynamicChannelMixin): + """A mixin class for Pytorch conv, which can mutate ``in_channels`` and + ``out_channels``. + + Note: + All subclass should implement ``conv_func``API. + """ + + @property + @abstractmethod + def conv_func(self: _ConvNd): + """The function that will be used in ``forward_mixin``.""" + pass + + def register_mutable_attr(self, attr, mutable): + + if attr == 'in_channels': + self._register_mutable_in_channels(mutable) + elif attr == 'out_channels': + self._register_mutable_out_channels(mutable) + else: + raise NotImplementedError + + def _register_mutable_in_channels( + self: _ConvNd, mutable_in_channels: BaseMutable) -> None: + """Mutate ``in_channels`` with given mutable. + + Args: + mutable_in_channels (BaseMutable): Mutable for controlling + ``in_channels``. + + Raises: + ValueError: Error if size of mask if not same as ``in_channels``. + """ + assert hasattr(self, 'mutable_attrs') + self.check_mutable_channels(mutable_in_channels) + mask_size = mutable_in_channels.current_mask.size(0) + if mask_size != self.in_channels: + raise ValueError( + f'Expect mask size of mutable to be {self.in_channels} as ' + f'`in_channels`, but got: {mask_size}.') + + self.mutable_attrs['in_channels'] = mutable_in_channels + + def _register_mutable_out_channels( + self: _ConvNd, mutable_out_channels: BaseMutable) -> None: + """Mutate ``out_channels`` with given mutable. + + Args: + mutable_out_channels (BaseMutable): Mutable for controlling + ``out_channels``. + + Raises: + ValueError: Error if size of mask if not same as ``out_channels``. + """ + assert hasattr(self, 'mutable_attrs') + self.check_mutable_channels(mutable_out_channels) + mask_size = mutable_out_channels.current_mask.size(0) + if mask_size != self.out_channels: + raise ValueError( + f'Expect mask size of mutable to be {self.out_channels} as ' + f'`out_channels`, but got: {mask_size}.') + + self.mutable_attrs['out_channels'] = mutable_out_channels + + @property + def mutable_in_channels(self: _ConvNd) -> Optional[BaseMutable]: + """Mutable related to input.""" + assert hasattr(self, 'mutable_attrs') + return getattr(self.mutable_attrs, 'in_channels', None) # type:ignore + + @property + def mutable_out_channels(self: _ConvNd) -> Optional[BaseMutable]: + """Mutable related to output.""" + assert hasattr(self, 'mutable_attrs') + return getattr(self.mutable_attrs, 'out_channels', None) # type:ignore + + def get_dynamic_params( + self: _ConvNd) -> Tuple[Tensor, Optional[Tensor], Tuple[int]]: + """Get dynamic parameters that will be used in forward process. + + Returns: + Tuple[Tensor, Optional[Tensor], Tuple[int]]: Sliced weight, bias + and padding. + """ + # slice in/out channel of weight according to + # mutable in_channels/out_channels + weight, bias = self._get_dynamic_params_by_mutable_channels( + self.weight, self.bias) + return weight, bias, self.padding + + def _get_dynamic_params_by_mutable_channels( + self: _ConvNd, weight: Tensor, + bias: Optional[Tensor]) -> Tuple[Tensor, Optional[Tensor]]: + """Get sliced weight and bias according to ``mutable_in_channels`` and + ``mutable_out_channels``. + + Returns: + Tuple[Tensor, Optional[Tensor]]: Sliced weight and bias. + """ + if 'in_channels' not in self.mutable_attrs and \ + 'out_channels' not in self.mutable_attrs: + return weight, bias + + if 'in_channels' in self.mutable_attrs: + mutable_in_channels = self.mutable_attrs['in_channels'] + in_mask = mutable_in_channels.current_mask.to(weight.device) + else: + in_mask = torch.ones(weight.size(1)).bool().to(weight.device) + + if 'out_channels' in self.mutable_attrs: + mutable_out_channels = self.mutable_attrs['out_channels'] + out_mask = mutable_out_channels.current_mask.to(weight.device) + else: + out_mask = torch.ones(weight.size(0)).bool().to(weight.device) + + if self.groups == 1: + weight = weight[out_mask][:, in_mask] + elif self.groups == self.in_channels == self.out_channels: + # depth-wise conv + weight = weight[out_mask] + else: + # group-wise conv + in_mask_ = in_mask.reshape([self.groups, -1]) # G in/G + in_per_group = in_mask_.sum(dim=-1)[0].item() + assert (in_mask_.sum(dim=-1) == in_per_group).all() + out_mask_ = out_mask.reshape([self.groups, -1]) # G out/G + out_per_group = out_mask_.sum(dim=-1)[0].item() + assert (out_mask_.sum(dim=-1) == out_per_group).all() + + mask = out_mask_.unsqueeze(-1) * in_mask_.unsqueeze( + -2) # G out/G in/G + mask = mask.flatten() + weight = weight.flatten(0, 1) + weight = weight[mask] + weight = weight.reshape( + [self.groups * out_per_group, in_per_group, *self.kernel_size]) + + bias = self.bias[out_mask] if self.bias is not None else None + return weight, bias + + def forward_mixin(self: _ConvNd, x: Tensor) -> Tensor: + """Forward of dynamic conv2d OP.""" + groups = self.groups + if self.groups == self.in_channels == self.out_channels: + groups = x.size(1) + weight, bias, padding = self.get_dynamic_params() + + return self.conv_func(x, weight, bias, self.stride, padding, + self.dilation, groups) + + def to_static_op(self: _ConvNd) -> nn.Conv2d: + """Convert dynamic conv2d to :obj:`torch.nn.Conv2d`. + + Returns: + torch.nn.Conv2d: :obj:`torch.nn.Conv2d` with sliced parameters. + """ + self.check_if_mutables_fixed() + + weight, bias, padding = self.get_dynamic_params() + groups = self.groups + if groups == self.in_channels == self.out_channels and \ + self.mutable_in_channels is not None: + mutable_in_channels = self.mutable_attrs['in_channels'] + groups = mutable_in_channels.current_mask.sum().item() + out_channels = weight.size(0) + in_channels = weight.size(1) * groups + + kernel_size = tuple(weight.shape[2:]) + + static_conv = self.static_op_factory( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=self.stride, + padding=padding, + padding_mode=self.padding_mode, + dilation=self.dilation, + groups=groups, + bias=True if bias is not None else False) + + static_conv.weight = nn.Parameter(weight) + if bias is not None: + static_conv.bias = nn.Parameter(bias) + + return static_conv + + +class BigNasConvMixin(DynamicConvMixin): + """A mixin class for Pytorch conv, which can mutate ``in_channels``, + ``out_channels`` and ``kernel_size``.""" + + def register_mutable_attr(self, attr, mutable): + + if attr == 'in_channels': + self._register_mutable_in_channels(mutable) + elif attr == 'out_channels': + self._register_mutable_out_channels(mutable) + elif attr == 'kernel_size': + self._register_mutable_kernel_size(mutable) + else: + raise NotImplementedError + + def _register_mutable_kernel_size( + self: _ConvNd, mutable_kernel_size: BaseMutable) -> None: + """Mutate ``kernel_size`` with given mutable. + + Args: + mutable_kernel_size (BaseMutable): Mutable for controlling + ``kernel_size``. + + Note: + ``kernel_size_seq`` must be provided if ``mutable_kernel_size`` + does not have ``choices`` attribute. + + Raises: + ValueError: Error if max choice of ``kernel_size_list`` + not same as ``kernel_size``. + """ + + kernel_size_seq = getattr(mutable_kernel_size, 'choices', None) + if kernel_size_seq is None or len(kernel_size_seq) == 0: + raise ValueError('kernel size sequence must be provided') + kernel_size_list = list(sorted(kernel_size_seq)) + + _pair = _ntuple(len(self.weight.shape) - 2) + max_kernel_size = _pair(kernel_size_list[-1]) + if max_kernel_size != self.kernel_size: + raise ValueError( + f'Expect max kernel size to be: {self.kernel_size}, ' + f'but got: {max_kernel_size}') + + self.kernel_size_list = kernel_size_list + self.mutable_attrs['kernel_size'] = mutable_kernel_size + + def get_dynamic_params( + self: _ConvNd) -> Tuple[Tensor, Optional[Tensor], Tuple[int]]: + """Get dynamic parameters that will be used in forward process. + + Returns: + Tuple[Tensor, Optional[Tensor], Tuple[int]]: Sliced weight, bias + and padding. + """ + # 1. slice kernel size of weight according to kernel size mutable + weight, padding = self._get_dynamic_params_by_mutable_kernel_size( + self.weight) + + # 2. slice in/out channel of weight according to mutable in_channels + # and mutable out channels. + weight, bias = self._get_dynamic_params_by_mutable_channels( + weight, self.bias) + return weight, bias, padding + + def _get_dynamic_params_by_mutable_kernel_size( + self: _ConvNd, weight: Tensor) -> Tuple[Tensor, Tuple]: + """Get sliced weight and bias according to ``mutable_in_channels`` and + ``mutable_out_channels``.""" + + if 'kernel_size' not in self.mutable_attrs \ + or self.kernel_size_list is None: + return weight, self.padding + + mutable_kernel_size = self.mutable_attrs['kernel_size'] + current_kernel_size = self.get_current_choice(mutable_kernel_size) + + n_dims = len(self.weight.shape) - 2 + current_padding: Union[Tuple[int], Tuple[int, int]] = \ + _get_same_padding(current_kernel_size, n_dims) + + _pair = _ntuple(len(self.weight.shape) - 2) + if _pair(current_kernel_size) == self.kernel_size: + return weight, current_padding + + start_offset, end_offset = _get_current_kernel_pos( + source_kernel_size=self.kernel_size[0], + target_kernel_size=current_kernel_size) + current_weight = \ + weight[:, :, start_offset:end_offset, start_offset:end_offset] + + return current_weight, current_padding + + +class OFAConvMixin(BigNasConvMixin): + """A mixin class for Pytorch conv, which can mutate ``in_channels``, + ``out_channels`` and ``kernel_size``.""" + + def _register_mutable_kernel_size( + self: _ConvNd, mutable_kernel_size: BaseMutable) -> None: + """Mutate ``kernel_size`` with given mutable and register + transformation matrix.""" + super()._register_mutable_kernel_size(mutable_kernel_size) + self._register_trans_matrix() + + def _register_trans_matrix(self: _ConvNd) -> None: + """Register transformation matrix that used in progressive + shrinking.""" + assert self.kernel_size_list is not None + + trans_matrix_names = [] + for i in range(len(self.kernel_size_list) - 1, 0, -1): + source_kernel_size = self.kernel_size_list[i] + target_kernel_size = self.kernel_size_list[i - 1] + trans_matrix_name = self._get_trans_matrix_name( + src=source_kernel_size, tar=target_kernel_size) + trans_matrix_names.append(trans_matrix_name) + # TODO support conv1d & conv3d + trans_matrix = nn.Parameter(torch.eye(target_kernel_size**2)) + self.register_parameter(name=trans_matrix_name, param=trans_matrix) + self._trans_matrix_names = trans_matrix_names + + @staticmethod + def _get_trans_matrix_name(src: int, tar: int) -> str: + """Get name of trans matrix.""" + return f'trans_matrix_{src}to{tar}' + + def _get_dynamic_params_by_mutable_kernel_size( + self: _ConvNd, weight: Tensor) -> Tuple[Tensor, Tuple]: + """Get sliced weight and bias according to ``mutable_in_channels`` and + ``mutable_out_channels``.""" + + if 'kernel_size' not in self.mutable_attrs: + return weight, self.padding + + mutable_kernel_size = self.mutable_attrs['kernel_size'] + current_kernel_size = self.get_current_choice(mutable_kernel_size) + + n_dims = len(self.weight.shape) - 2 + current_padding: Union[Tuple[int], Tuple[int, int]] = \ + _get_same_padding(current_kernel_size, n_dims) + + _pair = _ntuple(len(self.weight.shape) - 2) + if _pair(current_kernel_size) == self.kernel_size: + return weight, current_padding + + current_weight = weight[:, :, :, :] + for i in range(len(self.kernel_size_list) - 1, 0, -1): + source_kernel_size = self.kernel_size_list[i] + if source_kernel_size <= current_kernel_size: + break + target_kernel_size = self.kernel_size_list[i - 1] + trans_matrix = getattr( + self, + self._get_trans_matrix_name( + src=source_kernel_size, tar=target_kernel_size)) + + start_offset, end_offset = _get_current_kernel_pos( + source_kernel_size=source_kernel_size, + target_kernel_size=target_kernel_size) + target_weight = current_weight[:, :, start_offset:end_offset, + start_offset:end_offset] + target_weight = target_weight.reshape(-1, target_kernel_size**2) + target_weight = F.linear(target_weight, trans_matrix) + target_weight = target_weight.reshape( + weight.size(0), weight.size(1), target_kernel_size, + target_kernel_size) + + current_weight = target_weight + + return current_weight, current_padding + + +class FuseConvMixin(DynamicConvMixin): + """A mixin class for fuse conv, which can mutate ``in_channels``, + ``out_channels`` .""" + + def set_forward_args(self, choice: Tensor) -> None: + """Interface for modifying the arch_param using partial.""" + param_channel_with_default_args: PartialType = \ + partial( + self._get_dynamic_params_by_mutable_channels_choice, + choice=choice) + setattr(self, '_get_dynamic_params_by_mutable_channels', + param_channel_with_default_args) + + def get_dynamic_params( + self: _ConvNd) -> Tuple[Tensor, Optional[Tensor], Tuple[int]]: + """Get dynamic parameters that will be used in forward process. + + Returns: + Tuple[Tensor, Optional[Tensor], Tuple[int]]: Sliced weight, bias + and padding. + """ + # slice in/out channel of weight according to mutable in_channels + # and mutable out channels. + weight, bias = self._get_dynamic_params_by_mutable_channels( + self.weight, self.bias) + return weight, bias, self.padding + + def _get_dynamic_params_by_mutable_channels_choice( + self: _ConvNd, weight: Tensor, bias: Optional[Tensor], + choice: Tensor) -> Tuple[Tensor, Optional[Tensor]]: + """Get sliced weight and bias according to ``mutable_in_channels`` and + ``mutable_out_channels``. + + Returns: + Tuple[Tensor, Optional[Tensor]]: Sliced weight and bias. + """ + + mutable_in_channels = 0 + mutable_out_channels = 0 + + if 'in_channels' in self.mutable_attrs: + mutable_in_channels = self.mutable_attrs[ + 'in_channels'].current_mask.sum().item() + + if 'out_channels' in self.mutable_attrs: + mutable_out_channels = self.mutable_attrs[ + 'out_channels'].current_mask.sum().item() + + if mutable_in_channels == 0: + mutable_in_channels = self.in_channels + if mutable_out_channels == 0: + mutable_out_channels = self.out_channels + + # if channel not in mutable_attrs or unchanged + if mutable_in_channels == self.in_channels and \ + mutable_out_channels == self.out_channels: + return weight, bias + + weight = self.weight[:, 0:mutable_in_channels, :, :] + if self.groups == 1: + cout, cin, k, _ = weight.shape + fused_weight = torch.mm(choice, + weight.reshape(cout, + -1)).reshape(-1, cin, k, k) + elif self.groups == self.in_channels == self.out_channels: + # depth-wise conv + cout, cin, k, _ = weight.shape + fused_weight = torch.mm(choice, + weight.reshape(cout, + -1)).reshape(-1, cin, k, k) + else: + raise NotImplementedError( + 'Current `ChannelMutator` only support pruning the depth-wise ' + '`nn.Conv2d` or `nn.Conv2d` module whose group number equals ' + f'to one, but got {self.groups}.') + if (self.bias is not None): + fused_bias = torch.mm(choice, self.bias.unsqueeze(1)).squeeze(1) + else: + fused_bias = self.bias + return fused_weight, fused_bias + + def to_static_op(self: _ConvNd) -> nn.Conv2d: + """Convert dynamic conv2d to :obj:`torch.nn.Conv2d`. + + Returns: + torch.nn.Conv2d: :obj:`torch.nn.Conv2d` with sliced parameters. + """ + self.check_if_mutables_fixed() + + weight, bias, padding = self.get_dynamic_params() + groups = self.groups + if groups == self.in_channels == self.out_channels and \ + self.mutable_in_channels is not None: + mutable_in_channels = self.mutable_attrs['in_channels'] + groups = mutable_in_channels.current_mask.sum().item() + out_channels = weight.size(0) + in_channels = weight.size(1) * groups + + kernel_size = tuple(weight.shape[2:]) + + static_conv = self.static_op_factory( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=self.stride, + padding=padding, + padding_mode=self.padding_mode, + dilation=self.dilation, + groups=groups, + bias=True if bias is not None else False) + + static_conv.weight = nn.Parameter(weight) + if bias is not None: + static_conv.bias = nn.Parameter(bias) + + return static_conv + + def get_pooled_channel(self: _ConvNd, tau: float) -> Tensor: + """Calculate channel's kl and apply softmax pooling on channel. Return + `layeri_softmaxp` as pooling result. + + Args: + tau (float): Temperature by epoch/iter. + + Returns: + Tensor: softmax pooled channel. + """ + param = self.weight + + # Compute layeri_param. + layeri_param = torch.reshape(param.detach(), (param.shape[0], -1)) + layeri_Eudist = torch.cdist(layeri_param, layeri_param, p=2) + layeri_negaEudist = -layeri_Eudist + softmax = nn.Softmax(dim=1) + layeri_softmaxp = softmax(layeri_negaEudist / tau) + + # KL = [c, 1, c] * ([c, 1 ,c] / [c, c, 1]).log() + # = [c, 1, c] * ([c, 1, c].log() - [c, c, 1].log()) + # only dim0 is required, dim1 and dim2 are pooled + # calc mean(dim=1) first + + # avoid frequent NaN + eps = 1e-7 + layeri_kl = layeri_softmaxp[:, None, :] + log_p = layeri_kl * (layeri_kl + eps).log() + log_q = layeri_kl * torch.mean((layeri_softmaxp + eps).log(), dim=1) + + layeri_kl = torch.mean((log_p - log_q), dim=2) + del log_p, log_q + real_out = self.mutable_attrs['out_channels'].activated_channels + + layeri_iscore_kl = torch.sum(layeri_kl, dim=1) + _, topm_ids_order = torch.topk( + layeri_iscore_kl, int(real_out), sorted=False) + del param, layeri_param, layeri_negaEudist, layeri_kl + return layeri_softmaxp[topm_ids_order, :] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_layernorm_mixins.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_layernorm_mixins.py new file mode 100755 index 000000000..785be9935 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_layernorm_mixins.py @@ -0,0 +1,147 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import logging +from typing import Dict, Optional, Set, Tuple + +import torch +from mmengine import print_log +from torch import Tensor, nn +from torch.nn import LayerNorm + +from mmrazor.models.mutables.base_mutable import BaseMutable +from .dynamic_mixins import DynamicChannelMixin + + +class DynamicLayerNormMixin(DynamicChannelMixin): + """A mixin class for Pytorch LayerNorm, which can mutate + ``num_features``.""" + accepted_mutable_attrs: Set[str] = {'num_features'} + + attr_mappings: Dict[str, str] = { + 'in_channels': 'num_features', + 'out_channels': 'num_features', + } + + @property + def num_features(self): + return getattr(self, 'normalized_shape')[0] + + @property + def mutable_num_features(self): + """Mutable number of features.""" + assert hasattr(self, 'mutable_attrs') + return self.mutable_attrs['num_features'] + + def register_mutable_attr(self, attr, mutable): + """Register attribute of mutable.""" + self.check_mutable_attr_valid(attr) + if attr in self.attr_mappings: + attr_map = self.attr_mappings[attr] + assert attr_map in self.accepted_mutable_attrs + if attr_map in self.mutable_attrs: + print_log( + f'{attr_map}({attr}) is already in `mutable_attrs`', + level=logging.WARNING) + else: + self._register_mutable_attr(attr_map, mutable) + elif attr in self.accepted_mutable_attrs: + self._register_mutable_attr(attr, mutable) + else: + raise NotImplementedError + + def _register_mutable_attr(self, attr, mutable): + """Register `num_features`.""" + if attr == 'num_features': + self._register_mutable_num_features(mutable) + else: + raise NotImplementedError + + def _register_mutable_num_features( + self: LayerNorm, mutable_num_features: BaseMutable) -> None: + """Mutate ``num_features`` with given mutable. + + Args: + mutable_num_features (BaseMutable): Mutable for controlling + ``num_features``. + Raises: + RuntimeError: Error if both ``affine`` and + ``tracking_running_stats`` are False. + ValueError: Error if size of mask if not same as ``num_features``. + """ + if not self.elementwise_affine: + raise RuntimeError( + 'num_features can not be mutated if both `affine` and ' + '`tracking_running_stats` are False') + + self.check_mutable_channels(mutable_num_features) + mask_size = mutable_num_features.current_mask.size(0) + + # normalized_shape is a tuple + if mask_size != self.normalized_shape[0]: + raise ValueError( + f'Expect mask size of mutable to be {self.normalized_shape}' + f' as `normalized_shape`, but got: {mask_size}.') + + self.mutable_attrs['num_features'] = mutable_num_features + + def _get_num_features_mask(self: LayerNorm) -> Optional[torch.Tensor]: + """Get mask of ``num_features``.""" + if self.elementwise_affine: + refer_tensor = self.weight + else: + return None + + if 'num_features' in self.mutable_attrs: + out_mask = self.mutable_num_features.current_mask.to( + refer_tensor.device) + else: + out_mask = torch.ones_like(refer_tensor).bool() + + return out_mask + + def get_dynamic_params( + self: LayerNorm) -> Tuple[Optional[Tensor], Optional[Tensor]]: + """Get dynamic parameters that will be used in forward process. + + Returns: + Tuple[Optional[Tensor], Optional[Tensor], Optional[Tensor], + Optional[Tensor]]: Sliced running_mean, running_var, weight and + bias. + """ + out_mask = self._get_num_features_mask() + + if self.elementwise_affine: + weight = self.weight[out_mask] + bias = self.bias[out_mask] + else: + weight, bias = self.weight, self.bias + + return weight, bias + + def to_static_op(self: LayerNorm) -> nn.Module: + """Convert dynamic LayerNormxd to :obj:`torch.nn.LayerNormxd`. + + Returns: + torch.nn.LayerNormxd: :obj:`torch.nn.LayerNormxd` with sliced + parameters. + """ + self.check_if_mutables_fixed() + + weight, bias = self.get_dynamic_params() + + if 'num_features' in self.mutable_attrs: + num_features = self.mutable_attrs['num_features'].current_mask.sum( + ).item() + else: + num_features = self.num_features + + static_ln = self.static_op_factory( + normalized_shape=num_features, + eps=self.eps, + elementwise_affine=self.elementwise_affine) + + if weight is not None: + static_ln.weight = nn.Parameter(weight.clone()) + if bias is not None: + static_ln.bias = nn.Parameter(bias.clone()) + + return static_ln diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_mixins.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_mixins.py new file mode 100755 index 000000000..2a610e5e8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_mixins.py @@ -0,0 +1,455 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import logging +from abc import ABC, abstractmethod +from typing import Any, Dict, Optional, Set, Tuple + +import torch +from mmengine import print_log +from torch import Tensor, nn +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.models.mutables.base_mutable import BaseMutable + + +class DynamicMixin(ABC): + """Base class for dynamic OP. A dynamic OP usually consists of a normal + static OP and mutables, where mutables are used to control the searchable + (mutable) part of the dynamic OP. + + Note: + When the dynamic OP has just been initialized, its forward propagation + logic should be the same as the corresponding static OP. Only after + the searchable part accepts the specific mutable through the + corresponding interface does the part really become dynamic. + + Note: + All subclass should implement ``to_static_op`` and + ``static_op_factory`` APIs. + + Args: + accepted_mutables (set): The string set of all accepted mutables. + """ + accepted_mutable_attrs: Set[str] = set() + attr_mappings: Dict[str, str] = dict() + + @abstractmethod + def register_mutable_attr(self, attr: str, mutable: BaseMutable): + pass + + def get_mutable_attr(self, attr: str) -> BaseMutable: + + self.check_mutable_attr_valid(attr) + if attr in self.attr_mappings: + attr_map = self.attr_mappings[attr] + return getattr(self.mutable_attrs, attr_map, None) # type:ignore + else: + return getattr(self.mutable_attrs, attr, None) # type:ignore + + @classmethod + @abstractmethod + def convert_from(cls, module): + """Convert an instance of Pytorch module to a new instance of Dynamic + module.""" + + @property + @abstractmethod + def static_op_factory(self): + """Corresponding Pytorch OP.""" + + @abstractmethod + def to_static_op(self) -> nn.Module: + """Convert dynamic OP to static OP. + + Note: + The forward result for the same input between dynamic OP and its + corresponding static OP must be same. + + Returns: + nn.Module: Corresponding static OP. + """ + + def check_if_mutables_fixed(self) -> None: + """Check if all mutables are fixed. + + Raises: + RuntimeError: Error if a existing mutable is not fixed. + """ + from mmrazor.models.mutables import (DerivedMutable, + MutableChannelContainer) + + def check_fixed(mutable: Optional[BaseMutable]) -> None: + if mutable is not None and not mutable.is_fixed: + raise RuntimeError(f'Mutable `{mutable.alias}` is not fixed.') + + for mutable in self.mutable_attrs.values(): # type: ignore + if isinstance(mutable, (MutableChannelContainer, DerivedMutable)): + continue + check_fixed(mutable) + + def check_mutable_attr_valid(self, attr): + assert attr in self.attr_mappings or \ + attr in self.accepted_mutable_attrs + + @staticmethod + def get_current_choice(mutable: BaseMutable) -> Any: + """Get current choice of given mutable. + + Args: + mutable (BaseMutable): Given mutable. + + Raises: + RuntimeError: Error if `current_choice` is None. + + Returns: + Any: Current choice of given mutable. + """ + current_choice = mutable.current_choice + if current_choice is None: + raise RuntimeError(f'current choice of mutable {type(mutable)} ' + 'can not be None at runtime') + + return current_choice + + +class DynamicChannelMixin(DynamicMixin): + """Base class for dynamic OP with mutable channels. + + Note: + All subclass should implement ``mutable_in_channels`` and + ``mutable_out_channels`` APIs. + """ + + attr_mappings: Dict[str, str] = { + 'in_channels': 'in_channels', + 'out_channels': 'out_channels', + } + + @staticmethod + def check_mutable_channels(mutable_channels: BaseMutable) -> None: + """Check if mutable has `currnet_mask` attribute. + + Args: + mutable_channels (BaseMutable): Mutable to be checked. + + Raises: + ValueError: Error if mutable does not have `current_mask` + attribute. + """ + if not hasattr(mutable_channels, 'current_mask'): + raise ValueError( + 'channel mutable must have attribute `current_mask`') + + +class DynamicBatchNormMixin(DynamicChannelMixin): + """A mixin class for Pytorch BatchNorm, which can mutate + ``num_features``.""" + accepted_mutable_attrs: Set[str] = {'num_features'} + attr_mappings: Dict[str, str] = { + 'in_channels': 'num_features', + 'out_channels': 'num_features', + } + + def register_mutable_attr(self, attr, mutable): + self.check_mutable_attr_valid(attr) + if attr in self.attr_mappings: + attr_map = self.attr_mappings[attr] + assert attr_map in self.accepted_mutable_attrs + if attr_map in self.mutable_attrs: + print_log( + f'{attr_map}({attr}) is already in `mutable_attrs`', + level=logging.WARNING) + else: + self._register_mutable_attr(attr_map, mutable) + elif attr in self.accepted_mutable_attrs: + self._register_mutable_attr(attr, mutable) + else: + raise NotImplementedError + + def _register_mutable_attr(self, attr, mutable): + + if attr == 'num_features': + self._register_mutable_num_features(mutable) + else: + raise NotImplementedError + + def _register_mutable_num_features( + self: _BatchNorm, mutable_num_features: BaseMutable) -> None: + """Mutate ``num_features`` with given mutable. + + Args: + mutable_num_features (BaseMutable): Mutable for controlling + ``num_features``. + + Raises: + RuntimeError: Error if both ``affine`` and + ``tracking_running_stats`` are False. + ValueError: Error if size of mask if not same as ``num_features``. + """ + if not self.affine and not self.track_running_stats: + raise RuntimeError( + 'num_features can not be mutated if both `affine` and ' + '`tracking_running_stats` are False') + + self.check_mutable_channels(mutable_num_features) + mask_size = mutable_num_features.current_mask.size(0) + if mask_size != self.num_features: + raise ValueError( + f'Expect mask size of mutable to be {self.num_features} as ' + f'`num_features`, but got: {mask_size}.') + + self.mutable_attrs['num_features'] = mutable_num_features + + def _get_num_features_mask(self: _BatchNorm) -> Optional[torch.Tensor]: + """Get mask of ``num_features``""" + if self.affine: + refer_tensor = self.weight + elif self.track_running_stats: + refer_tensor = self.running_mean + else: + return None + + if 'num_features' in self.mutable_attrs: + out_mask = self.mutable_attrs['num_features'].current_mask.to( + refer_tensor.device) + else: + out_mask = torch.ones_like(refer_tensor).bool() + + return out_mask + + def get_dynamic_params( + self: _BatchNorm + ) -> Tuple[Optional[Tensor], Optional[Tensor], Optional[Tensor], + Optional[Tensor]]: + """Get dynamic parameters that will be used in forward process. + + Returns: + Tuple[Optional[Tensor], Optional[Tensor], Optional[Tensor], + Optional[Tensor]]: Sliced running_mean, running_var, weight and + bias. + """ + out_mask = self._get_num_features_mask() + + if self.affine: + weight = self.weight[out_mask] + bias = self.bias[out_mask] + else: + weight, bias = self.weight, self.bias + + if self.track_running_stats: + running_mean = self.running_mean[out_mask] \ + if not self.training or self.track_running_stats else None + running_var = self.running_var[out_mask] \ + if not self.training or self.track_running_stats else None + else: + running_mean, running_var = self.running_mean, self.running_var + + return running_mean, running_var, weight, bias + + def to_static_op(self: _BatchNorm) -> nn.Module: + """Convert dynamic BatchNormxd to :obj:`torch.nn.BatchNormxd`. + + Returns: + torch.nn.BatchNormxd: :obj:`torch.nn.BatchNormxd` with sliced + parameters. + """ + self.check_if_mutables_fixed() + + running_mean, running_var, weight, bias = self.get_dynamic_params() + if 'num_features' in self.mutable_attrs: + num_features = self.mutable_attrs['num_features'].current_mask.sum( + ).item() + else: + num_features = self.num_features + + static_bn = self.static_op_factory( + num_features=num_features, + eps=self.eps, + momentum=self.momentum, + affine=self.affine, + track_running_stats=self.track_running_stats) + + if running_mean is not None: + static_bn.running_mean.copy_(running_mean) + static_bn.running_mean = static_bn.running_mean.to( + running_mean.device) + if running_var is not None: + static_bn.running_var.copy_(running_var) + static_bn.running_var = static_bn.running_var.to( + running_var.device) + if weight is not None: + static_bn.weight = nn.Parameter(weight) + if bias is not None: + static_bn.bias = nn.Parameter(bias) + + return static_bn + + +class DynamicLinearMixin(DynamicChannelMixin): + """A mixin class for Pytorch Linear, which can mutate ``in_features`` and + ``out_features``.""" + + accepted_mutable_attrs: Set[str] = {'in_features', 'out_features'} + attr_mappings: Dict[str, str] = { + 'in_channels': 'in_features', + 'out_channels': 'out_features', + } + + def register_mutable_attr(self, attr, mutable): + self.check_mutable_attr_valid(attr) + if attr in self.attr_mappings: + attr_map = self.attr_mappings[attr] + assert attr_map in self.accepted_mutable_attrs + if attr_map in self.mutable_attrs: + print_log( + f'{attr_map}({attr}) is already in `mutable_attrs`', + level=logging.WARNING) + else: + self._register_mutable_attr(attr_map, mutable) + elif attr in self.accepted_mutable_attrs: + self._register_mutable_attr(attr, mutable) + else: + raise NotImplementedError + + def _register_mutable_attr(self, attr, mutable): + + if attr == 'in_features': + self._register_mutable_in_features(mutable) + elif attr == 'out_features': + self._register_mutable_out_features(mutable) + else: + raise NotImplementedError + + def _register_mutable_in_features( + self: nn.Linear, mutable_in_features: BaseMutable) -> None: + """Mutate ``in_features`` with given mutable. + + Args: + mutable_in_features (BaseMutable): Mutable for controlling + ``in_features``. + + Raises: + ValueError: Error if size of mask if not same as ``in_features``. + """ + self.check_mutable_channels(mutable_in_features) + mask_size = mutable_in_features.current_mask.size(0) + if mask_size != self.in_features: + raise ValueError( + f'Expect mask size of mutable to be {self.in_features} as ' + f'`in_features`, but got: {mask_size}.') + + self.mutable_attrs['in_features'] = mutable_in_features + + def _register_mutable_out_features( + self: nn.Linear, mutable_out_features: BaseMutable) -> None: + """Mutate ``out_features`` with given mutable. + + Args: + mutable_out_features (BaseMutable): Mutable for controlling + ``out_features``. + + Raises: + ValueError: Error if size of mask if not same as ``out_features``. + """ + self.check_mutable_channels(mutable_out_features) + mask_size = mutable_out_features.current_mask.size(0) + if mask_size != self.out_features: + raise ValueError( + f'Expect mask size of mutable to be {self.out_features} as ' + f'`in_features`, but got: {mask_size}.') + + self.mutable_attrs['out_features'] = mutable_out_features + + def get_dynamic_params(self: nn.Linear) -> Tuple[Tensor, Optional[Tensor]]: + """Get dynamic parameters that will be used in forward process. + + Returns: + Tuple[Tensor, Optional[Tensor]]: Sliced weight and bias. + """ + if 'in_features' not in self.mutable_attrs and \ + 'out_features' not in self.mutable_attrs: + return self.weight, self.bias + + if 'in_features' in self.mutable_attrs: + in_mask = self.mutable_attrs['in_features'].current_mask.to( + self.weight.device) + else: + in_mask = torch.ones(self.weight.size(1)).bool().to( + self.weight.device) + if 'out_features' in self.mutable_attrs: + + out_mask = self.mutable_attrs['out_features'].current_mask.to( + self.weight.device) + else: + out_mask = torch.ones(self.weight.size(0)).bool().to( + self.weight.device) + + weight = self.weight[out_mask][:, in_mask] + bias = self.bias[out_mask] if self.bias is not None else None + + return weight, bias + + def to_static_op(self: nn.Linear) -> nn.Module: + """Convert to :obj:`torch.nn.Linear`. + + Returns: + nn.Linear: :obj:`torch.nn.Linear` with sliced parameters. + """ + self.check_if_mutables_fixed() + + weight, bias = self.get_dynamic_params() + out_features = weight.size(0) + in_features = weight.size(1) + + static_linear = self.static_op_factory( + in_features=in_features, + out_features=out_features, + bias=True if bias is not None else False) + + static_linear.weight = nn.Parameter(weight) + if bias is not None: + static_linear.bias = nn.Parameter(bias) + + return static_linear + + +class DynamicResizeMixin(DynamicMixin): + """A mixin class for Pytorch InputResizer, which can mutate ``shape``.""" + + accepted_mutable_attrs: Set[str] = {'shape'} + + def register_mutable_attr(self, attr, mutable): + if attr == 'shape': + self._register_mutable_shape(mutable) + else: + raise NotImplementedError + + def _register_mutable_shape(self, mutable_shape): + assert hasattr(self, 'mutable_attrs') + current_shape = mutable_shape.current_choice + shape_dim = 1 if isinstance(current_shape, int) else len(current_shape) + if shape_dim not in [1, 2, 3]: + raise ValueError('Expect shape of mutable to be 1, 2 or 3' + f', but got: {shape_dim}.') + + self.mutable_attrs['shape'] = mutable_shape + + def get_dynamic_shape(self): + if 'shape' in self.mutable_attrs: + current_shape = self.mutable_attrs['shape'].current_choice + else: + current_shape = None + return current_shape + + def to_static_op(self) -> nn.Module: + self.check_if_mutables_fixed() + + input_resizer = self.static_op_factory( + interpolation_type=self._interpolation_type, # type:ignore + align_corners=self._align_corners, # type:ignore + scale_factor=self._scale_factor) # type:ignore + + size = self.get_dynamic_shape() + if size is not None: + input_resizer._size = size + + return input_resizer diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/__init__.py new file mode 100755 index 000000000..0d8896010 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .dafl_generator import DAFLGenerator +from .zskt_generator import ZSKTGenerator + +__all__ = ['DAFLGenerator', 'ZSKTGenerator'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/base_generator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/base_generator.py new file mode 100755 index 000000000..ae38df415 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/base_generator.py @@ -0,0 +1,63 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional + +import torch +from mmengine.model import BaseModule + +from mmrazor.models.utils import get_module_device + + +class BaseGenerator(BaseModule): + """The base class for generating images. + + Args: + img_size (int): The size of generated image. + latent_dim (int): The dimension of latent data. + hidden_channels (int): The dimension of hidden channels. + init_cfg (dict, optional): The config to control the initialization. + Defaults to None. + """ + + def __init__(self, + img_size: int, + latent_dim: int, + hidden_channels: int, + init_cfg: Optional[Dict] = None) -> None: + super().__init__(init_cfg=init_cfg) + self.img_size = img_size + self.latent_dim = latent_dim + self.hidden_channels = hidden_channels + + def process_latent(self, + latent_data: Optional[torch.Tensor] = None, + batch_size: int = 1) -> torch.Tensor: + """Generate the latent data if the input is None. Put the latent data + into the current gpu. + + Args: + latent_data (torch.Tensor, optional): The latent data. Defaults to + None. + batch_size (int): The batch size of the latent data. Defaults to 1. + """ + if isinstance(latent_data, torch.Tensor): + assert latent_data.shape[1] == self.latent_dim, \ + 'Second dimension of the input must be equal to "latent_dim",'\ + f'but got {latent_data.shape[1]} != {self.latent_dim}.' + if latent_data.ndim == 2: + batch_data = latent_data + else: + raise ValueError('The noise should be in shape of (n, c)' + f'but got {latent_data.shape}') + elif latent_data is None: + assert batch_size > 0, \ + '"batch_size" should larger than zero when "latent_data" is '\ + f'None, but got {batch_size}.' + batch_data = torch.randn((batch_size, self.latent_dim)) + + # putting data on the right device + batch_data = batch_data.to(get_module_device(self)) + return batch_data + + def forward(self) -> None: + """Forward function.""" + raise NotImplementedError diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/dafl_generator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/dafl_generator.py new file mode 100755 index 000000000..6a17e4b6b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/dafl_generator.py @@ -0,0 +1,86 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS +from .base_generator import BaseGenerator + + +@MODELS.register_module() +class DAFLGenerator(BaseGenerator): + """Generator for DAFL. + + Args: + img_size (int): The size of generated image. + latent_dim (int): The dimension of latent data. + hidden_channels (int): The dimension of hidden channels. + scale_factor (int, optional): The scale factor for F.interpolate. + Defaults to 2. + bn_eps (float, optional): The eps param in bn. Defaults to 0.8. + leaky_slope (float, optional): The slope param in leaky relu. Defaults + to 0.2. + init_cfg (dict, optional): The config to control the initialization. + """ + + def __init__( + self, + img_size: int, + latent_dim: int, + hidden_channels: int, + scale_factor: int = 2, + bn_eps: float = 0.8, + leaky_slope: float = 0.2, + init_cfg: Optional[Dict] = None, + ) -> None: + super().__init__( + img_size, latent_dim, hidden_channels, init_cfg=init_cfg) + self.init_size = self.img_size // (scale_factor**2) + self.scale_factor = scale_factor + self.linear = nn.Linear(self.latent_dim, + self.hidden_channels * self.init_size**2) + + self.bn1 = nn.BatchNorm2d(self.hidden_channels) + self.conv_blocks1 = nn.Sequential( + nn.Conv2d( + self.hidden_channels, + self.hidden_channels, + 3, + stride=1, + padding=1), + nn.BatchNorm2d(self.hidden_channels, eps=bn_eps), + nn.LeakyReLU(leaky_slope, inplace=True), + ) + self.conv_blocks2 = nn.Sequential( + nn.Conv2d( + self.hidden_channels, + self.hidden_channels // 2, + 3, + stride=1, + padding=1), + nn.BatchNorm2d(self.hidden_channels // 2, eps=bn_eps), + nn.LeakyReLU(leaky_slope, inplace=True), + nn.Conv2d(self.hidden_channels // 2, 3, 3, stride=1, padding=1), + nn.Tanh(), nn.BatchNorm2d(3, affine=False)) + + def forward(self, + data: Optional[torch.Tensor] = None, + batch_size: int = 1) -> torch.Tensor: + """Forward function for generator. + + Args: + data (torch.Tensor, optional): The input data. Defaults to None. + batch_size (int): Batch size. Defaults to 1. + """ + batch_data = self.process_latent(data, batch_size) + img = self.linear(batch_data) + img = img.view(img.shape[0], self.hidden_channels, self.init_size, + self.init_size) + img = self.bn1(img) + img = F.interpolate(img, scale_factor=self.scale_factor) + img = self.conv_blocks1(img) + img = F.interpolate(img, scale_factor=self.scale_factor) + img = self.conv_blocks2(img) + return img diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/zskt_generator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/zskt_generator.py new file mode 100755 index 000000000..2216eb2ce --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/zskt_generator.py @@ -0,0 +1,91 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional, Tuple + +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS +from .base_generator import BaseGenerator + + +class View(nn.Module): + """Class for view tensors. + + Args: + size (Tuple[int, ...]): Size of the output tensor. + """ + + def __init__(self, size: Tuple[int, ...]) -> None: + super(View, self).__init__() + self.size = size + + def forward(self, tensor: torch.Tensor) -> torch.Tensor: + """"Forward function for view tensors.""" + return tensor.view(self.size) + + +@MODELS.register_module() +class ZSKTGenerator(BaseGenerator): + """Generator for ZSKT. code link: + https://github.com/polo5/ZeroShotKnowledgeTransfer/ + + Args: + img_size (int): The size of generated image. + latent_dim (int): The dimension of latent data. + hidden_channels (int): The dimension of hidden channels. + scale_factor (int, optional): The scale factor for F.interpolate. + Defaults to 2. + leaky_slope (float, optional): The slope param in leaky relu. Defaults + to 0.2. + init_cfg (dict, optional): The config to control the initialization. + """ + + def __init__( + self, + img_size: int, + latent_dim: int, + hidden_channels: int, + scale_factor: int = 2, + leaky_slope: float = 0.2, + init_cfg: Optional[Dict] = None, + ) -> None: + super().__init__( + img_size, latent_dim, hidden_channels, init_cfg=init_cfg) + self.init_size = self.img_size // (scale_factor**2) + self.scale_factor = scale_factor + + self.layers = nn.Sequential( + nn.Linear(self.latent_dim, + self.hidden_channels * self.init_size**2), + View((-1, self.hidden_channels, self.init_size, self.init_size)), + nn.BatchNorm2d(self.hidden_channels), + nn.Upsample(scale_factor=scale_factor), + nn.Conv2d( + self.hidden_channels, + self.hidden_channels, + 3, + stride=1, + padding=1), nn.BatchNorm2d(self.hidden_channels), + nn.LeakyReLU(leaky_slope, inplace=True), + nn.Upsample(scale_factor=scale_factor), + nn.Conv2d( + self.hidden_channels, + self.hidden_channels // 2, + 3, + stride=1, + padding=1), nn.BatchNorm2d(self.hidden_channels // 2), + nn.LeakyReLU(leaky_slope, inplace=True), + nn.Conv2d(self.hidden_channels // 2, 3, 3, stride=1, padding=1), + nn.BatchNorm2d(3, affine=True)) + + def forward(self, + data: Optional[torch.Tensor] = None, + batch_size: int = 1) -> torch.Tensor: + """Forward function for generator. + + Args: + data (torch.Tensor, optional): The input data. Defaults to None. + batch_size (int): Batch size. Defaults to 1. + """ + batch_data = self.process_latent(data, batch_size) + return self.layers(batch_data) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/__init__.py new file mode 100755 index 000000000..0d7da475d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .darts_subnet_head import DartsSubnetClsHead +from .deit_head import DeiTClsHead + +__all__ = ['DartsSubnetClsHead', 'DeiTClsHead'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/darts_subnet_head.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/darts_subnet_head.py new file mode 100755 index 000000000..c3886ced3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/darts_subnet_head.py @@ -0,0 +1,83 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List, Tuple + +import torch +from torch import nn + +from mmrazor.models.utils import add_prefix +from mmrazor.registry import MODELS + +try: + from mmcls.evaluation import Accuracy + from mmcls.models.heads import LinearClsHead + from mmcls.structures import ClsDataSample +except ImportError: + from mmrazor.utils import get_placeholder + Accuracy = get_placeholder('mmcls') + LinearClsHead = get_placeholder('mmcls') + ClsDataSample = get_placeholder('mmcls') + + +@MODELS.register_module() +class DartsSubnetClsHead(LinearClsHead): + + def __init__(self, aux_in_channels, aux_loss, **kwargs): + super(DartsSubnetClsHead, self).__init__(**kwargs) + self.aux_linear = nn.Linear(aux_in_channels, self.num_classes) + self.aux_loss_module = MODELS.build(aux_loss) + + def forward_aux(self, feats: Tuple[torch.Tensor]): + + aux_feat = feats[0] + aux_cls_score = self.aux_linear(aux_feat) + return aux_cls_score + + def _get_aux_loss(self, cls_score: torch.Tensor, + data_samples: List[ClsDataSample], **kwargs): + """Unpack data samples and compute loss.""" + # Unpack data samples and pack targets + if 'score' in data_samples[0].gt_label: + # Batch augmentation may convert labels to one-hot format scores. + target = torch.stack([i.gt_label.score for i in data_samples]) + else: + target = torch.hstack([i.gt_label.label for i in data_samples]) + + # compute loss + losses = dict() + loss = self.aux_loss_module( + cls_score, target, avg_factor=cls_score.size(0), **kwargs) + losses['loss'] = loss + + # compute accuracy + if self.cal_acc: + assert target.ndim == 1, 'If you enable batch augmentation ' \ + 'like mixup during training, `cal_acc` is pointless.' + acc = Accuracy.calculate(cls_score, target, topk=self.topk) + losses.update( + {f'accuracy_top-{k}': a + for k, a in zip(self.topk, acc)}) + + return losses + + def loss(self, feats: Tuple[torch.Tensor], + data_samples: List[ClsDataSample], **kwargs) -> dict: + """Calculate losses from the classification score. + Args: + feats (tuple[Tensor]): The features extracted from the backbone. + Multiple stage inputs are acceptable but only the last stage + will be used to classify. The shape of every item should be + ``(num_samples, num_classes)``. + data_samples (List[ClsDataSample]): The annotation data of + every samples. + **kwargs: Other keyword arguments to forward the loss module. + Returns: + dict[str, Tensor]: a dictionary of loss components + """ + losses = super().loss(feats, data_samples, **kwargs) + + aux_cls_score = self.forward_aux(feats) + aux_losses = self._get_aux_loss(aux_cls_score, data_samples, **kwargs) + + losses.update(add_prefix(aux_losses, 'aux_head.')) + + return losses diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/deit_head.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/deit_head.py new file mode 100755 index 000000000..61d587d93 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/deit_head.py @@ -0,0 +1,69 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List, Tuple + +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS + +try: + from mmcls.models import VisionTransformerClsHead +except ImportError: + from mmrazor.utils import get_placeholder + VisionTransformerClsHead = get_placeholder('mmcls') + + +@MODELS.register_module() +class DeiTClsHead(VisionTransformerClsHead): + """Distilled Vision Transformer classifier head. + + Comparing with the :class:`DeiTClsHead` in mmcls, this head support to + train the distilled version DeiT. + + Args: + num_classes (int): Number of categories excluding the background + category. + in_channels (int): Number of channels in the input feature map. + hidden_dim (int, optional): Number of the dimensions for hidden layer. + Defaults to None, which means no extra hidden layer. + act_cfg (dict): The activation config. Only available during + pre-training. Defaults to ``dict(type='Tanh')``. + init_cfg (dict): The extra initialization configs. Defaults to + ``dict(type='Constant', layer='Linear', val=0)``. + """ + + def _init_layers(self): + """"Init extra hidden linear layer to handle dist token if exists.""" + super(DeiTClsHead, self)._init_layers() + if self.hidden_dim is None: + head_dist = nn.Linear(self.in_channels, self.num_classes) + else: + head_dist = nn.Linear(self.hidden_dim, self.num_classes) + self.layers.add_module('head_dist', head_dist) + + def pre_logits( + self, feats: Tuple[List[torch.Tensor]] + ) -> Tuple[torch.Tensor, torch.Tensor]: + """The process before the final classification head. + + The input ``feats`` is a tuple of list of tensor, and each tensor is + the feature of a backbone stage. In ``DeiTClsHead``, we obtain the + feature of the last stage and forward in hidden layer if exists. + """ + _, cls_token, dist_token = feats[-1] + if self.hidden_dim is None: + return cls_token, dist_token + else: + cls_token = self.layers.act(self.layers.pre_logits(cls_token)) + dist_token = self.layers.act(self.layers.pre_logits(dist_token)) + return cls_token, dist_token + + def forward(self, feats: Tuple[List[torch.Tensor]]) -> torch.Tensor: + """The forward process.""" + cls_token, dist_token = self.pre_logits(feats) + # The final classification head. + cls_score = self.layers.head(cls_token) + # Forward so that the corresponding recorder can record the output + # of the distillation token + _ = self.layers.head_dist(dist_token) + return cls_score diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/__init__.py new file mode 100755 index 000000000..60b3c7e44 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .squeezemean_with_dropout import SqueezeMeanPoolingWithDropout + +__all__ = ['SqueezeMeanPoolingWithDropout'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/squeezemean_with_dropout.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/squeezemean_with_dropout.py new file mode 100755 index 000000000..eca344729 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/squeezemean_with_dropout.py @@ -0,0 +1,57 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Tuple, Union + +import torch +import torch.nn.functional as F +from mmengine.model import BaseModule + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class SqueezeMeanPoolingWithDropout(BaseModule): + """Dimensionality Reduction Neck with Dropout. + + Dimensionality Reduction the feature map of backbone by SqueezeMean. + Some of the code is borrowed from + `https://github.com/facebookresearch/AttentiveNAS`. + + Args: + drop_ratio (float): Dropout rate. Defaults to 0.2. + """ + + def __init__(self, drop_ratio: float = 0.2): + super(SqueezeMeanPoolingWithDropout, self).__init__() + self.drop_ratio = drop_ratio + + def dimension_reduction(self, x: torch.Tensor): + assert x.ndim > 1, 'SqueezeMean only support (B, C, *) input.' + 'to B C*H*W output if dim = 2' + for i in range(x.ndim - 1, 1, -1): + x = x.mean(i, keepdim=True) + x = torch.squeeze(x, -1) + return x + + def forward( + self, inputs: Union[Tuple, + torch.Tensor]) -> Union[Tuple, torch.Tensor]: + """Forward function with dropout. + + Args: + x (Union[Tuple, torch.Tensor]): The feature map of backbone. + Returns: + Tuple[torch.Tensor]: The output features. + """ + drop_ratio = self.drop_ratio if self.drop_ratio is not None else 0.0 + + if isinstance(inputs, tuple): + outs = tuple([self.dimension_reduction(x) for x in inputs]) + if drop_ratio > 0 and self.training: + outs = tuple([F.dropout(x, p=drop_ratio) for x in outs]) + elif isinstance(inputs, torch.Tensor): + inputs = self.dimension_reduction(inputs) + if drop_ratio > 0 and self.training: + outs = F.dropout(inputs, p=drop_ratio) # type:ignore + else: + raise TypeError('neck inputs should be tuple or torch.tensor') + return outs diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/__init__.py new file mode 100755 index 000000000..4e6eec7d3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/__init__.py @@ -0,0 +1,17 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .common import Identity +from .darts_series import (DartsDilConv, DartsPoolBN, DartsSepConv, + DartsSkipConnect, DartsZero) +from .efficientnet_series import ConvBnAct, DepthwiseSeparableConv +from .function import InputResizer +from .gather_tensors import GatherTensors +from .mobilenet_series import MBBlock +from .shufflenet_series import ShuffleBlock, ShuffleXception +from .transformer_series import MultiheadAttention, RelativePosition2D + +__all__ = [ + 'ShuffleBlock', 'ShuffleXception', 'DartsPoolBN', 'DartsDilConv', + 'DartsSepConv', 'DartsSkipConnect', 'DartsZero', 'MBBlock', 'Identity', + 'ConvBnAct', 'DepthwiseSeparableConv', 'GatherTensors', 'InputResizer', + 'RelativePosition2D', 'MultiheadAttention' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/base.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/base.py new file mode 100755 index 000000000..f02756000 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/base.py @@ -0,0 +1,19 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmengine.model import BaseModule + + +class BaseOP(BaseModule): + """Base class for searchable operations. + + Args: + in_channels (int): The input channels of the operation. + out_channels (int): The output channels of the operation. + stride (int): Stride of the operation. Defaults to 1. + """ + + def __init__(self, in_channels, out_channels, stride=1, **kwargs): + super(BaseOP, self).__init__(**kwargs) + + self.in_channels = in_channels + self.out_channels = out_channels + self.stride = stride diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/common.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/common.py new file mode 100755 index 000000000..8f1bccd9b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/common.py @@ -0,0 +1,48 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmcv.cnn import ConvModule + +from mmrazor.registry import MODELS +from .base import BaseOP + + +@MODELS.register_module() +class Identity(BaseOP): + """Base class for searchable operations. + + Args: + conv_cfg (dict, optional): Config dict for convolution layer. + Default: None, which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN'). + act_cfg (dict): Config dict for activation layer. + Default: None. + """ + + def __init__(self, + conv_cfg=None, + norm_cfg=dict(type='BN'), + act_cfg=None, + **kwargs): + super(Identity, self).__init__(**kwargs) + + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.act_cfg = act_cfg + + if self.stride != 1 or self.in_channels != self.out_channels: + self.downsample = ConvModule( + self.in_channels, + self.out_channels, + kernel_size=1, + stride=self.stride, + padding=0, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=self.act_cfg) + else: + self.downsample = None + + def forward(self, x): + if self.downsample is not None: + x = self.downsample(x) + return x diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/darts_series.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/darts_series.py new file mode 100755 index 000000000..71368f515 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/darts_series.py @@ -0,0 +1,181 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +from mmcv.cnn import build_norm_layer +from mmcv.cnn.bricks import DropPath + +from mmrazor.registry import MODELS +from .base import BaseOP + + +@MODELS.register_module() +class DartsPoolBN(BaseOP): + + def __init__(self, + pool_type, + kernel_size=3, + norm_cfg=dict(type='BN'), + use_drop_path=False, + **kwargs): + super(DartsPoolBN, self).__init__(**kwargs) + self.kernel_size = kernel_size + self.norm_cfg = norm_cfg + if pool_type == 'max': + self.pool = nn.MaxPool2d(self.kernel_size, self.stride, 1) + elif pool_type == 'avg': + self.pool = nn.AvgPool2d( + self.kernel_size, self.stride, 1, count_include_pad=False) + self.bn = build_norm_layer(self.norm_cfg, self.out_channels)[1] + + self.drop_path = DropPath() if use_drop_path else None + + def forward(self, x): + out = self.pool(x) + out = self.bn(out) + if self.drop_path is not None: + out = self.drop_path(out) + + return out + + +@MODELS.register_module() +class DartsDilConv(BaseOP): + + def __init__(self, + kernel_size, + use_drop_path=False, + norm_cfg=dict(type='BN'), + **kwargs): + super(DartsDilConv, self).__init__(**kwargs) + self.kernel_size = kernel_size + self.norm_cfg = norm_cfg + self.dilation = 2 + assert self.kernel_size in [3, 5] + assert self.stride in [1, 2] + self.conv1 = nn.Sequential( + nn.ReLU(), + nn.Conv2d( + self.in_channels, + self.in_channels, + self.kernel_size, + self.stride, (self.kernel_size // 2) * self.dilation, + dilation=self.dilation, + groups=self.in_channels, + bias=False), + nn.Conv2d( + self.in_channels, self.out_channels, 1, stride=1, bias=False), + build_norm_layer(self.norm_cfg, self.in_channels)[1]) + + self.drop_path = DropPath() if use_drop_path else None + + def forward(self, x): + out = self.conv1(x) + if self.drop_path is not None: + out = self.drop_path(out) + return out + + +@MODELS.register_module() +class DartsSepConv(BaseOP): + + def __init__(self, + kernel_size, + use_drop_path=False, + norm_cfg=dict(type='BN'), + **kwargs): + super(DartsSepConv, self).__init__(**kwargs) + + self.kernel_size = kernel_size + self.norm_cfg = norm_cfg + assert self.kernel_size in [3, 5] + assert self.stride in [1, 2] + self.conv1 = nn.Sequential( + nn.ReLU(), + nn.Conv2d( + self.in_channels, + self.in_channels, + self.kernel_size, + self.stride, + self.kernel_size // 2, + groups=self.in_channels, + bias=False), + nn.Conv2d( + self.in_channels, self.in_channels, 1, stride=1, bias=False), + build_norm_layer(self.norm_cfg, self.in_channels)[1]) + self.conv2 = nn.Sequential( + nn.ReLU(), + nn.Conv2d( + self.in_channels, + self.out_channels, + self.kernel_size, + 1, + self.kernel_size // 2, + groups=self.in_channels, + bias=False), + nn.Conv2d( + self.out_channels, self.out_channels, 1, stride=1, bias=False), + build_norm_layer(self.norm_cfg, self.out_channels)[1]) + + self.drop_path = DropPath() if use_drop_path else None + + def forward(self, x): + out = self.conv1(x) + out = self.conv2(out) + if self.drop_path is not None: + out = self.drop_path(out) + return out + + +@MODELS.register_module() +class DartsSkipConnect(BaseOP): + """Reduce feature map size by factorized pointwise (stride=2).""" + + def __init__(self, + use_drop_path=False, + norm_cfg=dict(type='BN'), + **kwargs): + super(DartsSkipConnect, self).__init__(**kwargs) + self.norm_cfg = norm_cfg + if self.stride > 1: + self.relu = nn.ReLU() + self.conv1 = nn.Conv2d( + self.in_channels, + self.out_channels // 2, + 1, + stride=2, + padding=0, + bias=False) + self.conv2 = nn.Conv2d( + self.in_channels, + self.out_channels // 2, + 1, + stride=2, + padding=0, + bias=False) + self.bn = build_norm_layer(self.norm_cfg, self.out_channels)[1] + + self.drop_path = DropPath() if use_drop_path else None + + def forward(self, x): + if self.stride > 1: + x = self.relu(x) + out = torch.cat( + [self.conv1(x), self.conv2(x[:, :, 1:, 1:])], dim=1) + out = self.bn(out) + if self.drop_path is not None: + out = self.drop_path(out) + else: + out = x + return out + + +@MODELS.register_module() +class DartsZero(BaseOP): + + def __init__(self, **kwargs): + super(DartsZero, self).__init__(**kwargs) + + def forward(self, x): + if self.stride == 1: + return x.mul(0.) + return x[:, :, ::self.stride, ::self.stride].mul(0.) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/efficientnet_series.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/efficientnet_series.py new file mode 100755 index 000000000..ab78caa5b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/efficientnet_series.py @@ -0,0 +1,165 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional + +import torch.nn as nn +from mmcv.cnn import ConvModule + +from mmrazor.registry import MODELS +from .base import BaseOP + +try: + from mmcls.models.utils import SELayer +except ImportError: + from mmrazor.utils import get_placeholder + SELayer = get_placeholder('mmcls') + + +@MODELS.register_module() +class ConvBnAct(BaseOP): + """ConvBnAct block from timm. + + Args: + in_channels (int): number of in channels. + out_channels (int): number of out channels. + kernel_size (int): kernel size of convolution. + stride (int, optional): stride of convolution. Defaults to 1. + dilation (int, optional): dilation rate of convolution. Defaults to 1. + padding (int, optional): padding size of convolution. Defaults to 0. + skip (bool, optional): whether using skip connect. Defaults to False. + conv_cfg (Optional[dict], optional): Config dict for convolution layer. + Default: None, which means using conv2d. + norm_cfg (Dict, optional): Config dict for normalization layer. + Default: dict(type='BN'). + act_cfg (Dict, optional):Config dict for activation layer. + Default: dict(type='ReLU'). + """ + + def __init__(self, + in_channels: int, + out_channels: int, + kernel_size: int, + stride: int = 1, + dilation: int = 1, + padding: int = 0, + skip: bool = False, + conv_cfg: Optional[dict] = None, + se_cfg: Dict = None, + norm_cfg: Dict = dict(type='BN'), + act_cfg: Dict = dict(type='ReLU')): + super().__init__( + in_channels=in_channels, out_channels=out_channels, stride=stride) + self.has_residual = skip and stride == 1 \ + and in_channels == out_channels + self.with_se = se_cfg is not None + + if self.with_se: + assert isinstance(se_cfg, dict) + self.se = SELayer(self.out_channels, **se_cfg) + + self.convModule = ConvModule( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=stride, + dilation=dilation, + padding=padding, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + + def forward(self, x): + """Forward function.""" + shortcut = x + x = self.convModule(x) + if self.has_residual: + x += shortcut + return x + + +@MODELS.register_module() +class DepthwiseSeparableConv(BaseOP): + """DepthwiseSeparable block Used for DS convs in MobileNet-V1 and in the + place of IR blocks that have no expansion (factor of 1.0). This is an + alternative to having a IR with an optional first pw conv. + + Args: + in_channels (int): number of in channels. + out_channels (int): number of out channels. + dw_kernel_size (int, optional): the kernel size of depth-wise + convolution. Defaults to 3. + stride (int, optional): stride of convolution. + Defaults to 1. + dilation (int, optional): dilation rate of convolution. + Defaults to 1. + noskip (bool, optional): whether use skip connection. + Defaults to False. + pw_kernel_size (int, optional): kernel size of point wise convolution. + Defaults to 1. + pw_act (bool, optional): whether using activation in point-wise + convolution. Defaults to False. + se_cfg (Dict, optional): _description_. Defaults to None. + conv_cfg (Optional[dict], optional): Config dict for convolution layer. + Default: None, which means using conv2d. + norm_cfg (Dict, optional): Config dict for normalization layer. + Default: dict(type='BN'). + act_cfg (Dict, optional):Config dict for activation layer. + Default: dict(type='ReLU'). + """ + + def __init__(self, + in_channels: int, + out_channels: int, + dw_kernel_size: int = 3, + stride: int = 1, + dilation: int = 1, + noskip: bool = False, + pw_kernel_size: int = 1, + pw_act: bool = False, + conv_cfg: Optional[dict] = None, + se_cfg: Dict = None, + norm_cfg: Dict = dict(type='BN'), + act_cfg: Dict = dict(type='ReLU')): + + super().__init__( + in_channels=in_channels, out_channels=out_channels, stride=stride) + self.has_residual = (stride == 1 + and in_channels == out_channels) and not noskip + self.has_pw_act = pw_act # activation after point-wise conv + + self.se_cfg = se_cfg + + self.conv_dw = ConvModule( + in_channels=in_channels, + out_channels=in_channels, + kernel_size=dw_kernel_size, + stride=stride, + dilation=dilation, + padding=dw_kernel_size // 2, + groups=in_channels, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg, + ) + + # Squeeze-and-excitation + self.se = SELayer(out_channels, ** + se_cfg) if self.se_cfg else nn.Identity() + + self.conv_pw = ConvModule( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=pw_kernel_size, + padding=pw_kernel_size // 2, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg if self.has_pw_act else None, + ) + + def forward(self, x): + shortcut = x + x = self.conv_dw(x) + x = self.se(x) + x = self.conv_pw(x) + if self.has_residual: + x += shortcut + return x diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/function.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/function.py new file mode 100755 index 000000000..3509e7da4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/function.py @@ -0,0 +1,41 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List, Optional, Tuple, Union + +import torch +from torch.nn import Module, functional + + +class InputResizer(Module): + valid_interpolation_type = { + 'nearest', 'linear', 'bilinear', 'bicubic', 'trilinear', 'area', + 'nearest-exact' + } + + def __init__( + self, + interpolation_type: str = 'bicubic', + align_corners: bool = False, + scale_factor: Optional[Union[float, List[float]]] = None) -> None: + super().__init__() + + if interpolation_type not in self.valid_interpolation_type: + raise ValueError( + 'Expect `interpolation_type` be ' + f'one of {self.valid_interpolation_type}, but got: ' + f'{interpolation_type}') + self._interpolation_type = interpolation_type + self._scale_factor = scale_factor + self._align_corners = align_corners + self._size = None + + def forward(self, + x: torch.Tensor, + size: Optional[Tuple[int, int]] = None) -> torch.Tensor: + size = size if size is not None else self._size + + return functional.interpolate( + input=x, + size=size, + mode=self._interpolation_type, + scale_factor=self._scale_factor, + align_corners=self._align_corners) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/gather_tensors.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/gather_tensors.py new file mode 100755 index 000000000..7bc34fde1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/gather_tensors.py @@ -0,0 +1,58 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Any, Tuple + +import torch +import torch.distributed as dist + + +class GatherTensors(torch.autograd.Function): + """Gather tensors from all GPUS, supporting backward propagation. + + See more details in torch.distributed.all_gather and + torch.distributed.all_reduce. + """ + + @staticmethod + def forward(ctx: Any, input: torch.Tensor) -> Tuple[Any, ...]: + """Forward function. + + It must accept a context ctx as the first argument. + + The context can be used to store tensors that can be then retrieved + during the backward pass. + + Args: + ctx (Any): Context to be used for forward propagation. + input (torch.Tensor): Tensor to be broadcast from current process. + """ + output = [ + torch.empty_like(input) for _ in range(dist.get_world_size()) + ] + dist.all_gather(output, input) + return tuple(output) + + @staticmethod + def backward(ctx: Any, *grads: torch.Tensor) -> torch.Tensor: + """Backward function. + + It must accept a context :attr:`ctx` as the first argument, followed by + as many outputs did :func:`forward` return, and it should return as + many tensors, as there were inputs to :func:`forward`. Each argument is + the gradient w.r.t the given output, and each returned value should be + the gradient w.r.t. the corresponding input. + + The context can be used to retrieve tensors saved during the forward + pass. It also has an attribute :attr:`ctx.needs_input_grad` as a tuple + of booleans representing whether each input needs gradient. E.g., + :func:`backward` will have ``ctx.needs_input_grad[0] = True`` if the + first input to :func:`forward` needs gradient computated w.r.t. the + output. + + Args: + ctx (Any): Context to be used for forward propagation. + grads (torch.Tensor): Grads to be merged from current process. + """ + rank = dist.get_rank() + merged = torch.stack(grads) + dist.all_reduce(merged) + return merged[rank] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/mobilenet_series.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/mobilenet_series.py new file mode 100755 index 000000000..e6817dd87 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/mobilenet_series.py @@ -0,0 +1,217 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict + +import torch +import torch.nn.functional as F +import torch.utils.checkpoint as cp +from mmcv.cnn import ConvModule +from mmcv.cnn.bricks import build_conv_layer +from mmcv.cnn.bricks.drop import drop_path + +from mmrazor.registry import MODELS +from .base import BaseOP + +try: + from mmcls.models.utils import SELayer +except ImportError: + from mmrazor.utils import get_placeholder + SELayer = get_placeholder('mmcls') + + +class ShortcutLayer(BaseOP): + + def __init__(self, + in_channels: int, + out_channels: int, + reduction: int = 1, + conv_cfg: Dict = dict(type='Conv2d'), + init_cfg=None): + super().__init__(in_channels, out_channels, init_cfg) + + assert reduction in [1, 2] + self.reduction = reduction + + # conv module can be removed if in_channels equal to out_channels + self.conv = build_conv_layer( + conv_cfg, + in_channels=in_channels, + out_channels=out_channels, + kernel_size=1, + stride=1, + bias=False) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + if self.reduction > 1: + padding = x.size(-1) & 1 + x = F.avg_pool2d(x, self.reduction, padding=padding) + + # HACK + if hasattr(self.conv, 'mutable_in_channels' + ) and self.conv.mutable_in_channels is not None: + in_channels = self.conv.mutable_in_channels.current_mask.sum( + ).item() + else: + in_channels = self.conv.in_channels + if hasattr(self.conv, 'mutable_out_channels' + ) and self.conv.mutable_out_channels is not None: + out_channels = self.conv.mutable_out_channels.current_mask.sum( + ).item() + else: + out_channels = self.conv.out_channels + + if in_channels != out_channels: + x = self.conv(x) + + return x + + +@MODELS.register_module() +class MBBlock(BaseOP): + """Mobilenet block for Searchable backbone. + + Args: + kernel_size (int): Size of the convolving kernel. + expand_ratio (int): The input channels' expand factor of the depthwise + convolution. + se_cfg (dict, optional): Config dict for se layer. Defaults to None, + which means no se layer. + conv_cfg (dict, optional): Config dict for convolution layer. + Defaults to None, which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Defaults to dict(type='BN'). + act_cfg (dict): Config dict for activation layer. + Defaults to dict(type='ReLU'). + drop_path_rate (float): stochastic depth rate. Defaults to 0. + with_cp (bool): Use checkpoint or not. Using checkpoint will save some + memory while slowing down the training speed. Defaults to False. + with_attentive_shortcut (bool): Use shortcut in AttentiveNAS or not. + Defaults to False. + + Returns: + Tensor: The output tensor. + """ + + def __init__(self, + kernel_size: int, + expand_ratio: int, + se_cfg: Dict = None, + conv_cfg: Dict = dict(type='Conv2d'), + norm_cfg: Dict = dict(type='BN'), + act_cfg: Dict = dict(type='ReLU'), + drop_path_rate: float = 0., + with_cp: bool = False, + with_attentive_shortcut: bool = False, + **kwargs): + + super().__init__(**kwargs) + + if with_attentive_shortcut: + self.shortcut = ShortcutLayer( + in_channels=self.in_channels, + out_channels=self.out_channels, + reduction=self.stride, + conv_cfg=conv_cfg) + self.with_attentive_shortcut = with_attentive_shortcut + + self.with_res_shortcut = ( + self.stride == 1 and self.in_channels == self.out_channels + and not self.with_attentive_shortcut) + assert self.stride in [1, 2] + self._drop_path_rate = drop_path_rate + self.kernel_size = kernel_size + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.act_cfg = act_cfg + self.with_cp = with_cp + self.with_se = se_cfg is not None + self.mid_channels = self.in_channels * expand_ratio + self.with_expand_conv = (self.mid_channels != self.in_channels) + + if self.with_se: + assert isinstance(se_cfg, dict) + + if self.with_expand_conv: + self.expand_conv = ConvModule( + in_channels=self.in_channels, + out_channels=self.mid_channels, + kernel_size=1, + stride=1, + padding=0, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + self.depthwise_conv = ConvModule( + in_channels=self.mid_channels, + out_channels=self.mid_channels, + kernel_size=kernel_size, + stride=self.stride, + padding=kernel_size // 2, + groups=self.mid_channels, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=act_cfg) + if self.with_se: + self.se = SELayer(self.mid_channels, **se_cfg) + self.linear_conv = ConvModule( + in_channels=self.mid_channels, + out_channels=self.out_channels, + kernel_size=1, + stride=1, + padding=0, + conv_cfg=conv_cfg, + norm_cfg=norm_cfg, + act_cfg=None) + + @property + def drop_path_rate(self): + return self._drop_path_rate + + @drop_path_rate.setter + def drop_path_rate(self, value): + if not isinstance(value, float): + raise TypeError('Expected float.') + self._drop_path_rate = value + + def forward(self, x): + """Forward function. + + Args: + x (torch.Tensor): The input tensor. + Returns: + torch.Tensor: The output tensor. + """ + + def _inner_forward(x): + out = x + + if self.with_expand_conv: + out = self.expand_conv(out) + + out = self.depthwise_conv(out) + if self.with_se: + out = self.se(out) + + out = self.linear_conv(out) + + if self.with_res_shortcut: + if self.drop_path_rate > 0.: + out = drop_path(out, self.drop_path_rate, self.training) + return x + out + + elif self.with_attentive_shortcut: + sx = self.shortcut(x) + if self.drop_path_rate > 0. and \ + x.size(1) == sx.size(1) and \ + self.shortcut.reduction == 1: + out = drop_path(out, self.drop_path_rate, self.training) + return sx + out + + else: + return out + + if self.with_cp and x.requires_grad: + out = cp.checkpoint(_inner_forward, x) + else: + out = _inner_forward(x) + + return out diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/shufflenet_series.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/shufflenet_series.py new file mode 100755 index 000000000..efd205999 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/shufflenet_series.py @@ -0,0 +1,261 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +import torch.utils.checkpoint as cp +from mmcv.cnn import ConvModule, DepthwiseSeparableConvModule + +from mmrazor.registry import MODELS +from .base import BaseOP + +try: + from mmcls.models.utils import channel_shuffle +except ImportError: + from mmrazor.utils import get_placeholder + channel_shuffle = get_placeholder('mmcls') + + +@MODELS.register_module() +class ShuffleBlock(BaseOP): + """InvertedResidual block for Searchable ShuffleNetV2 backbone. + + Args: + kernel_size (int): Size of the convolving kernel. + stride (int): Stride of the convolution layer. Default: 1 + conv_cfg (dict, optional): Config dict for convolution layer. + Default: None, which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Default: dict(type='BN'). + act_cfg (dict): Config dict for activation layer. + Default: dict(type='ReLU'). + with_cp (bool): Use checkpoint or not. Using checkpoint will save some + memory while slowing down the training speed. Default: False. + + Returns: + Tensor: The output tensor. + """ + + def __init__(self, + kernel_size, + conv_cfg=None, + norm_cfg=dict(type='BN'), + act_cfg=dict(type='ReLU'), + with_cp=False, + **kwargs): + + super(ShuffleBlock, self).__init__(**kwargs) + + assert kernel_size in [3, 5, 7] + self.kernel_size = kernel_size + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.act_cfg = act_cfg + self.with_cp = with_cp + + branch_features = self.out_channels // 2 + if self.stride == 1: + assert self.in_channels == branch_features * 2, ( + f'in_channels ({self.in_channels}) should equal to ' + f'branch_features * 2 ({branch_features * 2}) ' + 'when stride is 1') + + if self.in_channels != branch_features * 2: + assert self.stride != 1, ( + f'stride ({self.stride}) should not equal 1 when ' + f'in_channels != branch_features * 2') + + if self.stride > 1: + self.branch1 = nn.Sequential( + ConvModule( + self.in_channels, + self.in_channels, + kernel_size=self.kernel_size, + stride=self.stride, + padding=self.kernel_size // 2, + groups=self.in_channels, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=None), + ConvModule( + self.in_channels, + branch_features, + kernel_size=1, + stride=1, + padding=0, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=self.act_cfg), + ) + + self.branch2 = nn.Sequential( + ConvModule( + self.in_channels if (self.stride > 1) else branch_features, + branch_features, + kernel_size=1, + stride=1, + padding=0, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=self.act_cfg), + ConvModule( + branch_features, + branch_features, + kernel_size=self.kernel_size, + stride=self.stride, + padding=self.kernel_size // 2, + groups=branch_features, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=None), + ConvModule( + branch_features, + branch_features, + kernel_size=1, + stride=1, + padding=0, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=self.act_cfg)) + + def forward(self, x): + + def _inner_forward(x): + if self.stride > 1: + out = torch.cat((self.branch1(x), self.branch2(x)), dim=1) + else: + x1, x2 = x.chunk(2, dim=1) + out = torch.cat((x1, self.branch2(x2)), dim=1) + + out = channel_shuffle(out, 2) + + return out + + if self.with_cp and x.requires_grad: + out = cp.checkpoint(_inner_forward, x) + else: + out = _inner_forward(x) + + return out + + +@MODELS.register_module() +class ShuffleXception(BaseOP): + """Xception block for ShuffleNetV2 backbone. + + Args: + conv_cfg (dict, optional): Config dict for convolution layer. + Defaults to None, which means using conv2d. + norm_cfg (dict): Config dict for normalization layer. + Defaults to dict(type='BN'). + act_cfg (dict): Config dict for activation layer. + Defaults to dict(type='ReLU'). + with_cp (bool): Use checkpoint or not. Using checkpoint will save some + memory while slowing down the training speed. Defaults to False. + + Returns: + Tensor: The output tensor. + """ + + def __init__(self, + conv_cfg=None, + norm_cfg=dict(type='BN'), + act_cfg=dict(type='ReLU'), + with_cp=False, + **kwargs): + super(ShuffleXception, self).__init__(**kwargs) + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.act_cfg = act_cfg + self.with_cp = with_cp + self.mid_channels = self.out_channels // 2 + + branch_features = self.out_channels // 2 + if self.stride == 1: + assert self.in_channels == branch_features * 2, ( + f'in_channels ({self.in_channels}) should equal to ' + f'branch_features * 2 ({branch_features * 2}) ' + 'when stride is 1') + + if self.in_channels != branch_features * 2: + assert self.stride != 1, ( + f'stride ({self.stride}) should not equal 1 when ' + f'in_channels != branch_features * 2') + + if self.stride > 1: + self.branch1 = nn.Sequential( + ConvModule( + self.in_channels, + self.in_channels, + kernel_size=3, + stride=self.stride, + padding=1, + groups=self.in_channels, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=None), + ConvModule( + self.in_channels, + branch_features, + kernel_size=1, + stride=1, + padding=0, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=self.act_cfg), + ) + + self.branch2 = [] + + self.branch2.append( + DepthwiseSeparableConvModule( + self.in_channels if (self.stride > 1) else branch_features, + self.mid_channels, + kernel_size=3, + stride=self.stride, + padding=1, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + dw_act_cfg=None, + act_cfg=self.act_cfg), ) + self.branch2.append( + DepthwiseSeparableConvModule( + self.mid_channels, + self.mid_channels, + kernel_size=3, + stride=1, + padding=1, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + dw_act_cfg=None, + act_cfg=self.act_cfg)) + self.branch2.append( + DepthwiseSeparableConvModule( + self.mid_channels, + branch_features, + kernel_size=3, + stride=1, + padding=1, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + dw_act_cfg=None, + act_cfg=self.act_cfg)) + self.branch2 = nn.Sequential(*self.branch2) + + def forward(self, x): + + def _inner_forward(x): + if self.stride > 1: + out = torch.cat((self.branch1(x), self.branch2(x)), dim=1) + else: + x1, x2 = x.chunk(2, dim=1) + out = torch.cat((x1, self.branch2(x2)), dim=1) + + out = channel_shuffle(out, 2) + + return out + + if self.with_cp and x.requires_grad: + out = cp.checkpoint(_inner_forward, x) + else: + out = _inner_forward(x) + + return out diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/transformer_series.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/transformer_series.py new file mode 100755 index 000000000..fd8fb0974 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/transformer_series.py @@ -0,0 +1,193 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Optional + +import torch +import torch.nn as nn +from mmengine.model.weight_init import trunc_normal_ + + +class RelativePosition2D(nn.Module): + """Rethinking and Improving Relative Position Encoding for Vision + Transformer. + + ICCV 2021. https://arxiv.org/pdf/2107.14222.pdf + Image RPE (iRPE for short) methods are new relative position encoding + methods dedicated to 2D images. + Args: + head_dims (int): embedding dims of relative position. + max_relative_position (int): The max relative position distance. + """ + + def __init__(self, head_dims: int, max_relative_position: int = 14): + super().__init__() + + self.head_dims = head_dims + self.max_relative_position = max_relative_position + # The first element in embeddings_table_v is the vertical embedding + # for the class + self.embeddings_table_v = nn.Parameter( + torch.randn(max_relative_position * 2 + 2, head_dims)) + self.embeddings_table_h = nn.Parameter( + torch.randn(max_relative_position * 2 + 2, head_dims)) + + trunc_normal_(self.embeddings_table_v, std=.02) + trunc_normal_(self.embeddings_table_h, std=.02) + + def forward(self, length_q, length_k): + # remove the first cls token distance computation + length_q = length_q - 1 + length_k = length_k - 1 + range_vec_q = torch.arange(length_q) + range_vec_k = torch.arange(length_k) + # compute the row and column distance + distance_mat_v = ( + range_vec_k[None, :] // int(length_q**0.5) - + range_vec_q[:, None] // int(length_q**0.5)) + distance_mat_h = ( + range_vec_k[None, :] % int(length_q**0.5) - + range_vec_q[:, None] % int(length_q**0.5)) + # clip the distance to the range of + # [-max_relative_position, max_relative_position] + distance_mat_clipped_v = torch.clamp(distance_mat_v, + -self.max_relative_position, + self.max_relative_position) + distance_mat_clipped_h = torch.clamp(distance_mat_h, + -self.max_relative_position, + self.max_relative_position) + + # translate the distance from [1, 2 * max_relative_position + 1], + # 0 is for the cls token + final_mat_v = distance_mat_clipped_v + self.max_relative_position + 1 + final_mat_h = distance_mat_clipped_h + self.max_relative_position + 1 + # pad the 0 which represent the cls token + final_mat_v = torch.nn.functional.pad(final_mat_v, (1, 0, 1, 0), + 'constant', 0) + final_mat_h = torch.nn.functional.pad(final_mat_h, (1, 0, 1, 0), + 'constant', 0) + + final_mat_v = torch.LongTensor(final_mat_v) + final_mat_h = torch.LongTensor(final_mat_h) + # get the embeddings with the corresponding distance + embeddings = self.embeddings_table_v[ + final_mat_v] + self.embeddings_table_h[final_mat_h] + + return embeddings + + +class MultiheadAttention(nn.Module): + """Multi-head Attention Module with iRPE. + + This module implements multi-head attention that supports different input + dims and embed dims. And it also supports a shortcut from ``value``, which + is useful if input dims is not the same with embed dims. + + Args: + embed_dims (int): The embedding dimension. + num_heads (int): Parallel attention heads. + input_dims (int, optional): The input dimension, and if None, + use ``embed_dims``. Defaults to None. + attn_drop_rate (float): Dropout rate of the dropout layer after the + attention calculation of query and key. Defaults to 0. + proj_drop_rate (float): Dropout rate of the dropout layer after the + output projection. Defaults to 0. + out_drop_rate (dict): Dropout rate of the dropout layer before adding + the shortcut. Defaults to 0. + relative_position (bool, optional): Whether use relative position. + Defaults to True. + max_relative_position (int): The max relative position distance. + qkv_bias (bool): If True, add a learnable bias to q, k, v. + Defaults to True. + qk_scale (float, optional): Override default qk scale of + ``head_dim ** -0.5`` if set. Defaults to None. + proj_bias (bool) If True, add a learnable bias to output projection. + Defaults to True. + v_shortcut (bool): Add a shortcut from value to output. It's usually + used if ``input_dims`` is different from ``embed_dims``. + Defaults to False. + init_cfg (dict, optional): The Config for initialization. + Defaults to None. + """ + + def __init__(self, + embed_dims: int, + num_heads: int, + input_dims: Optional[int] = None, + attn_drop_rate: float = 0., + proj_drop_rate: float = 0., + out_drop_rate: float = 0., + relative_position: Optional[bool] = True, + max_relative_position: int = 14, + qkv_bias: bool = True, + qk_scale: Optional[float] = None, + proj_bias: bool = True, + v_shortcut: bool = False, + init_cfg: Optional[dict] = None): + super().__init__() + + self.input_dims = input_dims or embed_dims + self.embed_dims = embed_dims + self.num_heads = num_heads + self.v_shortcut = v_shortcut + self.relative_position = relative_position + self.max_relative_position = max_relative_position + + self.head_dims = 64 # unit + self.scale = qk_scale or self.head_dims**-0.5 + + self.q_embed_dims = num_heads * self.head_dims + + self.w_qs = nn.Linear( + self.input_dims, num_heads * self.head_dims, bias=qkv_bias) + self.w_ks = nn.Linear( + self.input_dims, num_heads * self.head_dims, bias=qkv_bias) + self.w_vs = nn.Linear( + self.input_dims, num_heads * self.head_dims, bias=qkv_bias) + + self.attn_drop = nn.Dropout(attn_drop_rate) + self.proj_drop = nn.Dropout(proj_drop_rate) + self.out_drop = nn.Dropout(out_drop_rate) + + self.proj = nn.Linear( + num_heads * self.head_dims, embed_dims, bias=proj_bias) + + # image relative position encoding + if self.relative_position: + self.rel_pos_embed_k = RelativePosition2D( + self.head_dims, self.max_relative_position) + self.rel_pos_embed_v = RelativePosition2D( + self.head_dims, self.max_relative_position) + + def forward(self, x): + B, N, _ = x.shape + + q = self.w_qs(x).view(B, N, self.num_heads, self.head_dims) + k = self.w_ks(x).view(B, N, self.num_heads, self.head_dims) + v = self.w_vs(x).view(B, N, self.num_heads, self.head_dims) + + q, k, v = q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2) + + attn = (q @ k.transpose(-2, -1)) * self.scale + + if self.relative_position: + r_p_k = self.rel_pos_embed_k(N, N) + attn = attn + (q.permute(2, 0, 1, 3).reshape(N, self.num_heads * B, -1) # noqa: E501 + @ r_p_k.transpose(2, 1)) \ + .transpose(1, 0).reshape(B, self.num_heads, N, N) * self.scale + + attn = attn.softmax(dim=-1) + attn = self.attn_drop(attn) + x = (attn @ v).transpose(1, 2).reshape(B, N, -1) + + if self.relative_position: + r_p_v = self.rel_pos_embed_v(N, N) + t_attn = attn.permute(2, 0, 1, 3).reshape(N, B * self.num_heads, + -1) + x = x + (t_attn @ r_p_v).transpose(1, 0).reshape( + B, self.num_heads, N, -1).transpose(2, 1).reshape(B, N, -1) + + x = self.proj(x) + x = self.out_drop(self.proj_drop(x)) + + if self.v_shortcut: + x = v.squeeze(1) + x + return x diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/__init__.py new file mode 100755 index 000000000..7072a29d8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .mutable_register import mutate_conv_module, mutate_mobilenet_layer +from .set_dropout import set_dropout + +__all__ = ['mutate_conv_module', 'mutate_mobilenet_layer', 'set_dropout'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/mutable_register.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/mutable_register.py new file mode 100755 index 000000000..f3a916748 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/mutable_register.py @@ -0,0 +1,86 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Optional, Sequence, Tuple + +from mmrazor.models.architectures.ops.mobilenet_series import MBBlock +from ...mutables.base_mutable import BaseMutable +from ...mutables.mutable_channel import MutableChannelContainer + + +def mutate_conv_module( + conv_module, + mutable_in_channels: Optional[BaseMutable] = None, + mutable_out_channels: Optional[BaseMutable] = None, + mutable_kernel_size: Optional[Tuple[BaseMutable, + Sequence[int]]] = None): + """Mutate a conv module.""" + if mutable_in_channels is not None: + MutableChannelContainer.register_mutable_channel_to_module( + conv_module.conv, mutable_in_channels, False) + + if mutable_out_channels is not None: + MutableChannelContainer.register_mutable_channel_to_module( + conv_module.conv, mutable_out_channels, True) + + if hasattr(conv_module, 'bn'): + MutableChannelContainer.register_mutable_channel_to_module( + conv_module.bn, mutable_out_channels, False) + + if mutable_kernel_size is not None: + conv_module.conv.register_mutable_attr('kernel_size', + mutable_kernel_size) + + +def mutate_mobilenet_layer(mb_layer: MBBlock, + mutable_in_channels, + mutable_out_channels, + mutable_expand_ratio, + mutable_kernel_size, + fine_grained_mode: bool = False): + """Mutate MobileNet layers.""" + mb_layer.derived_expand_channels = \ + mutable_expand_ratio * mutable_in_channels + + if mb_layer.with_expand_conv: + mutate_conv_module( + mb_layer.expand_conv, + mutable_in_channels=mutable_in_channels, + mutable_out_channels=mb_layer.derived_expand_channels) + + mutate_conv_module( + mb_layer.depthwise_conv, + mutable_in_channels=mb_layer.derived_expand_channels, + mutable_out_channels=mb_layer.derived_expand_channels, + mutable_kernel_size=mutable_kernel_size) + + if mb_layer.with_se: + if fine_grained_mode: + mutable_expand_ratio2 = copy.deepcopy(mutable_expand_ratio) + mutable_expand_ratio2.alias += '_se' + derived_se_channels = mutable_expand_ratio2 * mutable_in_channels + mb_layer.derived_se_channels = \ + derived_se_channels.derive_divide_mutable(4, 8) + else: + mb_layer.derived_se_channels = \ + mb_layer.derived_expand_channels.derive_divide_mutable(4, 8) + + mutate_conv_module( + mb_layer.se.conv1, + mutable_in_channels=mb_layer.derived_expand_channels, + mutable_out_channels=mb_layer.derived_se_channels) + mutate_conv_module( + mb_layer.se.conv2, + mutable_in_channels=mb_layer.derived_se_channels, + mutable_out_channels=mb_layer.derived_expand_channels) + + if not mb_layer.with_res_shortcut: + if mb_layer.with_attentive_shortcut: + MutableChannelContainer.register_mutable_channel_to_module( + mb_layer.shortcut.conv, mutable_in_channels, False) + MutableChannelContainer.register_mutable_channel_to_module( + mb_layer.shortcut.conv, mutable_out_channels, True) + + mutate_conv_module( + mb_layer.linear_conv, + mutable_in_channels=mb_layer.derived_expand_channels, + mutable_out_channels=mutable_out_channels) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/set_dropout.py b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/set_dropout.py new file mode 100755 index 000000000..f45f03a03 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/set_dropout.py @@ -0,0 +1,35 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List + +from ..dynamic_ops.bricks import DynamicSequential + + +def set_dropout(layers, module, dropout_stages: List[int], + drop_path_rate: float) -> None: + """Dynamically set dropout rate for layers by depth. + + Args: + layers: Layers in MobileNet-style networks. + module: Specific module to set a different ratio. + dropout_stages (List[int]): Stages to be set dropout. + drop_path_rate (float): Drop path rate for layers. + """ + assert hasattr(module, 'drop_path_rate') + visited_block_nums = 0 + total_block_nums = len([ + block for layer in layers for block in layer + if isinstance(block, module) + ]) + for idx, layer in enumerate(layers, start=1): + assert isinstance(layer, DynamicSequential) + mblayer_nums = len( + [block for block in layer if isinstance(block, module)]) + visited_block_nums += mblayer_nums + if idx not in dropout_stages: + continue + + for block_idx, block in enumerate(layer): + if isinstance(block, module) and hasattr(block, 'drop_path_rate'): + ratio = (visited_block_nums - mblayer_nums + + block_idx) / total_block_nums + block.drop_path_rate = drop_path_rate * ratio diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/__init__.py new file mode 100755 index 000000000..d2d70bd26 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/__init__.py @@ -0,0 +1,9 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .base_distiller import BaseDistiller +from .byot_distiller import BYOTDistiller +from .configurable_distiller import ConfigurableDistiller +from .ofd_distiller import OFDDistiller + +__all__ = [ + 'ConfigurableDistiller', 'BaseDistiller', 'BYOTDistiller', 'OFDDistiller' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/base_distiller.py b/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/base_distiller.py new file mode 100755 index 000000000..4cf575e90 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/base_distiller.py @@ -0,0 +1,22 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import ABC, abstractmethod +from typing import Dict, Optional + +from mmengine.model import BaseModule + +from ..algorithms.base import LossResults + + +class BaseDistiller(BaseModule, ABC): + """Base class for distiller. + + Args: + init_cfg (dict, optional): Config for distiller. Default to None. + """ + + def __init__(self, init_cfg: Optional[Dict] = None) -> None: + super().__init__(init_cfg) + + @abstractmethod + def compute_distill_losses(self) -> LossResults: + """Compute distill losses automatically.""" diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/byot_distiller.py b/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/byot_distiller.py new file mode 100755 index 000000000..fca0d774e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/byot_distiller.py @@ -0,0 +1,44 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List, Optional + +from mmrazor.registry import MODELS +from .configurable_distiller import ConfigurableDistiller + + +@MODELS.register_module() +class BYOTDistiller(ConfigurableDistiller): + """``BYOTDistiller`` inherits ``ConfigurableDistiller`` and only modifies + ``get_record()`` function to ``get_record_with_cidx()``. + + In ``BYOTDistiller``, ``self.teacher_recorder`` records self-teacher data + which requires detach(). + """ + + def get_record(self, + recorder: str, + from_student: bool, + record_idx: int = 0, + data_idx: Optional[int] = None, + connector: Optional[str] = None, + connector_idx: Optional[int] = None) -> List: + """According to each item in ``record_infos``, get the corresponding + record in ``recorder_manager``. + + Detach teacher_record. + """ + + if from_student: + recorder_ = self.student_recorders.get_recorder(recorder) + else: + recorder_ = self.teacher_recorders.get_recorder(recorder) + record_data = recorder_.get_record_data(record_idx, data_idx) + + if connector: + record_data = self.connectors[connector](record_data) + if connector_idx is not None: + record_data = record_data[connector_idx] + # Detach self-teacher output Tensor from model, assert hook tensor. + if not from_student: + record_data = record_data.detach() + + return record_data diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/configurable_distiller.py b/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/configurable_distiller.py new file mode 100755 index 000000000..e6c5c267e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/configurable_distiller.py @@ -0,0 +1,294 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import warnings +from inspect import signature +from typing import Dict, List, Optional, Union + +from mmengine.model import BaseModel +from torch import nn + +from mmrazor.registry import MODELS +from ..algorithms.base import LossResults +from ..task_modules import DistillDeliveryManager, RecorderManager +from .base_distiller import BaseDistiller + + +@MODELS.register_module() +class ConfigurableDistiller(BaseDistiller): + """``ConfigurableDistiller`` is a powerful tool that can reproduce most + distillation algorithms without modifying the code of teacher or student + models. + + ``ConfigurableDistiller`` can get various intermediate results of the + model in a hacky way by ``Recorder``. More details see user-docs for + ``Recorder``. + + ``ConfigurableDistiller`` can use the teacher's intermediate results to + override the student's intermediate results in a hacky way by ``Delivery``. + More details see user-docs for ``Delivery``. + + Args: + student_recorders (dict, optional): Config for multiple recorders. A + student model may have more than one recorder. These recorders + only record the student model's intermediate results. Defaults to + None. + teacher_recorders (dict, optional): Config for multiple recorders. A + teacher model may have more than one recorder. These recorders + only record the teacher model's intermediate results. Defaults to + None. + distill_deliveries (dict, optional): Config for multiple deliveries. A + distill algorithm may have more than one delivery. Defaults to + None. + connectors (dict, optional): Config for multiple connectors. A + distillation model may have more than one connector. Defaults to + None. + distill_losses: (Dict[str, Dict], optional): Config for multiple + distill losses. A distill algorithm may have more than one distill + loss. Defaults to None. + loss_forward_mappings: (Dict[str, Dict], optional): Mapping between + distill loss forward arguments and records. + + Note: + If a distill loss needs to backward, the name of the loss must contain + "loss". If it is only used as a statistical value, the name can not + contain "loss". More details see docs for + :func:`mmengine.model.BaseModel._parse_loss`. + + Note: + The keys of ``loss_forward_mappings`` should be consistent with the + keys of ``distill_losses``. + + Each item in ``loss_forward_mappings`` is a mapping between a distill + loss and its forward arguments. The keys of the mapping are the + signature of the loss's forward, and the values of the mapping are the + recorded data location. + + ``from_recorder``refers to the recorder where the data is stored, and + if ``from_student`` is True, it means the recorder is in ` + `student_recorders``; otherwise, it means the recorder is in + ``teacher_recorders``. + + A connector can be called according to its `connector_name`, so that a + input can use a different connector in different loss. + + Examples: + >>> distill_losses = dict( + ... loss_neck=dict(type='L2Loss', loss_weight=5)) + + >>> student_recorders = dict( + ... feat = dict(type='ModuleOutputs', sources='neck.gap')) + + >>> teacher_recorders = dict( + ... feat = dict(type='ModuleOutputs', sources='neck.gap')) + + >>> connectors = dict( + ... loss_neck_sfeat = dict( + ... type='SingleConvConnector', in_channel=32, out_channel=64), + ... loss_neck_tfeat = dict( + ... type='SingleConvConnector', in_channel=32, out_channel=64)) + + >>> loss_forward_mappings = dict( + ... loss_neck=dict( + ... s_feature=dict(from_recorder='feat', from_student=True, + ... connector='loss_neck_sfeat'), + ... t_feature=dict(from_recorder='feat', from_student=False, + ... connector='loss_neck_tfeat'))) + """ + + def __init__(self, + student_recorders: Optional[Dict[str, Dict]] = None, + teacher_recorders: Optional[Dict[str, Dict]] = None, + distill_deliveries: Optional[Dict[str, Dict]] = None, + connectors: Optional[Dict[str, Dict]] = None, + distill_losses: Optional[Dict[str, Dict]] = None, + loss_forward_mappings: Optional[Dict[str, Dict]] = None, + **kwargs): + super().__init__(**kwargs) + # The recorder manager is just constructed, but not really initialized + # yet. Recorder manager initialization needs to input the corresponding + # model. + self.student_recorders = RecorderManager(student_recorders) + self.teacher_recorders = RecorderManager(teacher_recorders) + + self.deliveries = DistillDeliveryManager(distill_deliveries) + + self.distill_losses = self.build_distill_losses(distill_losses) + + self.connectors = self.build_connectors(connectors) + + if loss_forward_mappings: + # Check if loss_forward_mappings is in the correct format. + self._check_loss_forward_mappings(self.distill_losses, + loss_forward_mappings, + self.student_recorders, + self.teacher_recorders) + self.loss_forward_mappings = loss_forward_mappings + else: + self.loss_forward_mappings = dict() + + def set_deliveries_override(self, override: bool) -> None: + """Set the `override_data` of all deliveries.""" + self.deliveries.override_data = override + + def prepare_from_student(self, model: BaseModel) -> None: + """Initialize student recorders.""" + self.student_recorders.initialize(model) + + def prepare_from_teacher(self, model: nn.Module) -> None: + """Initialize teacher recorders.""" + self.teacher_recorders.initialize(model) + + def build_connectors( + self, + connectors: Optional[Union[Dict[str, List], Dict[str, Dict]]] = None, + ) -> nn.ModuleDict: + """Initialize connectors.""" + + distill_connecotrs = nn.ModuleDict() + if connectors: + for connector_name, connector_cfg in connectors.items(): + if isinstance(connector_cfg, dict): + connector = MODELS.build(connector_cfg) + distill_connecotrs[connector_name] = connector + else: + assert isinstance(connector_cfg, list) + module_list = [] + for cfg in connector_cfg: + connector = MODELS.build(cfg) + module_list.append(connector) + distill_connecotrs[connector_name] = nn.Sequential( + *module_list) + + return distill_connecotrs + + def build_distill_losses( + self, + losses: Optional[Dict[str, Dict]] = None, + ) -> nn.ModuleDict: + """build distill losses according config.""" + + distill_losses = nn.ModuleDict() + if losses: + for loss_name, loss_cfg in losses.items(): + assert loss_name not in distill_losses + if 'loss' not in loss_name: + warnings.warn( + f'Warning: If {loss_name} is a loss that needs to ' + f'backward, the name of {loss_name} must contain ' + f'"loss". If it is only used as a statistical value, ' + 'then the name must not contain "loss". More details ' + 'see docs for ' + ':func:`mmengine.model.BaseModel._parse_loss`', + UserWarning) + item_loss = MODELS.build(loss_cfg) + distill_losses[loss_name] = item_loss + + return distill_losses + + def get_record(self, + recorder: str, + from_student: bool, + record_idx: int = 0, + data_idx: Optional[int] = None, + connector: Optional[str] = None, + connector_idx: Optional[int] = None) -> List: + """According to each item in ``record_infos``, get the corresponding + record in ``recorder_manager``.""" + + if from_student: + recorder_ = self.student_recorders.get_recorder(recorder) + else: + recorder_ = self.teacher_recorders.get_recorder(recorder) + record_data = recorder_.get_record_data(record_idx, data_idx) + + if connector: + record_data = self.connectors[connector](record_data) + if connector_idx is not None: + record_data = record_data[connector_idx] + + return record_data + + def compute_distill_losses(self) -> LossResults: + """Compute distill losses automatically.""" + # Record all computed losses' results. + losses = dict() + for loss_name, forward_mappings in self.loss_forward_mappings.items(): + forward_kwargs = dict() + for forward_key, record in forward_mappings.items(): + forward_var = self.get_record(**record) + forward_kwargs[forward_key] = forward_var + + loss_module = self.distill_losses[loss_name] + loss = loss_module(**forward_kwargs) # type: ignore + # add computed loss result. + losses[loss_name] = loss + + return losses + + def _check_loss_forward_mappings( + self, losses: nn.ModuleDict, loss_forward_mappings: Dict[str, + Dict], + student_recorders: RecorderManager, + teacher_recorders: RecorderManager) -> None: + """Check if ``loss_forward_mappings`` is in the correct format.""" + + if not isinstance(loss_forward_mappings, dict): + raise TypeError( + 'loss_forward_mappings should be a dict instance, but got' + f'{type(loss_forward_mappings)}') + + for loss_name, forward_mappings in loss_forward_mappings.items(): + assert loss_name in losses, \ + f'"{loss_name}" is not in distill losses. The keys of ' \ + 'loss_forward_kwargs must match the keys of distill_losses.' + + if not isinstance(forward_mappings, dict): + raise TypeError( + 'Each item of loss_forward_mappings should be a dict ' + f'instance, but got {type(forward_mappings)}') + + loss_module = losses[loss_name] + loss_forward_params = signature(loss_module.forward).parameters + loss_forward_keys = loss_forward_params.keys() + # Allow default params. + # Check non-default params, not len(params). + + for forward_key, record_info in forward_mappings.items(): + assert forward_key in loss_forward_keys, \ + f'{forward_key} is not in the signature of \ + {type(loss_module).__name__} forward, \ + please check your config.' + + if (loss_forward_params[forward_key].default != + loss_forward_params[forward_key].empty): + # default params without check + continue + + assert 'recorder' in record_info, \ + 'Each item of loss_forward_mappings should have ' \ + '"recorder", pls check your config.' + + assert 'from_student' in record_info, \ + 'Each item of loss_forward_mappings should have ' \ + '"from_student", pls check your config.' + + recorder: str = record_info['recorder'] + from_student: bool = record_info['from_student'] + + if not isinstance(from_student, bool): + raise TypeError(f'from_student should be a bool instance, ' + f'but got {type(from_student)}') + + if from_student: + assert recorder in student_recorders.recorders, \ + f'For {forward_key}, "{recorder}" must be in \ + `student_recorders`.' + + else: + assert recorder in teacher_recorders.recorders, \ + f'For {forward_key}, "{recorder}" must be in \ + `teacher_recorders`.' + + if 'connector' in record_info: + connector: str = record_info['connector'] + assert connector in self.connectors, \ + f'{connector} must be in "connectors".' diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/ofd_distiller.py b/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/ofd_distiller.py new file mode 100755 index 000000000..6aed9ae35 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/ofd_distiller.py @@ -0,0 +1,77 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import math +from operator import attrgetter + +import torch +import torch.nn as nn + +try: + from scipy.stats import norm +except ImportError: + from mmrazor.utils import get_placeholder + norm = get_placeholder('norm') + +from mmrazor.registry import MODELS +from ..architectures.connectors import OFDTeacherConnector +from ..losses import OFDLoss +from .configurable_distiller import ConfigurableDistiller + + +@MODELS.register_module() +class OFDDistiller(ConfigurableDistiller): + """Distiller for ``OverhaulFeatureDistillation``, inherited from + ``ConfigurableDistiller``, add func: + + ``init_ofd_connectors`` to initialize margin. + """ + + def init_ofd_connectors(self, teacher: nn.Module) -> None: + """Initialize OFD connectors' `margin`.""" + for loss_key, loss_forward_mapping in self.loss_forward_mappings.items( + ): + if isinstance(self.distill_losses[loss_key], OFDLoss): + for _input_keys, _input_mapping in loss_forward_mapping.items( + ): + if 'connector' in _input_mapping and not _input_mapping[ + 'from_student']: + + recorder = self.teacher_recorders.get_recorder( + _input_mapping['recorder']) + module_key = recorder.source + bn_module = attrgetter(module_key)(teacher) + + assert isinstance( + bn_module, (nn.BatchNorm2d, nn.SyncBatchNorm) + ), ('Overhaul distillation only support connection on ' + 'layers: [`BatchNorm2d`, `SyncBatchNorm`]') + connector = self.connectors[ + _input_mapping['connector']] + assert isinstance(connector, OFDTeacherConnector), ( + 'OFD loss mapping for `t_feature` expect type ' + '`OFDTeacherConnector`, but get ' + f'`{type(connector)}`') + margin = self._get_margin_from_BN(bn_module) + connector.init_margin(margin) + + def _get_margin_from_BN(self, bn: nn.BatchNorm2d) -> torch.Tensor: + """Get margin from BN layer. + + Args: + bn (nn.BatchNorm2d): input module, must be a BN layer. + + Returns: + torch.Tensor: margin + """ + margin = [] + std = bn.weight.data + mean = bn.bias.data + for (s, m) in zip(std, mean): + s = abs(s.item()) + m = m.item() + if norm.cdf(-m / s) > 0.001: + margin.append(-s * math.exp(-(m / s)**2 / 2) / + math.sqrt(2 * math.pi) / norm.cdf(-m / s) + m) + else: + margin.append(-3 * s) + return torch.FloatTensor(margin).unsqueeze(1).unsqueeze(2).unsqueeze( + 0).detach() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/__init__.py new file mode 100755 index 000000000..950821210 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/__init__.py @@ -0,0 +1,10 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .base import BaseFakeQuantize +from .lsq import (LearnableFakeQuantize, enable_param_learning, + enable_static_estimate, enable_val) +from .torch_fake_quants import register_torch_fake_quants + +__all__ = [ + 'BaseFakeQuantize', 'register_torch_fake_quants', 'LearnableFakeQuantize', + 'enable_val', 'enable_param_learning', 'enable_static_estimate' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/base.py b/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/base.py new file mode 100755 index 000000000..45aed7421 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/base.py @@ -0,0 +1,8 @@ +# Copyright (c) OpenMMLab. All rights reserved. +try: + from torch.ao.quantization import FakeQuantize +except ImportError: + from mmrazor.utils import get_placeholder + FakeQuantize = get_placeholder('torch>=1.13') + +BaseFakeQuantize = FakeQuantize diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/lsq.py b/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/lsq.py new file mode 100755 index 000000000..1689d0393 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/lsq.py @@ -0,0 +1,313 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +from torch.nn.parameter import Parameter + +from mmrazor.registry import MODELS + +try: + from torch.ao.quantization import FakeQuantizeBase +except ImportError: + from mmrazor.utils import get_placeholder + FakeQuantizeBase = get_placeholder('torch>=1.13') + + +def enable_param_learning(mod): + """Enables learning of quantization parameters, if applicable. Example + usage:: + + # model is any PyTorch model model.apply(enable_param_learning) + """ + if isinstance(mod, LearnableFakeQuantize): + mod.enable_param_learning() + + +def enable_static_estimate(mod): + """Enables static observer estimates, if applicable. Example usage:: + + # model is any PyTorch model model.apply(enable_static_estimate) + """ + if isinstance(mod, LearnableFakeQuantize): + mod.enable_static_estimate() + + +def enable_val(mod): + """Enable validation, if applicable. Example usage:: + + # model is any PyTorch model model.apply(enable_val) + """ + if isinstance(mod, LearnableFakeQuantize): + mod.enable_val() + + +@MODELS.register_module() +class LearnableFakeQuantize(FakeQuantizeBase): + """This is an extension of the FakeQuantize module in fake_quantize.py, + which supports learning of the scale and zero point parameters through + backpropagation. + + In addition to the attributes in the original FakeQuantize module, the + LearnableFakeQuantize module also includes the following attributes to + support quantization parameter learning. + + * :attr:`fake_quant_enabled` defines the flag for enabling fake + quantization on the output. + + * :attr:`static_enabled` defines the flag for using observer's static + estimation for scale and zero point. + + * :attr:`learning_enabled` defines the flag for enabling backpropagation + for scale and zero point. + + Args: + observer (module): Module for observing statistics on input tensors and + calculating scale and zero-point. + quant_min (int): Minimum quantization value. If unspecified, it will + follow the 8-bit setup. + quant_max (int): Maximum quantization value. If unspecified, it will + follow the 8-bit setup. + scale (float): The initial value of the floating-point scale factor. + Defaults to 1. + zero_point (float): The initial value of the floating-point zero-point. + Defaults to 0. + use_grad_scaling (bool): Whether the gradients for scale and zero point + are normalized by the constant, which is proportional to the square + root of the number of elements in the tensor. The related + literature justifying the use of this particular constant can be + found here: https://openreview.net/pdf?id=rkgO66VKDS. Defaults to + True. + zero_point_trainable (bool): Whether the zero_point is trainable. + Defaults to False. + observer_kwargs (dict | optional): Arguments for the observer module. + """ + + def __init__(self, + observer, + quant_min=0, + quant_max=255, + scale=1., + zero_point=0., + use_grad_scaling=True, + zero_point_trainable=False, + **observer_kwargs): + super(LearnableFakeQuantize, self).__init__() + assert quant_min < quant_max, \ + 'quant_min must be strictly less than quant_max.' + self.quant_min = quant_min + self.quant_max = quant_max + # also pass quant_min and quant_max to observer + observer_kwargs['quant_min'] = quant_min + observer_kwargs['quant_max'] = quant_max + self.use_grad_scaling = use_grad_scaling + + self.scale = Parameter(torch.tensor([scale])) + self.zero_point_trainable = zero_point_trainable + if zero_point_trainable: + self.zero_point = Parameter(torch.tensor([zero_point])) + else: + self.register_buffer('zero_point', torch.tensor([zero_point])) + + self.activation_post_process = observer(**observer_kwargs) + assert \ + torch.iinfo(self.activation_post_process.dtype).min <= quant_min, \ + 'quant_min out of bound' + assert \ + quant_max <= torch.iinfo(self.activation_post_process.dtype).max, \ + 'quant_max out of bound' + self.dtype = self.activation_post_process.dtype + self.qscheme = self.activation_post_process.qscheme + self.ch_axis = self.activation_post_process.ch_axis \ + if hasattr(self.activation_post_process, 'ch_axis') else -1 + self.register_buffer('fake_quant_enabled', + torch.tensor([1], dtype=torch.uint8)) + self.register_buffer('static_enabled', + torch.tensor([1], dtype=torch.uint8)) + self.register_buffer('learning_enabled', + torch.tensor([0], dtype=torch.uint8)) + + bitrange = torch.tensor(quant_max - quant_min + 1).double() + self.bitwidth = int(torch.log2(bitrange).item()) + self.register_buffer('eps', + torch.tensor([torch.finfo(torch.float32).eps])) + + @torch.jit.export + def enable_param_learning(self): + """Enables learning of quantization parameters and disables static + observer estimates. + + Forward path returns fake quantized X. + """ + self.toggle_qparam_learning(enabled=True) \ + .toggle_fake_quant(enabled=True) \ + .toggle_observer_update(enabled=False) + return self + + @torch.jit.export + def enable_static_estimate(self): + """Enables static observer estimates and disables learning of + quantization parameters. + + Forward path returns fake quantized X. + """ + self.toggle_qparam_learning(enabled=False) \ + .toggle_fake_quant(enabled=True) \ + .toggle_observer_update(enabled=True) + + @torch.jit.export + def enable_val(self): + """Disables static observer accumulating data from input and doesn't + update the quantization parameters. + + Forward path returns fake quantized X. + """ + self.toggle_qparam_learning(enabled=False) \ + .toggle_fake_quant(enabled=True) \ + .toggle_observer_update(enabled=False) + + @torch.jit.export + def enable_static_observation(self): + """Enables static observer accumulating data from input but doesn't + update the quantization parameters. + + Forward path returns the original X. + """ + self.toggle_qparam_learning(enabled=False) \ + .toggle_fake_quant(enabled=False) \ + .toggle_observer_update(enabled=True) + + @torch.jit.export + def toggle_observer_update(self, enabled=True): + """Toggles whether static observer accumulates data from input.""" + self.static_enabled[0] = int(enabled) + return self + + @torch.jit.export + def enable_observer(self, enabled=True): + """Enables static observer accumulating data from input.""" + self.toggle_observer_update(enabled) + + @torch.jit.export + def toggle_qparam_learning(self, enabled=True): + """Toggles whether the quantization parameters are learnable.""" + self.learning_enabled[0] = int(enabled) + self.scale.requires_grad = enabled + if self.zero_point_trainable: + self.zero_point.requires_grad = enabled + return self + + @torch.jit.export + def toggle_fake_quant(self, enabled=True): + """Toggles whether the fake quantization is enabled.""" + self.fake_quant_enabled[0] = int(enabled) + return self + + @torch.jit.export + def observe_quant_params(self): + """Shows the quantization parameters.""" + print('LearnableFakeQuantize Scale: {}'.format(self.scale.detach())) + print('LearnableFakeQuantize Zero Point: {}'.format( + self.zero_point.detach())) + + @torch.jit.export + def calculate_qparams(self): + """Calculate the quantization parameters.""" + self.scale.data.clamp_(min=self.eps.item()) + scale = self.scale.detach() + zero_point = self.zero_point.detach().round().clamp( + self.quant_min, self.quant_max).long() + return scale, zero_point + + def forward(self, X): + """Forward computation. + + Forward path returns fake quantized X. + """ + if self.static_enabled[0] == 1: + self.activation_post_process(X.detach()) + _scale, _zero_point = \ + self.activation_post_process.calculate_qparams() + _scale = _scale.to(self.scale.device) + _zero_point = _zero_point.to(self.zero_point.device) + + if self.qscheme in (torch.per_channel_symmetric, + torch.per_channel_affine): + self.scale.data = torch.ones_like(_scale) + self.zero_point.data = torch.zeros_like(_zero_point.float()) + + self.scale.data.copy_(_scale) + self.zero_point.data.copy_(_zero_point) + else: + self.scale.data.clamp_(min=self.eps.item()) + + if self.fake_quant_enabled[0] == 1: + + if self.use_grad_scaling: + grad_factor = 1.0 / (X.numel() * self.quant_max)**0.5 + else: + grad_factor = 1.0 + if self.qscheme in (torch.per_channel_symmetric, + torch.per_channel_affine): + X = torch._fake_quantize_learnable_per_channel_affine( + X, self.scale, self.zero_point, self.ch_axis, + self.quant_min, self.quant_max, grad_factor) + else: + if not (self.quant_min <= self.zero_point <= self.quant_max): + print(self.quant_min, self.zero_point, self.quant_max) + X = torch._fake_quantize_learnable_per_tensor_affine( + X, self.scale, self.zero_point, self.quant_min, + self.quant_max, grad_factor) + + return X + + def _load_from_state_dict(self, state_dict, prefix, local_metadata, strict, + missing_keys, unexpected_keys, error_msgs): + """Removing this function throws an error that the the size of the + loaded tensor does not match the original size i.e., These buffers + start out with numel 0 and become numel 1 once they have their first + forward pass. + + Modified from https://github.com/pytorch/pytorch/blob/master/torch/ao/quantization/fake_quantize.py # noqa:E501 + """ + local_state = ['scale', 'zero_point'] + for name in local_state: + key = prefix + name + if key in state_dict: + val = state_dict[key] + # Custom handling to allow loading scale and zero_point + # of size N into uninitialized buffers of size 0. The + # buffers are resized here, and the values are copied in + # the default state_dict loading code of the parent. + if name == 'scale': + self.scale.data = self.scale.data.resize_(val.shape) + else: + assert name == 'zero_point' + self.zero_point.data = self.zero_point.data.resize_( + val.shape) + # For torchscript module we need to update the attributes here + # since we do not call the `_load_from_state_dict` function + # defined module.py + if torch.jit.is_scripting(): + if name == 'scale': + self.scale.copy_(val) + else: + assert name == 'zero_point' + self.zero_point.copy_(val) + elif strict: + missing_keys.append(key) + super(LearnableFakeQuantize, + self)._load_from_state_dict(state_dict, prefix, local_metadata, + strict, missing_keys, + unexpected_keys, error_msgs) + + @torch.jit.export + def extra_repr(self): + """The printable representational string.""" + repr_str = f'static_enabled={self.static_enabled}, ' + repr_str += f'fake_quant_enabled={self.fake_quant_enabled}, ' + repr_str += f'quant_min={self.activation_post_process.quant_min}, ' + repr_str += f'quant_max={self.activation_post_process.quant_max}, ' + repr_str += f'dtype={self.dtype}, ' + repr_str += f'qscheme={self.qscheme}, ' + repr_str += f'scale={self.scale}, ' + repr_str += f'zero_point={self.zero_point}, ' + repr_str += f'zero_point_trainable={self.zero_point_trainable}' + return repr_str diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/torch_fake_quants.py b/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/torch_fake_quants.py new file mode 100755 index 000000000..06e325b32 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/torch_fake_quants.py @@ -0,0 +1,38 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import inspect +from typing import List + +from mmrazor.registry import MODELS + +try: + import torch.ao.quantization.fake_quantize as torch_fake_quant_src +except ImportError: + from mmrazor.utils import get_package_placeholder + torch_fake_quant_src = get_package_placeholder('torch>=1.13') + + +# TORCH_fake_quants = register_torch_fake_quants() +# TORCH_fake_quants including: +# FakeQuantize +# FakeQuantizeBase +# FixedQParamsFakeQuantize +# FusedMovingAvgObsFakeQuantize +def register_torch_fake_quants() -> List[str]: + """Register fake_quants in ``torch.ao.quantization.fake_quantize`` to the + ``MODELS`` registry. + + Returns: + List[str]: A list of registered fake_quants' name. + """ + torch_fake_quants = [] + for module_name in dir(torch_fake_quant_src): + if module_name.startswith('__') or module_name.startswith('_') or \ + module_name.startswith('default'): + continue + _fake_quant = getattr(torch_fake_quant_src, module_name) + if inspect.isclass(_fake_quant) and issubclass( + _fake_quant, torch_fake_quant_src.FakeQuantizeBase): + if MODELS.get(module_name) is None: + MODELS.register_module(module=_fake_quant) + torch_fake_quants.append(module_name) + return torch_fake_quants diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/__init__.py new file mode 100755 index 000000000..65e2108fd --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/__init__.py @@ -0,0 +1,28 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .ab_loss import ABLoss +from .at_loss import ATLoss +from .crd_loss import CRDLoss +from .cross_entropy_loss import CrossEntropyLoss +from .cwd import ChannelWiseDivergence +from .dafl_loss import ActivationLoss, InformationEntropyLoss, OnehotLikeLoss +from .decoupled_kd import DKDLoss +from .dist_loss import DISTLoss +from .factor_transfer_loss import FTLoss +from .fbkd_loss import FBKDLoss +from .kd_soft_ce_loss import KDSoftCELoss +from .kl_divergence import KLDivergence +from .l1_loss import L1Loss +from .l2_loss import L2Loss +from .mgd_loss import MGDLoss +from .ofd_loss import OFDLoss +from .pkd_loss import PKDLoss +from .relational_kd import AngleWiseRKD, DistanceWiseRKD +from .weighted_soft_label_distillation import WSLD + +__all__ = [ + 'ChannelWiseDivergence', 'KLDivergence', 'AngleWiseRKD', 'DistanceWiseRKD', + 'WSLD', 'L2Loss', 'ABLoss', 'DKDLoss', 'KDSoftCELoss', 'ActivationLoss', + 'OnehotLikeLoss', 'InformationEntropyLoss', 'FTLoss', 'ATLoss', 'OFDLoss', + 'L1Loss', 'FBKDLoss', 'CRDLoss', 'CrossEntropyLoss', 'PKDLoss', 'MGDLoss', + 'DISTLoss' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/ab_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/ab_loss.py new file mode 100755 index 000000000..b4c628154 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/ab_loss.py @@ -0,0 +1,66 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class ABLoss(nn.Module): + """Activation Boundaries Loss. + + Paper: Knowledge Transfer via Distillation of Activation Boundaries + Formed by Hidden Neurons, AAAI2019. https://arxiv.org/pdf/1811.03233.pdf + + Modified from: https://github.com/facebookresearch/AlphaNet + + Args: + loss_weight (float): Weight of loss. Defaults to 1.0. + margin (float): Relaxation for training stability. Defaults to 1.0. + """ + + def __init__( + self, + loss_weight: float = 1.0, + margin: float = 1.0, + ) -> None: + super().__init__() + self.loss_weight = loss_weight + self.margin = margin + + def forward( + self, + s_feature: torch.Tensor, + t_feature: torch.Tensor, + ) -> torch.Tensor: + """ABLoss forward function. + + Args: + s_features (torch.Tensor): Student featuremap. + t_features (torch.Tensor): Teacher featuremap. + """ + batch_size = s_feature.shape[0] + loss = self.criterion_alternative_l2(s_feature, t_feature) + loss = loss / batch_size / 1000 * 3 + return self.loss_weight * loss + + def criterion_alternative_l2( + self, + source: torch.Tensor, + target: torch.Tensor, + ) -> torch.Tensor: + """Piecewise differentiable loss approximating the activation + boundaries loss. + + Guide the student learns a separating boundary between activation + region and deactivation region formed by each neuron in the teacher. + + Args: + source (torch.Tensor): Student featuremap. + target (torch.Tensor): Teacher featuremap. + """ + loss = ((source + self.margin)**2 * ((source > -self.margin) & + (target <= 0)).float() + + (source - self.margin)**2 * ((source <= self.margin) & + (target > 0)).float()) + return torch.abs(loss).sum() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/at_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/at_loss.py new file mode 100755 index 000000000..025ac6748 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/at_loss.py @@ -0,0 +1,41 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class ATLoss(nn.Module): + """"Paying More Attention to Attention: Improving the Performance of + Convolutional Neural Networks via Attention Transfer" Conference paper at + ICLR2017 https://openreview.net/forum?id=Sks9_ajex. + + https://github.com/szagoruyko/attention-transfer/blob/master/utils.py + + Args: + loss_weight (float): Weight of loss. Defaults to 1.0. + """ + + def __init__( + self, + loss_weight: float = 1.0, + ) -> None: + super().__init__() + self.loss_weight = loss_weight + + def forward(self, s_feature: torch.Tensor, + t_feature: torch.Tensor) -> torch.Tensor: + """"Forward function for ATLoss.""" + loss = (self.calc_attention_matrix(s_feature) - + self.calc_attention_matrix(t_feature)).pow(2).mean() + return self.loss_weight * loss + + def calc_attention_matrix(self, x: torch.Tensor) -> torch.Tensor: + """"Calculate the attention matrix. + + Args: + x (torch.Tensor): Input features. + """ + return F.normalize(x.pow(2).mean(1).view(x.size(0), -1)) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/crd_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/crd_loss.py new file mode 100755 index 000000000..4ca81aaf5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/crd_loss.py @@ -0,0 +1,271 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import math +from typing import Union + +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class CRDLoss(nn.Module): + """Variate CRD Loss, ICLR 2020. + + https://arxiv.org/abs/1910.10699 + Args: + loss_weight (float, optional): loss weight. Defaults to 1.0. + temperature (float, optional): temperature. Defaults to 0.07. + neg_num (int, optional): number of negative samples. Defaults to 16384. + sample_n (int, optional): number of total samples. Defaults to 50000. + dim_out (int, optional): output channels. Defaults to 128. + momentum (float, optional): momentum. Defaults to 0.5. + eps (double, optional): eps. Defaults to 1e-7. + """ + + def __init__(self, + loss_weight: float = 1.0, + temperature=0.07, + neg_num=16384, + sample_n=50000, + dim_out=128, + momentum=0.5, + eps=1e-7): + super().__init__() + self.loss_weight = loss_weight + self.eps = eps + + self.contrast = ContrastMemory(dim_out, sample_n, neg_num, temperature, + momentum) + self.criterion_s_t = ContrastLoss(sample_n, eps=self.eps) + + def forward(self, s_feats, t_feats, data_samples): + input_data = data_samples[0] + assert 'sample_idx' in input_data, \ + 'you should pass a dict with key `sample_idx` in mimic function.' + assert isinstance( + input_data.sample_idx, torch.Tensor + ), f'`sample_idx` must be a tensor, but get {type(input_data.sample_idx)}' # noqa: E501 + + sample_idxs = torch.stack( + [sample.sample_idx for sample in data_samples]) + if 'contrast_sample_idxs' in input_data: + assert isinstance( + input_data.contrast_sample_idxs, torch.Tensor + ), f'`contrast_sample_idxs` must be a tensor, but get {type(input_data.contrast_sample_idxs)}' # noqa: E501 + contrast_sample_idxs = torch.stack( + [sample.contrast_sample_idxs for sample in data_samples]) + else: + contrast_sample_idxs = None + out_s, out_t = self.contrast(s_feats, t_feats, sample_idxs, + contrast_sample_idxs) + s_loss = self.criterion_s_t(out_s) + t_loss = self.criterion_s_t(out_t) + loss = s_loss + t_loss + return loss + + +class ContrastLoss(nn.Module): + """contrastive loss, corresponding to Eq (18) + + Args: + n_data (int): number of data + eps (float, optional): eps. Defaults to 1e-7. + """ + + def __init__(self, n_data: int, eps: float = 1e-7): + super(ContrastLoss, self).__init__() + self.n_data = n_data + self.eps = eps + + def forward(self, x): + bsz = x.shape[0] + m = x.size(1) - 1 + + # noise distribution + Pn = 1 / float(self.n_data) + + # loss for positive pair + P_pos = x.select(1, 0) + log_D1 = torch.div(P_pos, P_pos.add(m * Pn + self.eps)).log_() + + # loss for neg_sample negative pair + P_neg = x.narrow(1, 1, m) + log_D0 = torch.div(P_neg.clone().fill_(m * Pn), + P_neg.add(m * Pn + self.eps)).log_() + + loss = -(log_D1.sum(0) + log_D0.view(-1, 1).sum(0)) / bsz + + return loss + + +class ContrastMemory(nn.Module): + """memory buffer that supplies large amount of negative samples. + + https://github.com/HobbitLong/RepDistiller/blob/master/crd/memory.py + + Args: + dim_out (int, optional): output channels. Defaults to 128. + n_sample (int, optional): number of total samples. + Defaults to 50000. + neg_sample (int, optional): number of negative samples. + Defaults to 16384. + T (float, optional): temperature. Defaults to 0.07. + momentum (float, optional): momentum. Defaults to 0.5. + """ + + def __init__(self, + dim_out: int, + n_sample: int, + neg_sample: int, + T: float = 0.07, + momentum: float = 0.5): + super(ContrastMemory, self).__init__() + self.n_sample = n_sample + self.unigrams = torch.ones(self.n_sample) + self.multinomial = AliasMethod(self.unigrams) + # self.multinomial.cuda() + self.neg_sample = neg_sample + + self.register_buffer('params', + torch.tensor([neg_sample, T, -1, -1, momentum])) + stdv = 1. / math.sqrt(dim_out / 3) + self.register_buffer( + 'memory_v1', + torch.rand(n_sample, dim_out).mul_(2 * stdv).add_(-stdv)) + self.register_buffer( + 'memory_v2', + torch.rand(n_sample, dim_out).mul_(2 * stdv).add_(-stdv)) + + def forward(self, + feat_s: torch.Tensor, + feat_t: torch.Tensor, + idx: torch.Tensor, + sample_idx: Union[None, torch.Tensor] = None) -> torch.Tensor: + neg_sample = int(self.params[0].item()) + T = self.params[1].item() + Z_s = self.params[2].item() + Z_t = self.params[3].item() + + momentum = self.params[4].item() + bsz = feat_s.size(0) + n_sample = self.memory_v1.size(0) + dim_out = self.memory_v1.size(1) + + # original score computation + if sample_idx is None: + sample_idx = self.multinomial.draw(bsz * (self.neg_sample + 1))\ + .view(bsz, -1) + sample_idx.select(1, 0).copy_(idx.data) + # sample + weight_s = torch.index_select(self.memory_v1, 0, + sample_idx.view(-1)).detach() + weight_s = weight_s.view(bsz, neg_sample + 1, dim_out) + out_t = torch.bmm(weight_s, feat_t.view(bsz, dim_out, 1)) + out_t = torch.exp(torch.div(out_t, T)) + # sample + weight_t = torch.index_select(self.memory_v2, 0, + sample_idx.view(-1)).detach() + weight_t = weight_t.view(bsz, neg_sample + 1, dim_out) + out_s = torch.bmm(weight_t, feat_s.view(bsz, dim_out, 1)) + out_s = torch.exp(torch.div(out_s, T)) + + # set Z if haven't been set yet + if Z_s < 0: + self.params[2] = out_s.mean() * n_sample + Z_s = self.params[2].clone().detach().item() + print('normalization constant Z_s is set to {:.1f}'.format(Z_s)) + if Z_t < 0: + self.params[3] = out_t.mean() * n_sample + Z_t = self.params[3].clone().detach().item() + print('normalization constant Z_t is set to {:.1f}'.format(Z_t)) + + # compute out_s, out_t + out_s = torch.div(out_s, Z_s).contiguous() + out_t = torch.div(out_t, Z_t).contiguous() + + # update memory + with torch.no_grad(): + l_pos = torch.index_select(self.memory_v1, 0, idx.view(-1)) + l_pos.mul_(momentum) + l_pos.add_(torch.mul(feat_s, 1 - momentum)) + l_norm = l_pos.pow(2).sum(1, keepdim=True).pow(0.5) + updated_v1 = l_pos.div(l_norm) + self.memory_v1.index_copy_(0, idx, updated_v1) + + ab_pos = torch.index_select(self.memory_v2, 0, idx.view(-1)) + ab_pos.mul_(momentum) + ab_pos.add_(torch.mul(feat_t, 1 - momentum)) + ab_norm = ab_pos.pow(2).sum(1, keepdim=True).pow(0.5) + updated_v2 = ab_pos.div(ab_norm) + self.memory_v2.index_copy_(0, idx, updated_v2) + + return out_s, out_t + + +class AliasMethod(object): + """ + From: https://hips.seas.harvard.edu/blog/2013/03/03/ + the-alias-method-efficient-sampling-with-many-discrete-outcomes/ + + Args: + probs (torch.Tensor): probility vector. + """ + + def __init__(self, probs: torch.Tensor) -> None: + + if probs.sum() > 1: + probs.div_(probs.sum()) + neg_sample = len(probs) + self.prob = torch.zeros(neg_sample) + self.alias = torch.LongTensor([0] * neg_sample) + + # Sort the data into the outcomes with probabilities + # that are larger and smaller than 1/neg_sample. + smaller = [] + larger = [] + for kk, prob in enumerate(probs): + self.prob[kk] = neg_sample * prob + if self.prob[kk] < 1.0: + smaller.append(kk) + else: + larger.append(kk) + + # Loop though and create little binary mixtures that + # appropriately allocate the larger outcomes over the + # overall uniform mixture. + while len(smaller) > 0 and len(larger) > 0: + small = smaller.pop() + large = larger.pop() + + self.alias[small] = large + self.prob[large] = (self.prob[large] - 1.0) + self.prob[small] + + if self.prob[large] < 1.0: + smaller.append(large) + else: + larger.append(large) + + for last_one in smaller + larger: + self.prob[last_one] = 1 + + def cuda(self): + """To cuda device.""" + self.prob = self.prob.cuda() + self.alias = self.alias.cuda() + + def draw(self, N: int) -> torch.Tensor: + """Draw N samples from multinomial.""" + neg_sample = self.alias.size(0) + + kk = torch.zeros( + N, dtype=torch.long, + device=self.prob.device).random_(0, neg_sample) + prob = self.prob.index_select(0, kk) + alias = self.alias.index_select(0, kk) + # b is whether a random number is greater than q + b = torch.bernoulli(prob) + oq = kk.mul(b.long()) + oj = alias.mul((1 - b).long()) + + return oq + oj diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/cross_entropy_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/cross_entropy_loss.py new file mode 100755 index 000000000..685748092 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/cross_entropy_loss.py @@ -0,0 +1,23 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class CrossEntropyLoss(nn.Module): + """Cross entropy loss. + + Args: + loss_weight (float): Weight of the loss. Defaults to 1.0. + """ + + def __init__(self, loss_weight=1.0): + super(CrossEntropyLoss, self).__init__() + self.loss_weight = loss_weight + + def forward(self, preds_S, preds_T): + preds_T = preds_T.detach() + loss = F.cross_entropy(preds_S, preds_T.argmax(dim=1)) + return loss * self.loss_weight diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/cwd.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/cwd.py new file mode 100755 index 000000000..3c8ca1195 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/cwd.py @@ -0,0 +1,51 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class ChannelWiseDivergence(nn.Module): + """PyTorch version of `Channel-wise Distillation for Semantic Segmentation. + + `_. + + Args: + tau (float): Temperature coefficient. Defaults to 1.0. + loss_weight (float): Weight of loss. Defaults to 1.0. + """ + + def __init__(self, tau=1.0, loss_weight=1.0): + super(ChannelWiseDivergence, self).__init__() + self.tau = tau + self.loss_weight = loss_weight + + def forward(self, preds_S, preds_T): + """Forward computation. + + Args: + preds_S (torch.Tensor): The student model prediction with + shape (N, C, H, W). + preds_T (torch.Tensor): The teacher model prediction with + shape (N, C, H, W). + + Return: + torch.Tensor: The calculated loss value. + """ + assert preds_S.shape[-2:] == preds_T.shape[-2:] + N, C, H, W = preds_S.shape + + softmax_pred_T = F.softmax(preds_T.view(-1, W * H) / self.tau, dim=1) + + logsoftmax = torch.nn.LogSoftmax(dim=1) + loss = torch.sum(softmax_pred_T * + logsoftmax(preds_T.view(-1, W * H) / self.tau) - + softmax_pred_T * + logsoftmax(preds_S.view(-1, W * H) / self.tau)) * ( + self.tau**2) + + loss = self.loss_weight * loss / (C * N) + + return loss diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/dafl_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/dafl_loss.py new file mode 100755 index 000000000..d6205feae --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/dafl_loss.py @@ -0,0 +1,124 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +import torch.nn.functional as F +from mmengine.dist import get_dist_info + +from mmrazor.registry import MODELS +from ..architectures.ops import GatherTensors + + +class DAFLLoss(nn.Module): + """Base class for DAFL losses. + + paper link: https://arxiv.org/pdf/1904.01186.pdf + + Args: + loss_weight (float): Weight of the loss. Defaults to 1.0. + """ + + def __init__(self, loss_weight=1.0) -> None: + super().__init__() + self.loss_weight = loss_weight + + def forward(self, preds_T: torch.Tensor) -> torch.Tensor: + """Forward function for the DAFLLoss. + + Args: + preds_T (torch.Tensor): The predictions of teacher. + """ + return self.loss_weight * self.forward_train(preds_T) + + def forward_train(self, preds_T: torch.Tensor) -> torch.Tensor: + """Forward function during training. + + Args: + preds_T (torch.Tensor): The predictions of teacher. + """ + raise NotImplementedError + + +@MODELS.register_module() +class OnehotLikeLoss(DAFLLoss): + """The loss function for measuring the one-hot-likeness of the target + logits.""" + + def __init__(self, **kwargs) -> None: + super().__init__(**kwargs) + + def forward_train(self, preds_T: torch.Tensor) -> torch.Tensor: + """Forward function in training for the OnehotLikeLoss. + + Args: + preds_T (torch.Tensor): The predictions of teacher. + """ + fake_label = preds_T.data.max(1)[1] + return F.cross_entropy(preds_T, fake_label) + + +@MODELS.register_module() +class InformationEntropyLoss(DAFLLoss): + """The loss function for measuring the class balance of the target logits. + + Args: + gather (bool, optional): The switch controlling whether + collecting tensors from multiple gpus. Defaults to True. + """ + + def __init__(self, gather=True, **kwargs) -> None: + super().__init__(**kwargs) + self.gather = gather + _, self.world_size = get_dist_info() + + def forward_train(self, preds_T: torch.Tensor) -> torch.Tensor: + """Forward function in training for the InformationEntropyLoss. + + Args: + preds_T (torch.Tensor): The predictions of teacher. + """ + # Gather predictions from all GPUS to calibrate the loss function. + if self.gather and self.world_size > 1: + preds_T = torch.cat(GatherTensors.apply(preds_T), dim=0) + class_prob = F.softmax(preds_T, dim=1).mean(dim=0) + info_entropy = class_prob * torch.log10(class_prob) + return info_entropy.sum() + + +@MODELS.register_module() +class ActivationLoss(nn.Module): + """The loss function for measuring the activation of the target featuremap. + It is negative of the norm of the target featuremap. + + Args: + loss_weight (float): Weight of the loss. Defaults to 1.0. + norm_type (str, optional):The type of the norm. Defaults to 'abs'. + """ + + def __init__(self, loss_weight=1.0, norm_type='abs') -> None: + super().__init__() + self.loss_weight = loss_weight + assert norm_type in ['norm', 'abs'], \ + '"norm_type" must be "norm" or "abs"' + self.norm_type = norm_type + + if self.norm_type == 'norm': + self.norm_fn = lambda x: -x.norm() + elif self.norm_type == 'abs': + self.norm_fn = lambda x: -x.abs().mean() + + def forward(self, feat_T: torch.Tensor) -> torch.Tensor: + """Forward function for the ActivationLoss. + + Args: + feat_T (torch.Tensor): The featuremap of teacher. + """ + return self.loss_weight * self.forward_train(feat_T) + + def forward_train(self, feat_T: torch.Tensor) -> torch.Tensor: + """Forward function in training for the ActivationLoss. + + Args: + feat_T (torch.Tensor): The featuremap of teacher. + """ + feat_T = feat_T.view(feat_T.size(0), -1) + return self.norm_fn(feat_T) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/decoupled_kd.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/decoupled_kd.py new file mode 100755 index 000000000..2aeff6a42 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/decoupled_kd.py @@ -0,0 +1,157 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class DKDLoss(nn.Module): + """Decoupled Knowledge Distillation, CVPR2022. + + link: https://arxiv.org/abs/2203.08679 + reformulate the classical KD loss into two parts: + 1. target class knowledge distillation (TCKD) + 2. non-target class knowledge distillation (NCKD). + Args: + tau (float): Temperature coefficient. Defaults to 1.0. + alpha (float): Weight of TCKD loss. Defaults to 1.0. + beta (float): Weight of NCKD loss. Defaults to 1.0. + reduction (str): Specifies the reduction to apply to the loss: + ``'none'`` | ``'batchmean'`` | ``'sum'`` | ``'mean'``. + ``'none'``: no reduction will be applied, + ``'batchmean'``: the sum of the output will be divided by + the batchsize, + ``'sum'``: the output will be summed, + ``'mean'``: the output will be divided by the number of + elements in the output. + Default: ``'batchmean'`` + loss_weight (float): Weight of loss. Defaults to 1.0. + """ + + def __init__( + self, + tau: float = 1.0, + alpha: float = 1.0, + beta: float = 1.0, + reduction: str = 'batchmean', + loss_weight: float = 1.0, + ) -> None: + super(DKDLoss, self).__init__() + self.tau = tau + accept_reduction = {'none', 'batchmean', 'sum', 'mean'} + assert reduction in accept_reduction, \ + f'KLDivergence supports reduction {accept_reduction}, ' \ + f'but gets {reduction}.' + self.reduction = reduction + self.alpha = alpha + self.beta = beta + self.loss_weight = loss_weight + + def forward( + self, + preds_S: torch.Tensor, + preds_T: torch.Tensor, + gt_labels: torch.Tensor, + ) -> torch.Tensor: + """DKDLoss forward function. + + Args: + preds_S (torch.Tensor): The student model prediction, shape (N, C). + preds_T (torch.Tensor): The teacher model prediction, shape (N, C). + gt_labels (torch.Tensor): The gt label tensor, shape (N, C). + + Return: + torch.Tensor: The calculated loss value. + """ + gt_mask = self._get_gt_mask(preds_S, gt_labels) + tckd_loss = self._get_tckd_loss(preds_S, preds_T, gt_labels, gt_mask) + nckd_loss = self._get_nckd_loss(preds_S, preds_T, gt_mask) + loss = self.alpha * tckd_loss + self.beta * nckd_loss + return self.loss_weight * loss + + def _get_nckd_loss( + self, + preds_S: torch.Tensor, + preds_T: torch.Tensor, + gt_mask: torch.Tensor, + ) -> torch.Tensor: + """Calculate non-target class knowledge distillation.""" + # implementation to mask out gt_mask, faster than index + s_nckd = F.log_softmax(preds_S / self.tau - 1000.0 * gt_mask, dim=1) + t_nckd = F.softmax(preds_T / self.tau - 1000.0 * gt_mask, dim=1) + return self._kl_loss(s_nckd, t_nckd) + + def _get_tckd_loss( + self, + preds_S: torch.Tensor, + preds_T: torch.Tensor, + gt_labels: torch.Tensor, + gt_mask: torch.Tensor, + ) -> torch.Tensor: + """Calculate target class knowledge distillation.""" + non_gt_mask = self._get_non_gt_mask(preds_S, gt_labels) + s_tckd = F.softmax(preds_S / self.tau, dim=1) + t_tckd = F.softmax(preds_T / self.tau, dim=1) + mask_student = torch.log(self._cat_mask(s_tckd, gt_mask, non_gt_mask)) + mask_teacher = self._cat_mask(t_tckd, gt_mask, non_gt_mask) + return self._kl_loss(mask_student, mask_teacher) + + def _kl_loss( + self, + preds_S: torch.Tensor, + preds_T: torch.Tensor, + ) -> torch.Tensor: + """Calculate the KL Divergence.""" + kl_loss = F.kl_div( + preds_S, preds_T, size_average=False, + reduction=self.reduction) * self.tau**2 + return kl_loss + + def _cat_mask( + self, + tckd: torch.Tensor, + gt_mask: torch.Tensor, + non_gt_mask: torch.Tensor, + ) -> torch.Tensor: + """Calculate preds of target (pt) & preds of non-target (pnt).""" + t1 = (tckd * gt_mask).sum(dim=1, keepdims=True) + t2 = (tckd * non_gt_mask).sum(dim=1, keepdims=True) + return torch.cat([t1, t2], dim=1) + + def _get_gt_mask( + self, + logits: torch.Tensor, + target: torch.Tensor, + ) -> torch.Tensor: + """Calculate groundtruth mask on logits with target class tensor. + + Args: + logits (torch.Tensor): The prediction logits with shape (N, C). + target (torch.Tensor): The gt_label target with shape (N, C). + + Return: + torch.Tensor: The masked logits. + """ + target = target.reshape(-1) + return torch.zeros_like(logits).scatter_(1, target.unsqueeze(1), + 1).bool() + + def _get_non_gt_mask( + self, + logits: torch.Tensor, + target: torch.Tensor, + ) -> torch.Tensor: + """Calculate non-groundtruth mask on logits with target class tensor. + + Args: + logits (torch.Tensor): The prediction logits with shape (N, C). + target (torch.Tensor): The gt_label target with shape (N, C). + + Return: + torch.Tensor: The masked logits. + """ + target = target.reshape(-1) + return torch.ones_like(logits).scatter_(1, target.unsqueeze(1), + 0).bool() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/dist_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/dist_loss.py new file mode 100755 index 000000000..4d7ac63af --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/dist_loss.py @@ -0,0 +1,52 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS + + +def cosine_similarity(a, b, eps=1e-8): + return (a * b).sum(1) / (a.norm(dim=1) * b.norm(dim=1) + eps) + + +def pearson_correlation(a, b, eps=1e-8): + return cosine_similarity(a - a.mean(1, keepdim=True), + b - b.mean(1, keepdim=True), eps) + + +def inter_class_relation(y_s, y_t): + return 1 - pearson_correlation(y_s, y_t).mean() + + +def intra_class_relation(y_s, y_t): + return inter_class_relation(y_s.transpose(0, 1), y_t.transpose(0, 1)) + + +@MODELS.register_module() +class DISTLoss(nn.Module): + + def __init__( + self, + inter_loss_weight=1.0, + intra_loss_weight=1.0, + tau=1.0, + loss_weight: float = 1.0, + teacher_detach: bool = True, + ): + super(DISTLoss, self).__init__() + self.inter_loss_weight = inter_loss_weight + self.intra_loss_weight = intra_loss_weight + self.tau = tau + + self.loss_weight = loss_weight + self.teacher_detach = teacher_detach + + def forward(self, logits_S, logits_T: torch.Tensor): + if self.teacher_detach: + logits_T = logits_T.detach() + y_s = (logits_S / self.tau).softmax(dim=1) + y_t = (logits_T / self.tau).softmax(dim=1) + inter_loss = self.tau**2 * inter_class_relation(y_s, y_t) + intra_loss = self.tau**2 * intra_class_relation(y_s, y_t) + kd_loss = self.inter_loss_weight * inter_loss + self.intra_loss_weight * intra_loss # noqa + return kd_loss * self.loss_weight diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/factor_transfer_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/factor_transfer_loss.py new file mode 100755 index 000000000..bf49920dd --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/factor_transfer_loss.py @@ -0,0 +1,38 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class FTLoss(nn.Module): + """Paraphrasing Complex Network: Network Compression via Factor Transfer, + NeurIPS 2018. + + https://arxiv.org/pdf/1802.04977.pdf + + Args: + loss_weight (float, optional): loss weight. Defaults to 1.0. + """ + + def __init__(self, loss_weight: float = 1.0) -> None: + super(FTLoss, self).__init__() + self.criterion = nn.L1Loss() + self.loss_weight = loss_weight + + def forward_train(self, s_feature: torch.Tensor, + t_feature: torch.Tensor) -> torch.Tensor: + """loss computation func.""" + loss = self.criterion(self.factor(s_feature), self.factor(t_feature)) + return loss + + def forward(self, s_feature: torch.Tensor, + t_feature: torch.Tensor) -> torch.Tensor: + """the forward func.""" + return self.loss_weight * self.forward_train(s_feature, t_feature) + + def factor(self, x: torch.Tensor) -> torch.Tensor: + """compute factor.""" + return F.normalize(x.view(x.size(0), -1)) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/fbkd_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/fbkd_loss.py new file mode 100755 index 000000000..66115c093 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/fbkd_loss.py @@ -0,0 +1,120 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Optional, Tuple + +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS + + +def mask_l2_loss( + tensor_a: torch.Tensor, + tensor_b: torch.Tensor, + saptial_attention_mask: Optional[torch.Tensor] = None, + channel_attention_mask: Optional[torch.Tensor] = None) -> torch.Tensor: + """L2 loss with two attention mask, which used to weight the feature + distillation loss in FBKD. + + Args: + tensor_a (torch.Tensor): Student featuremap. + tensor_b (torch.Tensor): Teacher featuremap. + saptial_attention_mask (torch.Tensor, optional): Mask of spatial-wise + attention. Defaults to None. + channel_attention_mask (torch.Tensor, optional): Mask of channel-wise + attention. Defaults to None. + + Returns: + diff (torch.Tensor): l2 loss with two attention mask. + """ + diff = (tensor_a - tensor_b)**2 + if saptial_attention_mask is not None: + diff = diff * saptial_attention_mask + if channel_attention_mask is not None: + diff = diff * channel_attention_mask + diff = torch.sum(diff)**0.5 + return diff + + +@MODELS.register_module() +class FBKDLoss(nn.Module): + """Loss For FBKD, which includs feat_loss, channel_loss, spatial_loss and + nonlocal_loss. + + Source code: + https://github.com/ArchipLab-LinfengZhang/Object-Detection-Knowledge- + Distillation-ICLR2021 + + Args: + mask_l2_weight (float): The weight of the mask l2 loss. + Defaults to 7e-5, which is the default value in source code. + channel_weight (float): The weight of the channel loss. + Defaults to 4e-3, which is the default value in source code. + spatial_weight (float): The weight of the spatial loss. + Defaults to 4e-3, which is the default value in source code. + nonloacl_weight (float): The weight of the nonlocal loss. + Defaults to 7e-5, which is the default value in source code. + loss_weight (float): Weight of loss. Defaults to 1.0. + """ + + def __init__(self, + mask_l2_weight: float = 7e-5, + channel_weight: float = 4e-3, + spatial_weight: float = 4e-3, + nonloacl_weight: float = 7e-5, + loss_weight: float = 1.0) -> None: + """Inits FBKDLoss.""" + super().__init__() + + self.mask_l2_weight = mask_l2_weight + self.channel_weight = channel_weight + self.spatial_weight = spatial_weight + self.nonloacl_weight = nonloacl_weight + self.loss_weight = loss_weight + + def forward(self, s_input: Tuple[torch.Tensor, ...], + t_input: Tuple[torch.Tensor, ...]) -> torch.Tensor: + """Forward function of FBKDLoss, including feat_loss, channel_loss, + spatial_loss and nonlocal_loss. + + Args: + s_input (Tuple[torch.Tensor, ...]): Student input which is the + output of ``'FBKDStudentConnector'``. + t_input (Tuple[torch.Tensor, ...]): Teacher input which is the + output of ``'FBKDTeacherConnector'``. + """ + losses = 0.0 + + (s_spatial_mask, s_channel_mask, s_channel_pool_adapt, + s_spatial_pool_adapt, s_relation_adapt, s_feat_adapt) = s_input + + (t_spatial_mask, t_channel_mask, t_spatial_pool, t_relation, + t_feat) = t_input + + # Spatial-wise mask. + spatial_sum_mask = (t_spatial_mask + s_spatial_mask) / 2 + spatial_sum_mask = spatial_sum_mask.detach() + + # Channel-wise mask, but not used in the FBKD source code. + channel_sum_mask = (t_channel_mask + s_channel_mask) / 2 + channel_sum_mask = channel_sum_mask.detach() + + # feat_loss with mask + losses += mask_l2_loss( + t_feat, + s_feat_adapt, + saptial_attention_mask=spatial_sum_mask, + channel_attention_mask=None) * self.mask_l2_weight + + # channel_loss + losses += torch.dist(torch.mean(t_feat, [2, 3]), + s_channel_pool_adapt) * self.channel_weight + + # spatial_loss + losses += torch.dist(t_spatial_pool, + s_spatial_pool_adapt) * self.spatial_weight + + # nonlocal_loss + losses += torch.dist( + t_relation, s_relation_adapt, p=2) * self.nonloacl_weight + + return self.loss_weight * losses diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/kd_soft_ce_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/kd_soft_ce_loss.py new file mode 100755 index 000000000..8ef8c23a4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/kd_soft_ce_loss.py @@ -0,0 +1,94 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS + +try: + from mmcls.models.losses.cross_entropy_loss import soft_cross_entropy +except ImportError: + from mmrazor.utils import get_placeholder + soft_cross_entropy = get_placeholder('mmcls') + + +@MODELS.register_module() +class KDSoftCELoss(nn.Module): + """Distilling the Knowledge in a Neural Network, NIPS2014. Based on Soft + Cross Entropy criterion. + + https://arxiv.org/pdf/1503.02531.pdf + + + Args: + tau (int, optional): Temperature. Defaults to 1. + reduction (str): Specifies the reduction to apply to the loss: + ``'none'`` | ``'none'`` | ``'sum'`` | ``'mean'``. + ``'none'``: no reduction will be applied, + ``'sum'``: the output will be summed, + ``'mean'``: the output will be divided by the number of + elements in the output. + Default: ``'mean'`` + mult_tem_square (bool, optional): Multiply square of temperature + or not. Defaults to True. + loss_weight (float): Weight of loss. Defaults to 1.0. + """ + + def __init__( + self, + tau: float = 1.0, + reduction: str = 'mean', + mult_tem_square: bool = True, + loss_weight: float = 1.0, + ) -> None: + super().__init__() + self.tau = tau + self.mult_tem_square = mult_tem_square + self.loss_weight = loss_weight + self.cls_criterion = soft_cross_entropy + + accept_reduction = {None, 'none', 'mean', 'sum'} + assert reduction in accept_reduction, \ + f'KLDivergence supports reduction {accept_reduction}, ' \ + f'but gets {reduction}.' + self.reduction = reduction + + def forward( + self, + preds_S: torch.Tensor, + preds_T: torch.Tensor, + weight: torch.Tensor = None, + avg_factor: int = None, + reduction_override: str = None, + ) -> torch.Tensor: + """Forward computation. + + Args: + preds_S (torch.Tensor): The student model prediction with + shape (N, C). + preds_T (torch.Tensor): The teacher model prediction with + shape (N, C). + weight (torch.Tensor, optional): Sample-wise loss weight with + shape (N, C). Defaults to None. + avg_factor (int, optional): Average factor that is used to average + the loss. Defaults to None. + reduction_override (str, optiom): Override redunction in forward. + Defaults to None. + + Return: + torch.Tensor: The calculated loss value. + """ + reduction = ( + reduction_override if reduction_override else self.reduction) + + preds_S = preds_S / self.tau + soft_label = F.softmax((preds_T / self.tau), dim=-1) + loss_cls = self.loss_weight * self.cls_criterion( + preds_S, + soft_label, + weight, + reduction=reduction, + avg_factor=avg_factor) + if self.mult_tem_square: + loss_cls *= (self.tau**2) + return loss_cls diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/kl_divergence.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/kl_divergence.py new file mode 100755 index 000000000..d79d74c49 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/kl_divergence.py @@ -0,0 +1,66 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class KLDivergence(nn.Module): + """A measure of how one probability distribution Q is different from a + second, reference probability distribution P. + + Args: + tau (float): Temperature coefficient. Defaults to 1.0. + reduction (str): Specifies the reduction to apply to the loss: + ``'none'`` | ``'batchmean'`` | ``'sum'`` | ``'mean'``. + ``'none'``: no reduction will be applied, + ``'batchmean'``: the sum of the output will be divided by + the batchsize, + ``'sum'``: the output will be summed, + ``'mean'``: the output will be divided by the number of + elements in the output. + Default: ``'batchmean'`` + loss_weight (float): Weight of loss. Defaults to 1.0. + teacher_detach (bool): Whether to detach the teacher model prediction. + Will set to ``'False'`` in some data-free distillation algorithms. + Defaults to True. + """ + + def __init__( + self, + tau: float = 1.0, + reduction: str = 'batchmean', + loss_weight: float = 1.0, + teacher_detach: bool = True, + ): + super(KLDivergence, self).__init__() + self.tau = tau + self.loss_weight = loss_weight + self.teacher_detach = teacher_detach + + accept_reduction = {'none', 'batchmean', 'sum', 'mean'} + assert reduction in accept_reduction, \ + f'KLDivergence supports reduction {accept_reduction}, ' \ + f'but gets {reduction}.' + self.reduction = reduction + + def forward(self, preds_S, preds_T): + """Forward computation. + + Args: + preds_S (torch.Tensor): The student model prediction with + shape (N, C, H, W) or shape (N, C). + preds_T (torch.Tensor): The teacher model prediction with + shape (N, C, H, W) or shape (N, C). + + Return: + torch.Tensor: The calculated loss value. + """ + if self.teacher_detach: + preds_T = preds_T.detach() + softmax_pred_T = F.softmax(preds_T / self.tau, dim=1) + logsoftmax_preds_S = F.log_softmax(preds_S / self.tau, dim=1) + loss = (self.tau**2) * F.kl_div( + logsoftmax_preds_S, softmax_pred_T, reduction=self.reduction) + return self.loss_weight * loss diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/l1_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/l1_loss.py new file mode 100755 index 000000000..4a220bc17 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/l1_loss.py @@ -0,0 +1,71 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Optional + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class L1Loss(nn.Module): + """Calculate the one-norm loss between the two inputs. + + Args: + loss_weight (float): Weight of loss. Defaults to 1.0. + size_average (bool, optional): Deprecated (see :attr:`reduction`). By + default, the losses are averaged over each loss element in the + batch. Note that for some losses, there multiple elements per + sample. If the field :attr:`size_average` is set to ``False``, the + losses are instead summed for each minibatch. Ignored when reduce + is ``False``. Defaults to True. + reduce (bool, optional): Deprecated (see :attr:`reduction`). By + default, the losses are averaged or summed over observations for + each minibatch depending on :attr:`size_average`. When + :attr:`reduce` is ``False``, returns a loss per batch element + instead and ignores :attr:`size_average`. Defaults to True. + reduction (string, optional): Specifies the reduction to apply to the + output: ``'none'`` | ``'mean'`` | ``'sum'``. ``'none'``: no + reduction will be applied, ``'mean'``: the sum of the output will + be divided by the number of elements in the output, ``'sum'``: the + output will be summed. Note: :attr:`size_average` and + :attr: `reduce` are in the process of being deprecated, and in the + meantime, specifying either of those two args will override + :attr:`reduction`. Defaults to mean. + """ + + def __init__( + self, + loss_weight: float = 1.0, + size_average: Optional[bool] = None, + reduce: Optional[bool] = None, + reduction: str = 'mean', + ) -> None: + super().__init__() + self.loss_weight = loss_weight + self.size_average = size_average + self.reduce = reduce + + accept_reduction = {'none', 'batchmean', 'sum', 'mean'} + assert reduction in accept_reduction, \ + f'KLDivergence supports reduction {accept_reduction}, ' \ + f'but gets {reduction}.' + self.reduction = reduction + + def forward( + self, + s_feature: torch.Tensor, + t_feature: torch.Tensor, + ) -> torch.Tensor: + """Forward computation. + + Args: + s_feature (torch.Tensor): The student model feature with + shape (N, C, H, W) or shape (N, C). + t_feature (torch.Tensor): The teacher model feature with + shape (N, C, H, W) or shape (N, C). + """ + loss = F.l1_loss(s_feature, t_feature, self.size_average, self.reduce, + self.reduction) + return self.loss_weight * loss diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/l2_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/l2_loss.py new file mode 100755 index 000000000..553131274 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/l2_loss.py @@ -0,0 +1,75 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class L2Loss(nn.Module): + """Calculate the two-norm loss between the two features. + + Args: + loss_weight (float): Weight of loss. Defaults to 1.0. + normalize (bool): Whether to normalize the feature. Defaults to True. + mult (float): Multiplier for feature normalization. Defaults to 1.0. + div_element (bool): Whether to divide the loss by element-wise. + Defaults to False. + dist (bool): Whether to conduct two-norm dist as torch.dist(p=2). + Defaults to False. + """ + + def __init__( + self, + loss_weight: float = 1.0, + normalize: bool = True, + mult: float = 1.0, + div_element: bool = False, + dist: bool = False, + ) -> None: + super().__init__() + self.loss_weight = loss_weight + self.normalize = normalize + self.mult = mult + self.div_element = div_element + self.dist = dist + + def forward( + self, + s_feature: torch.Tensor, + t_feature: torch.Tensor, + ) -> torch.Tensor: + """Forward computation. + + Args: + s_feature (torch.Tensor): The student model feature with + shape (N, C, H, W) or shape (N, C). + t_feature (torch.Tensor): The teacher model feature with + shape (N, C, H, W) or shape (N, C). + """ + if self.normalize: + s_feature = self.normalize_feature(s_feature) + t_feature = self.normalize_feature(t_feature) + + loss = torch.sum(torch.pow(torch.sub(s_feature, t_feature), 2)) + + # Calculate l2_loss as dist. + if self.dist: + loss = torch.sqrt(loss) + else: + if self.div_element: + loss = loss / s_feature.numel() + else: + loss = loss / s_feature.size(0) + + return self.loss_weight * loss + + def normalize_feature(self, feature: torch.Tensor) -> torch.Tensor: + """Normalize the input feature. + + Args: + feature (torch.Tensor): The student model feature with + shape (N, C, H, W) or shape (N, C). + """ + feature = feature.view(feature.size(0), -1) + return feature / feature.norm(2, dim=1, keepdim=True) * self.mult diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/mgd_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/mgd_loss.py new file mode 100755 index 000000000..1321edc53 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/mgd_loss.py @@ -0,0 +1,54 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class MGDLoss(nn.Module): + """PyTorch version of `Masked Generative Distillation. + + ` + + Args: + alpha_mgd (float, optional): Weight of dis_loss. Defaults to 0.00002 + """ + + def __init__(self, alpha_mgd: float = 0.00002) -> None: + super(MGDLoss, self).__init__() + self.alpha_mgd = alpha_mgd + self.loss_mse = nn.MSELoss(reduction='sum') + + def forward(self, preds_S: torch.Tensor, + preds_T: torch.Tensor) -> torch.Tensor: + """Forward function. + + Args: + preds_S(torch.Tensor): Bs*C*H*W, student's feature map + preds_T(torch.Tensor): Bs*C*H*W, teacher's feature map + + Return: + torch.Tensor: The calculated loss value. + """ + assert preds_S.shape == preds_T.shape + loss = self.get_dis_loss(preds_S, preds_T) * self.alpha_mgd + + return loss + + def get_dis_loss(self, preds_S: torch.Tensor, + preds_T: torch.Tensor) -> torch.Tensor: + """Get MSE distance of preds_S and preds_T. + + Args: + preds_S(torch.Tensor): Bs*C*H*W, student's feature map + preds_T(torch.Tensor): Bs*C*H*W, teacher's feature map + + Return: + torch.Tensor: The calculated mse distance value. + """ + N, C, H, W = preds_T.shape + dis_loss = self.loss_mse(preds_S, preds_T) / N + + return dis_loss diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/ofd_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/ofd_loss.py new file mode 100755 index 000000000..2e0c0adc6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/ofd_loss.py @@ -0,0 +1,56 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class OFDLoss(nn.Module): + """A Comprehensive Overhaul of Feature Distillation + https://sites.google.com/view/byeongho-heo/overhaul. + + The partial L2loss, only calculating loss when + `out_s > out_t` or `out_t > 0`. + + Args: + loss_weight (float, optional): loss weight. Defaults to 1.0. + mul_factor (float, optional): multiply factor. Defaults to 1000. + """ + + def __init__(self, + loss_weight: float = 1.0, + mul_factor: float = 1000.) -> None: + super(OFDLoss, self).__init__() + self.loss_weight = loss_weight + self.mul_factor = mul_factor + + def forward_train(self, s_feature: torch.Tensor, + t_feature: torch.Tensor) -> torch.Tensor: + """forward func for training. + + Args: + s_feature (torch.Tensor): student's feature + t_feature (torch.Tensor): teacher's feature + + Returns: + torch.Tensor: loss + """ + bsz = s_feature.shape[0] + loss = torch.nn.functional.mse_loss( + s_feature, t_feature, reduction='none') + loss = loss * ((s_feature > t_feature) | (t_feature > 0)).float() + return loss.sum() / bsz / self.mul_factor + + def forward(self, s_feature: torch.Tensor, + t_feature: torch.Tensor) -> torch.Tensor: + """forward func. + + Args: + s_feature (torch.Tensor): student's feature + t_feature (torch.Tensor): teacher's feature + + Returns: + torch.Tensor: loss + """ + return self.loss_weight * self.forward_train(s_feature, t_feature) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/pkd_loss.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/pkd_loss.py new file mode 100755 index 000000000..febc05c36 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/pkd_loss.py @@ -0,0 +1,83 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Tuple, Union + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class PKDLoss(nn.Module): + """PyTorch version of `PKD: General Distillation Framework for Object + Detectors via Pearson Correlation Coefficient. + + `_. + + Args: + loss_weight (float): Weight of loss. Defaults to 1.0. + resize_stu (bool): If True, we'll down/up sample the features of the + student model to the spatial size of those of the teacher model if + their spatial sizes are different. And vice versa. Defaults to + True. + """ + + def __init__(self, loss_weight=1.0, resize_stu=True): + super(PKDLoss, self).__init__() + self.loss_weight = loss_weight + self.resize_stu = resize_stu + + def norm(self, feat: torch.Tensor) -> torch.Tensor: + """Normalize the feature maps to have zero mean and unit variances. + + Args: + feat (torch.Tensor): The original feature map with shape + (N, C, H, W). + """ + assert len(feat.shape) == 4 + N, C, H, W = feat.shape + feat = feat.permute(1, 0, 2, 3).reshape(C, -1) + mean = feat.mean(dim=-1, keepdim=True) + std = feat.std(dim=-1, keepdim=True) + feat = (feat - mean) / (std + 1e-6) + return feat.reshape(C, N, H, W).permute(1, 0, 2, 3) + + def forward(self, preds_S: Union[torch.Tensor, Tuple], + preds_T: Union[torch.Tensor, Tuple]) -> torch.Tensor: + """Forward computation. + + Args: + preds_S (torch.Tensor | Tuple[torch.Tensor]): The student model + prediction. If tuple, it should be several tensors with shape + (N, C, H, W). + preds_T (torch.Tensor | Tuple[torch.Tensor]): The teacher model + prediction. If tuple, it should be several tensors with shape + (N, C, H, W). + + Return: + torch.Tensor: The calculated loss value. + """ + if isinstance(preds_S, torch.Tensor): + preds_S, preds_T = (preds_S, ), (preds_T, ) + + loss = 0. + + for pred_S, pred_T in zip(preds_S, preds_T): + size_S, size_T = pred_S.shape[2:], pred_T.shape[2:] + if size_S[0] != size_T[0]: + if self.resize_stu: + pred_S = F.interpolate(pred_S, size_T, mode='bilinear') + else: + pred_T = F.interpolate(pred_T, size_S, mode='bilinear') + assert pred_S.shape == pred_T.shape + + norm_S, norm_T = self.norm(pred_S), self.norm(pred_T) + + # First conduct feature normalization and then calculate the + # MSE loss. Methematically, it is equivalent to firstly calculate + # the Pearson Correlation Coefficient (r) between two feature + # vectors, and then use 1-r as the new feature imitation loss. + loss += F.mse_loss(norm_S, norm_T) / 2 + + return loss * self.loss_weight diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/relational_kd.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/relational_kd.py new file mode 100755 index 000000000..1eae338c1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/relational_kd.py @@ -0,0 +1,149 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS + + +def euclidean_distance(pred, squared=False, eps=1e-12): + """Calculate the Euclidean distance between the two examples in the output + representation space. + + Args: + pred (torch.Tensor): The prediction of the teacher or student with + shape (N, C). + squared (bool): Whether to calculate the squared Euclidean + distance. Defaults to False. + eps (float): The minimum Euclidean distance between the two + examples. Defaults to 1e-12. + """ + pred_square = pred.pow(2).sum(dim=-1) # (N, ) + prod = torch.mm(pred, pred.t()) # (N, N) + distance = (pred_square.unsqueeze(1) + pred_square.unsqueeze(0) - + 2 * prod).clamp(min=eps) # (N, N) + + if not squared: + distance = distance.sqrt() + + distance = distance.clone() + distance[range(len(prod)), range(len(prod))] = 0 + return distance + + +def angle(pred): + """Calculate the angle-wise relational potential which measures the angle + formed by the three examples in the output representation space. + + Args: + pred (torch.Tensor): The prediction of the teacher or student with + shape (N, C). + """ + pred_vec = pred.unsqueeze(0) - pred.unsqueeze(1) # (N, N, C) + norm_pred_vec = F.normalize(pred_vec, p=2, dim=2) + angle = torch.bmm(norm_pred_vec, + norm_pred_vec.transpose(1, 2)).view(-1) # (N*N*N, ) + return angle + + +@MODELS.register_module() +class DistanceWiseRKD(nn.Module): + """PyTorch version of distance-wise loss of `Relational Knowledge + Distillation. + + `_. + + Args: + loss_weight (float): Weight of distance-wise distillation loss. + Defaults to 25.0. + with_l2_norm (bool): Whether to normalize the model predictions before + calculating the loss. Defaults to True. + """ + + def __init__(self, loss_weight=25.0, with_l2_norm=True): + super(DistanceWiseRKD, self).__init__() + + self.loss_weight = loss_weight + self.with_l2_norm = with_l2_norm + + def distance_loss(self, preds_S, preds_T): + """Calculate distance-wise distillation loss.""" + d_T = euclidean_distance(preds_T, squared=False) + # mean_d_T is a normalization factor for distance + mean_d_T = d_T[d_T > 0].mean() + d_T = d_T / mean_d_T + + d_S = euclidean_distance(preds_S, squared=False) + mean_d_S = d_S[d_S > 0].mean() + d_S = d_S / mean_d_S + + return F.smooth_l1_loss(d_S, d_T) + + def forward(self, preds_S, preds_T): + """Forward computation. + + Args: + preds_S (torch.Tensor): The student model prediction with + shape (N, C, H, W) or shape (N, C). + preds_T (torch.Tensor): The teacher model prediction with + shape (N, C, H, W) or shape (N, C). + Return: + torch.Tensor: The calculated loss value. + """ + preds_S = preds_S.view(preds_S.shape[0], -1) + preds_T = preds_T.view(preds_T.shape[0], -1) + if self.with_l2_norm: + preds_S = F.normalize(preds_S, p=2, dim=1) + preds_T = F.normalize(preds_T, p=2, dim=1) + + loss = self.distance_loss(preds_S, preds_T) * self.loss_weight + + return loss + + +@MODELS.register_module() +class AngleWiseRKD(nn.Module): + """PyTorch version of angle-wise loss of `Relational Knowledge + Distillation. + + `_. + + Args: + loss_weight (float): Weight of angle-wise distillation loss. + Defaults to 50.0. + with_l2_norm (bool): Whether to normalize the model predictions before + calculating the loss. Defaults to True. + """ + + def __init__(self, loss_weight=50.0, with_l2_norm=True): + super(AngleWiseRKD, self).__init__() + + self.loss_weight = loss_weight + self.with_l2_norm = with_l2_norm + + def angle_loss(self, preds_S, preds_T): + """Calculate the angle-wise distillation loss.""" + angle_T = angle(preds_T) + angle_S = angle(preds_S) + return F.smooth_l1_loss(angle_S, angle_T) + + def forward(self, preds_S, preds_T): + """Forward computation. + + Args: + preds_S (torch.Tensor): The student model prediction with + shape (N, C, H, W) or shape (N, C). + preds_T (torch.Tensor): The teacher model prediction with + shape (N, C, H, W) or shape (N, C). + Return: + torch.Tensor: The calculated loss value. + """ + preds_S = preds_S.view(preds_S.shape[0], -1) + preds_T = preds_T.view(preds_T.shape[0], -1) + if self.with_l2_norm: + preds_S = F.normalize(preds_S, p=2, dim=-1) + preds_T = F.normalize(preds_T, p=2, dim=-1) + + loss = self.angle_loss(preds_S, preds_T) * self.loss_weight + + return loss diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/weighted_soft_label_distillation.py b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/weighted_soft_label_distillation.py new file mode 100755 index 000000000..e7704c5f4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/losses/weighted_soft_label_distillation.py @@ -0,0 +1,59 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class WSLD(nn.Module): + """PyTorch version of `Rethinking Soft Labels for Knowledge + Distillation: A Bias-Variance Tradeoff Perspective + `_. + + Args: + tau (float): Temperature coefficient. Defaults to 1.0. + loss_weight (float): Weight of loss. Defaults to 1.0. + num_classes (int): Defaults to 1000. + """ + + def __init__(self, tau=1.0, loss_weight=1.0, num_classes=1000): + super(WSLD, self).__init__() + + self.tau = tau + self.loss_weight = loss_weight + self.num_classes = num_classes + self.softmax = nn.Softmax(dim=1) + self.logsoftmax = nn.LogSoftmax(dim=1) + + def forward(self, student, teacher, gt_labels): + + student_logits = student / self.tau + teacher_logits = teacher / self.tau + + teacher_probs = self.softmax(teacher_logits) + + ce_loss = -torch.sum( + teacher_probs * self.logsoftmax(student_logits), 1, keepdim=True) + + student_detach = student.detach() + teacher_detach = teacher.detach() + log_softmax_s = self.logsoftmax(student_detach) + log_softmax_t = self.logsoftmax(teacher_detach) + one_hot_labels = F.one_hot( + gt_labels, num_classes=self.num_classes).float() + ce_loss_s = -torch.sum(one_hot_labels * log_softmax_s, 1, keepdim=True) + ce_loss_t = -torch.sum(one_hot_labels * log_softmax_t, 1, keepdim=True) + + focal_weight = ce_loss_s / (ce_loss_t + 1e-7) + ratio_lower = torch.zeros_like(focal_weight) + focal_weight = torch.max(focal_weight, ratio_lower) + focal_weight = 1 - torch.exp(-focal_weight) + ce_loss = focal_weight * ce_loss + + loss = (self.tau**2) * torch.mean(ce_loss) + + loss = self.loss_weight * loss + + return loss diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/__init__.py new file mode 100755 index 000000000..baf12b092 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/__init__.py @@ -0,0 +1,27 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .base_mutable import BaseMutable +from .derived_mutable import DerivedMutable +from .mutable_channel import (BaseMutableChannel, MutableChannelContainer, + OneShotMutableChannel, SimpleMutableChannel, + SquentialMutableChannel) +from .mutable_channel.units import (ChannelUnitType, DCFFChannelUnit, + DMCPChannelUnit, L1MutableChannelUnit, + MutableChannelUnit, + OneShotMutableChannelUnit, + SequentialMutableChannelUnit, + SlimmableChannelUnit) +from .mutable_module import (DiffChoiceRoute, DiffMutableModule, DiffMutableOP, + OneHotMutableOP, OneShotMutableModule, + OneShotMutableOP) +from .mutable_value import MutableValue, OneShotMutableValue + +__all__ = [ + 'OneShotMutableOP', 'OneShotMutableModule', 'DiffMutableOP', + 'DiffChoiceRoute', 'DiffMutableModule', 'DerivedMutable', 'MutableValue', + 'OneShotMutableValue', 'SequentialMutableChannelUnit', + 'L1MutableChannelUnit', 'OneShotMutableChannelUnit', + 'SimpleMutableChannel', 'MutableChannelUnit', 'SlimmableChannelUnit', + 'BaseMutableChannel', 'MutableChannelContainer', 'ChannelUnitType', + 'SquentialMutableChannel', 'OneHotMutableOP', 'OneShotMutableChannel', + 'BaseMutable', 'DCFFChannelUnit', 'DMCPChannelUnit' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/base_mutable.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/base_mutable.py new file mode 100755 index 000000000..2b5972d9f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/base_mutable.py @@ -0,0 +1,94 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import ABC, abstractmethod +from typing import Dict, Optional + +from mmengine.model import BaseModule + +from mmrazor.utils.typing import DumpChosen + + +class BaseMutable(BaseModule, ABC): + """Base Class for mutables. Mutable means a searchable module widely used + in Neural Architecture Search(NAS). + + It mainly consists of some optional operations, and achieving + searchable function by handling choice with ``MUTATOR``. + + All subclass should implement the following APIs: + + - ``fix_chosen()`` + - ``dump_chosen()`` + - ``current_choice.setter()`` + - ``current_choice.getter()`` + + Args: + alias (str, optional): alias of the `MUTABLE`. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 5 initializer including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. + """ + + def __init__(self, + alias: Optional[str] = None, + init_cfg: Optional[Dict] = None) -> None: + super().__init__(init_cfg=init_cfg) + + self.alias = alias + self._is_fixed = False + + @property # type: ignore + @abstractmethod + def current_choice(self): + """Current choice will affect :meth:`forward` and will be used in + :func:`mmrazor.core.subnet.utils.export_fix_subnet` or mutator. + """ + + @current_choice.setter # type: ignore + @abstractmethod + def current_choice(self, choice) -> None: + """Current choice setter will be executed in mutator.""" + + @property + def is_fixed(self) -> bool: + """bool: whether the mutable is fixed. + + Note: + If a mutable is fixed, it is no longer a searchable module, just + a normal fixed module. + If a mutable is not fixed, it still is a searchable module. + """ + return self._is_fixed + + @is_fixed.setter + def is_fixed(self, is_fixed: bool) -> None: + """Set the status of `is_fixed`.""" + assert isinstance(is_fixed, bool), \ + f'The type of `is_fixed` need to be bool type, ' \ + f'but got: {type(is_fixed)}' + if self._is_fixed: + raise AttributeError( + 'The mode of current MUTABLE is `fixed`. ' + 'Please do not set `is_fixed` function repeatedly.') + self._is_fixed = is_fixed + + @abstractmethod + def fix_chosen(self, chosen) -> None: + """Fix mutable with chosen. This function would fix the chosen of + mutable. The :attr:`is_fixed` will be set to True and only the selected + operations can be retained. All subclasses must implement this method. + + Note: + This operation is irreversible. + """ + raise NotImplementedError() + + @abstractmethod + def dump_chosen(self) -> DumpChosen: + """Save the current state of the mutable as a dictionary. + + ``DumpChosen`` has ``chosen`` and ``meta`` fields. ``chosen`` is + necessary, ``fix_chosen`` will use the ``chosen`` . ``meta`` is used to + store some non-essential information. + """ + raise NotImplementedError() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/derived_mutable.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/derived_mutable.py new file mode 100755 index 000000000..ac8a8c60a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/derived_mutable.py @@ -0,0 +1,456 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import sys + +if sys.version_info < (3, 8): + from typing_extensions import Protocol +else: + from typing import Protocol + +import inspect +import logging +from itertools import product +from typing import Any, Callable, Dict, Iterable, Optional, Set, Union + +import torch +from mmengine.logging import print_log +from torch import Tensor + +from mmrazor.utils.typing import DumpChosen +from ..utils import make_divisible +from .base_mutable import BaseMutable + + +class MutableProtocol(Protocol): # pragma: no cover + """Protocol for Mutable.""" + + @property + def current_choice(self) -> Any: + """Current choice.""" + + def derive_expand_mutable(self, expand_ratio: int) -> Any: + """Derive expand mutable.""" + + def derive_divide_mutable(self, ratio: int, divisor: int) -> Any: + """Derive divide mutable.""" + + +class MutableChannelProtocol(MutableProtocol): # pragma: no cover + """Protocol for MutableChannel.""" + + @property + def current_mask(self) -> Tensor: + """Current mask.""" + + +def _expand_choice_fn(mutable: MutableProtocol, + expand_ratio: Union[int, float]) -> Callable: + """Helper function to build `choice_fn` for expand derived mutable.""" + + def fn(): + return int(mutable.current_choice * expand_ratio) + + return fn + + +def _expand_mask_fn( + mutable: MutableProtocol, + expand_ratio: Union[int, float]) -> Callable: # pragma: no cover + """Helper function to build `mask_fn` for expand derived mutable.""" + if not hasattr(mutable, 'current_mask'): + raise ValueError('mutable must have attribute `currnet_mask`') + + def fn(): + mask = mutable.current_mask + if isinstance(expand_ratio, int): + expand_num_channels = mask.size(0) * expand_ratio + expand_choice = mutable.current_choice * expand_ratio + elif isinstance(expand_ratio, float): + expand_num_channels = int(mask.size(0) * expand_ratio) + expand_choice = int(mutable.current_choice * expand_ratio) + else: + raise NotImplementedError( + f'Not support type of expand_ratio: {type(expand_ratio)}') + expand_mask = torch.zeros(expand_num_channels).bool() + expand_mask[:expand_choice] = True + + return expand_mask + + return fn + + +def _divide_and_divise(x: int, ratio: int, divisor: int = 8) -> int: + """Helper function for divide and divise.""" + new_x = x // ratio + + return make_divisible(new_x, divisor) # type: ignore + + +def _divide_choice_fn(mutable: MutableProtocol, + ratio: int, + divisor: int = 8) -> Callable: + """Helper function to build `choice_fn` for divide derived mutable.""" + + def fn(): + return _divide_and_divise(mutable.current_choice, ratio, divisor) + + return fn + + +def _divide_mask_fn(mutable: MutableProtocol, + ratio: int, + divisor: int = 8) -> Callable: # pragma: no cover + """Helper function to build `mask_fn` for divide derived mutable.""" + if not hasattr(mutable, 'current_mask'): + raise ValueError('mutable must have attribute `currnet_mask`') + + def fn(): + mask = mutable.current_mask + divide_num_channels = _divide_and_divise(mask.size(0), ratio, divisor) + divide_choice = _divide_and_divise(mutable.current_choice, ratio, + divisor) + divide_mask = torch.zeros(divide_num_channels).bool() + divide_mask[:divide_choice] = True + + return divide_mask + + return fn + + +def _concat_choice_fn(mutables: Iterable[MutableChannelProtocol]) -> Callable: + """Helper function to build `choice_fn` for concat derived mutable.""" + + def fn(): + return sum((m.current_choice for m in mutables)) + + return fn + + +def _concat_mask_fn(mutables: Iterable[MutableChannelProtocol]) -> Callable: + """Helper function to build `mask_fn` for concat derived mutable.""" + + def fn(): + return torch.cat([m.current_mask for m in mutables]) + + return fn + + +class DerivedMethodMixin: + """A mixin that provides some useful method to derive mutable.""" + + def derive_same_mutable(self: MutableProtocol) -> 'DerivedMutable': + """Derive same mutable as the source.""" + return self.derive_expand_mutable(expand_ratio=1) + + def derive_expand_mutable( + self: MutableProtocol, + expand_ratio: Union[int, BaseMutable, float]) -> 'DerivedMutable': + """Derive expand mutable, usually used with `expand_ratio`.""" + # avoid circular import + if isinstance(expand_ratio, int): + choice_fn = _expand_choice_fn(self, expand_ratio=expand_ratio) + elif isinstance(expand_ratio, float): + choice_fn = _expand_choice_fn(self, expand_ratio=expand_ratio) + elif isinstance(expand_ratio, BaseMutable): + current_ratio = expand_ratio.current_choice + choice_fn = _expand_choice_fn(self, expand_ratio=current_ratio) + else: + raise NotImplementedError( + f'Not support type of ratio: {type(expand_ratio)}') + + mask_fn: Optional[Callable] = None + if hasattr(self, 'current_mask'): + if isinstance(expand_ratio, int): + mask_fn = _expand_mask_fn(self, expand_ratio=expand_ratio) + elif isinstance(expand_ratio, float): + mask_fn = _expand_mask_fn(self, expand_ratio=expand_ratio) + elif isinstance(expand_ratio, BaseMutable): + mask_fn = _expand_mask_fn(self, expand_ratio=current_ratio) + else: + raise NotImplementedError( + f'Not support type of ratio: {type(expand_ratio)}') + + return DerivedMutable(choice_fn=choice_fn, mask_fn=mask_fn) + + def derive_divide_mutable(self: MutableProtocol, + ratio: Union[int, float, BaseMutable], + divisor: int = 8) -> 'DerivedMutable': + """Derive divide mutable, usually used with `make_divisable`.""" + from .mutable_channel import BaseMutableChannel + + # avoid circular import + if isinstance(ratio, int): + choice_fn = _divide_choice_fn(self, ratio=ratio, divisor=divisor) + current_ratio = ratio + elif isinstance(ratio, float): + current_ratio = int(ratio) + choice_fn = _divide_choice_fn(self, ratio=current_ratio, divisor=1) + elif isinstance(ratio, BaseMutable): + current_ratio = int(ratio.current_choice) + choice_fn = _divide_choice_fn(self, ratio=current_ratio, divisor=1) + else: + raise NotImplementedError( + f'Not support type of ratio: {type(ratio)}') + + mask_fn: Optional[Callable] = None + if isinstance(self, BaseMutableChannel) and hasattr( + self, 'current_mask'): + mask_fn = _divide_mask_fn( + self, ratio=current_ratio, divisor=divisor) + elif getattr(self, 'mask_fn', None): # OneShotMutableChannel + mask_fn = _divide_mask_fn( + self, ratio=current_ratio, divisor=divisor) + + return DerivedMutable(choice_fn=choice_fn, mask_fn=mask_fn) + + @staticmethod + def derive_concat_mutable( + mutables: Iterable[MutableChannelProtocol]) -> 'DerivedMutable': + """Derive concat mutable, usually used with `torch.cat`.""" + for mutable in mutables: + if not hasattr(mutable, 'current_mask'): + raise RuntimeError('Source mutable of concat derived mutable ' + 'must have attribute `currnet_mask`') + + choice_fn = _concat_choice_fn(mutables) + mask_fn = _concat_mask_fn(mutables) + + return DerivedMutable(choice_fn=choice_fn, mask_fn=mask_fn) + + +class DerivedMutable(BaseMutable, DerivedMethodMixin): + """Class for derived mutable. + + A derived mutable is a mutable derived from other mutables that has + `current_choice` and `current_mask` attributes (if any). + + Note: + A derived mutable does not have its own search space, so it is + not legal to modify its `current_choice` or `current_mask` directly. + And the only way to modify them is by modifying `current_choice` or + `current_mask` in corresponding source mutables. + + Args: + choice_fn (callable): A closure that controls how to generate + `current_choice`. + mask_fn (callable, optional): A closure that controls how to generate + `current_mask`. Defaults to None. + source_mutables (iterable, optional): Specify source mutables for this + derived mutable. If the argument is None, source mutables will be + traced automatically by parsing mutables in closure variables. + Defaults to None. + alias (str, optional): alias of the `MUTABLE`. Defaults to None. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 5 initializer including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. Defaults to None. + + Examples: + >>> from mmrazor.models.mutables import SquentialMutableChannel + >>> mutable_channel = SquentialMutableChannel(num_channels=3) + >>> # derive expand mutable + >>> derived_mutable_channel = mutable_channel * 2 + >>> # source mutables will be traced automatically + >>> derived_mutable_channel.source_mutables + {SquentialMutableChannel(name=unbind, num_channels=3, current_choice=3)} # noqa: E501 + >>> # modify `current_choice` of `mutable_channel` + >>> mutable_channel.current_choice = 2 + >>> # `current_choice` and `current_mask` of derived mutable will be modified automatically # noqa: E501 + >>> derived_mutable_channel + DerivedMutable(current_choice=4, activated_channels=4, source_mutables={SquentialMutableChannel(name=unbind, num_channels=3, current_choice=2)}, is_fixed=False) # noqa: E501 + """ + + def __init__(self, + choice_fn: Callable, + mask_fn: Optional[Callable] = None, + source_mutables: Optional[Iterable[BaseMutable]] = None, + alias: Optional[str] = None, + init_cfg: Optional[Dict] = None) -> None: + super().__init__(alias, init_cfg) + + self.choice_fn = choice_fn + self.mask_fn = mask_fn + + if source_mutables is None: + source_mutables = self._trace_source_mutables() + if len(source_mutables) == 0: + raise RuntimeError( + 'Can not find source mutables automatically, ' + 'please provide manually.') + else: + source_mutables = set(source_mutables) + for mutable in source_mutables: + if not self.is_source_mutable(mutable): + raise ValueError('Expect all mutable to be source mutable, ' + f'but {mutable} is not') + self.source_mutables = source_mutables + + # TODO + # has no effect + def fix_chosen(self, chosen) -> None: + """Fix mutable with subnet config. + + Warning: + Fix derived mutable will have no actually effect. + """ + print_log( + 'Trying to fix chosen for derived mutable, ' + 'which will have no effect.', + level=logging.WARNING) + + def dump_chosen(self) -> DumpChosen: + """Dump information of chosen. + + Returns: + Dict: Dumped information. + """ + print_log( + 'Trying to dump chosen for derived mutable, ' + 'but its value depend on the source mutables.', + level=logging.WARNING) + return DumpChosen(chosen=self.export_chosen(), meta=None) + + def export_chosen(self): + return self.current_choice + + @property + def is_fixed(self) -> bool: + """Whether the derived mutable is fixed. + + Note: + Depends on whether all source mutables are already fixed. + """ + return all(m.is_fixed for m in self.source_mutables) + + @is_fixed.setter + def is_fixed(self, is_fixed: bool) -> bool: + """Setter of is fixed.""" + raise RuntimeError( + '`is_fixed` of derived mutable should not be modified directly') + + @property + def choices(self): + origin_choices = [m.current_choice for m in self.source_mutables] + + all_choices = [m.choices for m in self.source_mutables] + + product_choices = product(*all_choices) + + derived_choices = list() + for item_choices in product_choices: + for m, choice in zip(self.source_mutables, item_choices): + m.current_choice = choice + + derived_choices.append(self.choice_fn()) + + for m, choice in zip(self.source_mutables, origin_choices): + m.current_choice = choice + + return derived_choices + + @property + def num_choices(self) -> int: + """Number of all choices. + + Note: + Since derive mutable does not have its own search space, the number + of choices will always be `1`. + + Returns: + int: Number of choices. + """ + return 1 + + @property + def current_choice(self): + """Current choice of derived mutable.""" + return self.choice_fn() + + @current_choice.setter + def current_choice(self, choice) -> None: + """Setter of current choice. + + Raises: + RuntimeError: Error when `current_choice` of derived mutable + is modified directly. + """ + raise RuntimeError('Choice of drived mutable can not be set.') + + @property + def current_mask(self) -> Tensor: + """Current mask of derived mutable.""" + if self.mask_fn is None: + raise RuntimeError( + '`mask_fn` must be set before access `current_mask`.') + return self.mask_fn() + + @current_mask.setter + def current_mask(self, mask: Tensor) -> None: + """Setter of current mask. + + Raises: + RuntimeError: Error when `current_mask` of derived mutable + is modified directly. + """ + raise RuntimeError('Mask of drived mutable can not be set.') + + @staticmethod + def _trace_source_mutables_from_closure( + closure: Callable) -> Set[BaseMutable]: + """Trace source mutables from closure.""" + source_mutables: Set[BaseMutable] = set() + + def add_mutables_dfs( + mutable: Union[Iterable, BaseMutable, Dict]) -> None: + nonlocal source_mutables + if isinstance(mutable, BaseMutable): + if isinstance(mutable, DerivedMutable): + source_mutables |= mutable.source_mutables + else: + source_mutables.add(mutable) + # dict is also iterable, should parse first + elif isinstance(mutable, dict): + add_mutables_dfs(mutable.values()) + add_mutables_dfs(mutable.keys()) + elif isinstance(mutable, Iterable): + for m in mutable: + add_mutables_dfs(m) + + noncolcal_pars = inspect.getclosurevars(closure).nonlocals + add_mutables_dfs(noncolcal_pars.values()) + + return source_mutables + + def _trace_source_mutables(self) -> Set[BaseMutable]: + """Trace source mutables.""" + source_mutables = self._trace_source_mutables_from_closure( + self.choice_fn) + if self.mask_fn is not None: + source_mutables |= self._trace_source_mutables_from_closure( + self.mask_fn) + + return source_mutables + + @staticmethod + def is_source_mutable(mutable: object) -> bool: + """Judge whether an object is source mutable(not derived mutable). + + Args: + mutable (object): An object. + + Returns: + bool: Indicate whether the object is source mutable or not. + """ + return isinstance(mutable, BaseMutable) and \ + not isinstance(mutable, DerivedMutable) + + # TODO + # should be __str__? but can not provide info when debug + def __repr__(self) -> str: # pragma: no cover + s = f'{self.__class__.__name__}(' + s += f'current_choice={self.current_choice}, ' + if self.mask_fn is not None: + s += f'activated_channels={self.current_mask.sum().item()}, ' + s += f'source_mutables={self.source_mutables}, ' + s += f'is_fixed={self.is_fixed})' + + return s diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/MutableChannel.md b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/MutableChannel.md new file mode 100755 index 000000000..20b3db816 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/MutableChannel.md @@ -0,0 +1,36 @@ +# MutableChannels + +MutableChannels are used to deal with mutable number of channels in DynamicOps. + +``` +|-----------------------------------------| +| mutable_in_channel(BaseMutableChannel) | +| --------------------------------------- | +| DynamicOp | +| --------------------------------------- | +| mutable_out_channel(BaseMutableChannel) | +| --------------------------------------- | +``` + +\` +All MutableChannels inherit from BaseMutableChannel. Each MutableChannel has to implement two property. + +- current_choice: get and set the choice of the MutableChannel. +- current_mask: get the channel mask according to the current_choice. + +## MutableChannelContainer + +Here, we introduce a special MutableChannel: MutableChannelContainer. As the channels of a DynamicOp may belong to different MutableChannelUnits, we use MutableChannelContainers to store multiple MutableChannels as below. + +``` +----------------------------------------------------------- +| MutableChannelContainer | +----------------------------------------------------------- +|MutableChannel1| MutableChannel2 |MutableChannel3| +----------------------------------------------------------- +``` + +MutableChannelContainer has an method to register MutableChannels. + +- register_mutable: register/store BaseMutableChannel in the + MutableChannelContainer diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/__init__.py new file mode 100755 index 000000000..1dd78cb69 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/__init__.py @@ -0,0 +1,18 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .base_mutable_channel import BaseMutableChannel +from .mutable_channel_container import MutableChannelContainer +from .oneshot_mutable_channel import OneShotMutableChannel +from .sequential_mutable_channel import SquentialMutableChannel +from .simple_mutable_channel import SimpleMutableChannel +from .units import (ChannelUnitType, DCFFChannelUnit, DMCPChannelUnit, + L1MutableChannelUnit, MutableChannelUnit, + OneShotMutableChannelUnit, SequentialMutableChannelUnit, + SlimmableChannelUnit) + +__all__ = [ + 'SimpleMutableChannel', 'L1MutableChannelUnit', + 'SequentialMutableChannelUnit', 'MutableChannelUnit', + 'OneShotMutableChannelUnit', 'SlimmableChannelUnit', 'BaseMutableChannel', + 'MutableChannelContainer', 'SquentialMutableChannel', 'ChannelUnitType', + 'DCFFChannelUnit', 'OneShotMutableChannel', 'DMCPChannelUnit' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/base_mutable_channel.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/base_mutable_channel.py new file mode 100755 index 000000000..65d5a44d6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/base_mutable_channel.py @@ -0,0 +1,85 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""""" +from abc import abstractmethod + +import torch + +from mmrazor.utils.typing import DumpChosen +from ..base_mutable import BaseMutable +from ..derived_mutable import DerivedMethodMixin + + +class BaseMutableChannel(BaseMutable, DerivedMethodMixin): + """BaseMutableChannel works as a channel mask for DynamicOps to select + channels. + + |---------------------------------------| + |mutable_in_channel(BaseMutableChannel) | + |---------------------------------------| + | DynamicOp | + |---------------------------------------| + |mutable_out_channel(BaseMutableChannel)| + |---------------------------------------| + + All subclasses should implement the following APIs and the other + abstract method in ``BaseMutable`` + + - ``current_mask`` + + Args: + num_channels (int): number(dimension) of channels(mask). + """ + + def __init__(self, num_channels: int, **kwargs): + super().__init__(**kwargs) + self.name = '' + self.num_channels = num_channels + + @property # type: ignore + @abstractmethod + def current_mask(self) -> torch.Tensor: + """Return a mask indicating the channel selection.""" + raise NotImplementedError() + + @property + def activated_channels(self) -> int: + """Number of activated channels.""" + return (self.current_mask == 1).sum().item() + + # implementation of abstract methods + + def fix_chosen(self, chosen=None): + """Fix the mutable with chosen.""" + if chosen is not None: + self.current_choice = chosen + + if self.is_fixed: + raise AttributeError( + 'The mode of current MUTABLE is `fixed`. ' + 'Please do not call `fix_chosen` function again.') + + self.is_fixed = True + + def dump_chosen(self) -> DumpChosen: + """Dump chosen.""" + meta = dict(max_channels=self.mask.size(0)) + chosen = self.export_chosen() + + return DumpChosen(chosen=chosen, meta=meta) + + def export_chosen(self) -> int: + return self.activated_channels + + def num_choices(self) -> int: + """Number of available choices.""" + raise NotImplementedError() + + # others + + def __repr__(self): + repr_str = self.__class__.__name__ + repr_str += '(' + repr_str += f'num_channels={self.num_channels}, ' + repr_str += f'activated_channels={self.activated_channels}' + repr_str += ')' + return repr_str diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/mutable_channel_container.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/mutable_channel_container.py new file mode 100755 index 000000000..5706d0750 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/mutable_channel_container.py @@ -0,0 +1,123 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy + +import torch + +from mmrazor.registry import MODELS +from mmrazor.utils import IndexDict +from ...architectures.dynamic_ops.mixins import DynamicChannelMixin +from .base_mutable_channel import BaseMutableChannel +from .simple_mutable_channel import SimpleMutableChannel + + +@MODELS.register_module() +class MutableChannelContainer(BaseMutableChannel): + """MutableChannelContainer inherits from BaseMutableChannel. However, + it's not a single BaseMutableChannel, but a container for + BaseMutableChannel. The mask of MutableChannelContainer consists of + all masks of stored MutableChannels. + + ----------------------------------------------------------- + | MutableChannelContainer | + ----------------------------------------------------------- + |MutableChannel1| MutableChannel2 |MutableChannel3| + ----------------------------------------------------------- + + Important interfaces: + register_mutable: register/store BaseMutableChannel in the + MutableChannelContainer + """ + + def __init__(self, num_channels: int, **kwargs): + super().__init__(num_channels, **kwargs) + self.mutable_channels = IndexDict() + + # choice + + @property + def current_choice(self) -> torch.Tensor: + """Get current choices.""" + if len(self.mutable_channels) == 0: + return torch.ones([self.num_channels]).bool() + else: + self._fill_unregistered_range() + self._assert_mutables_valid() + mutable_channels = list(self.mutable_channels.values()) + masks = [mutable.current_mask for mutable in mutable_channels] + mask = torch.cat(masks) + return mask.bool() + + @current_choice.setter + def current_choice(self, choice): + """Set current choices. + + However, MutableChannelContainer doesn't support directly set mask. You + can change the mask of MutableChannelContainer by changing its stored + BaseMutableChannel. + """ + raise NotImplementedError() + + @property + def current_mask(self) -> torch.Tensor: + """Return current mask.""" + return self.current_choice.bool() + + # basic extension + + def register_mutable(self, mutable_channel: BaseMutableChannel, start: int, + end: int): + """Register/Store BaseMutableChannel in the MutableChannelContainer in + the range [start,end)""" + + self.mutable_channels[(start, end)] = mutable_channel + + @classmethod + def register_mutable_channel_to_module(cls, + module: DynamicChannelMixin, + mutable: BaseMutableChannel, + is_to_output_channel=True, + start=0, + end=-1): + """Register a BaseMutableChannel to a module with + MutableChannelContainers.""" + if end == -1: + end = mutable.current_choice + start + if is_to_output_channel: + container: MutableChannelContainer = module.get_mutable_attr( + 'out_channels') + else: + container = module.get_mutable_attr('in_channels') + assert isinstance(container, MutableChannelContainer) + container.register_mutable(mutable, start, end) + + # private methods + + def _assert_mutables_valid(self): + """Assert the current stored BaseMutableChannels are valid to generate + mask.""" + assert len(self.mutable_channels) > 0 + last_end = 0 + for start, end in self.mutable_channels: + assert start == last_end + last_end = end + assert last_end == self.num_channels, ( + f'channel mismatch: {last_end} vs {self.num_channels}') + + def _fill_unregistered_range(self): + """Fill with SimpleMutableChannels in the range without any stored + BaseMutableChannel. + + For example, if a MutableChannelContainer has 10 channels, and only the + [0,5) is registered with BaseMutableChannels, this method will + automatically register BaseMutableChannels in the range [5,10). + """ + last_end = 0 + for start, end in copy.copy(self.mutable_channels): + if last_end < start: + self.register_mutable( + SimpleMutableChannel(last_end - start), last_end, start) + last_end = end + if last_end < self.num_channels: + self.register_mutable( + SimpleMutableChannel(self.num_channels - last_end), last_end, + self.num_channels) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/oneshot_mutable_channel.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/oneshot_mutable_channel.py new file mode 100755 index 000000000..3265b79c6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/oneshot_mutable_channel.py @@ -0,0 +1,42 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List, Union + +from .sequential_mutable_channel import SquentialMutableChannel + + +class OneShotMutableChannel(SquentialMutableChannel): + """OneShotMutableChannel is a subclass of SquentialMutableChannel. The + difference is that a OneShotMutableChannel limits the candidates of the + choice. + + Args: + num_channels (int): number of channels. + candidate_choices (List[Union[float, int]], optional): A list of + candidate width ratios. Each candidate indicates how many + channels to be reserved. Defaults to []. + choice_mode (str, optional): Mode of choices. Defaults to 'number'. + """ + + def __init__(self, + num_channels: int, + candidate_choices: List[Union[float, int]] = [], + choice_mode='number', + **kwargs): + super().__init__(num_channels, choice_mode, **kwargs) + candidate_choices.sort() + self.candidate_choices = candidate_choices + if candidate_choices == []: + candidate_choices.append(num_channels if self.is_num_mode else 1.0) + + @property + def current_choice(self) -> Union[int, float]: + """Get current choice.""" + return super().current_choice + + @current_choice.setter + def current_choice(self, choice: Union[int, float]): + """Set current choice.""" + assert choice in self.candidate_choices + SquentialMutableChannel.current_choice.fset( # type: ignore + self, # type: ignore + choice) # type: ignore diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/sequential_mutable_channel.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/sequential_mutable_channel.py new file mode 100755 index 000000000..c2b4f9291 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/sequential_mutable_channel.py @@ -0,0 +1,140 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Callable, Union + +import torch + +from mmrazor.registry import MODELS +from ..derived_mutable import DerivedMutable +from .simple_mutable_channel import SimpleMutableChannel + +# TODO discuss later + + +@MODELS.register_module() +class SquentialMutableChannel(SimpleMutableChannel): + """SquentialMutableChannel defines a BaseMutableChannel which switch off + channel mask from right to left sequentially, like '11111000'. + + A choice of SquentialMutableChannel is an integer, which indicates how many + channel are activated from left to right. + + Args: + num_channels (int): number of channels. + """ + + def __init__(self, num_channels: int, choice_mode='number', **kwargs): + + super().__init__(num_channels, **kwargs) + assert choice_mode in ['ratio', 'number'] + self.choice_mode = choice_mode + + @property + def is_num_mode(self): + """Get if the choice is number mode.""" + return self.choice_mode == 'number' + + @property + def current_choice(self) -> Union[int, float]: + """Get current choice.""" + int_choice = (self.mask == 1).sum().item() + if self.is_num_mode: + return int_choice + else: + return self._num2ratio(int_choice) + + @current_choice.setter + def current_choice(self, choice: Union[int, float]): + """Set choice.""" + if isinstance(choice, float): + int_choice = self._ratio2num(choice) + else: + int_choice = choice + self.mask.fill_(0.0) + self.mask[0:int_choice] = 1.0 + + @property + def current_mask(self) -> torch.Tensor: + """Return current mask.""" + return self.mask.bool() + + # methods for + + def fix_chosen(self, chosen=...): + """Fix chosen.""" + if chosen is ...: + chosen = self.current_choice + assert self.is_fixed is False + self.current_choice = chosen + self.is_fixed = True + + def __rmul__(self, other) -> DerivedMutable: + return self * other + + def __mul__(self, other) -> DerivedMutable: + if isinstance(other, int) or isinstance(other, float): + return self.derive_expand_mutable(other) + + from ..mutable_value import OneShotMutableValue + + def expand_choice_fn(mutable1: 'SquentialMutableChannel', + mutable2: OneShotMutableValue) -> Callable: + + def fn(): + return int(mutable1.current_choice * mutable2.current_choice) + + return fn + + def expand_mask_fn(mutable1: 'SquentialMutableChannel', + mutable2: OneShotMutableValue) -> Callable: + + def fn(): + mask = mutable1.current_mask + max_expand_ratio = mutable2.max_choice + current_expand_ratio = mutable2.current_choice + expand_num_channels = int(mask.size(0) * max_expand_ratio) + + expand_choice = int(mutable1.current_choice * + current_expand_ratio) + expand_mask = torch.zeros(expand_num_channels).bool() + expand_mask[:expand_choice] = True + + return expand_mask + + return fn + + if isinstance(other, OneShotMutableValue): + return DerivedMutable( + choice_fn=expand_choice_fn(self, other), + mask_fn=expand_mask_fn(self, other)) + + raise TypeError(f'Unsupported type {type(other)} for mul!') + + def __floordiv__(self, other) -> DerivedMutable: + if isinstance(other, int): + return self.derive_divide_mutable(other) + elif isinstance(other, float): + return self.derive_divide_mutable(int(other)) + if isinstance(other, tuple): + assert len(other) == 2 + return self.derive_divide_mutable(*other) + + from ..mutable_value import OneShotMutableValue + if isinstance(other, OneShotMutableValue): + ratio = other.current_choice + return self.derive_divide_mutable(ratio) + + raise TypeError(f'Unsupported type {type(other)} for div!') + + def _num2ratio(self, choice: Union[int, float]) -> float: + """Convert the a number choice to a ratio choice.""" + if isinstance(choice, float): + return choice + else: + return choice / self.num_channels + + def _ratio2num(self, choice: Union[int, float]) -> int: + """Convert the a ratio choice to a number choice.""" + if isinstance(choice, int): + return choice + else: + return max(1, int(self.num_channels * choice)) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/simple_mutable_channel.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/simple_mutable_channel.py new file mode 100755 index 000000000..9e85f81a3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/simple_mutable_channel.py @@ -0,0 +1,57 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +from typing import Union + +import torch + +from mmrazor.registry import MODELS +from ..derived_mutable import DerivedMutable +from .base_mutable_channel import BaseMutableChannel + + +@MODELS.register_module() +class SimpleMutableChannel(BaseMutableChannel): + """SimpleMutableChannel is a simple BaseMutableChannel, it directly take a + mask as a choice. + + Args: + num_channels (int): number of channels. + """ + + def __init__(self, num_channels: int, **kwargs) -> None: + super().__init__(num_channels, **kwargs) + mask = torch.ones([self.num_channels + ]) # save bool as float for dist training + self.register_buffer('mask', mask) + self.mask: torch.Tensor + + # choice + + @property + def current_choice(self) -> torch.Tensor: + """Get current choice.""" + return self.mask.bool() + + @current_choice.setter + def current_choice(self, choice: torch.Tensor): + """Set current choice.""" + self.mask = choice.to(self.mask.device).float() + + @property + def current_mask(self) -> torch.Tensor: + """Get current mask.""" + return self.current_choice.bool() + + # basic extension + + def expand_mutable_channel( + self, expand_ratio: Union[int, float]) -> DerivedMutable: + """Get a derived SimpleMutableChannel with expanded mask.""" + + def _expand_mask(): + mask = self.current_mask + mask = torch.unsqueeze( + mask, -1).expand(list(mask.shape) + [expand_ratio]).flatten(-2) + return mask + + return DerivedMutable(_expand_mask, _expand_mask, [self]) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/__init__.py new file mode 100755 index 000000000..f6aa19222 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/__init__.py @@ -0,0 +1,15 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .dcff_channel_unit import DCFFChannelUnit +from .dmcp_channel_unit import DMCPChannelUnit +from .l1_mutable_channel_unit import L1MutableChannelUnit +from .mutable_channel_unit import ChannelUnitType, MutableChannelUnit +from .one_shot_mutable_channel_unit import OneShotMutableChannelUnit +from .sequential_mutable_channel_unit import SequentialMutableChannelUnit +from .slimmable_channel_unit import SlimmableChannelUnit + +__all__ = [ + 'L1MutableChannelUnit', 'MutableChannelUnit', + 'SequentialMutableChannelUnit', 'OneShotMutableChannelUnit', + 'SlimmableChannelUnit', 'ChannelUnitType', 'DCFFChannelUnit', + 'DMCPChannelUnit' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/channel_unit.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/channel_unit.py new file mode 100755 index 000000000..e730245d4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/channel_unit.py @@ -0,0 +1,258 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict, List + +import torch.nn as nn +from mmengine.model import BaseModule + +from mmrazor.models.architectures.dynamic_ops.mixins import DynamicChannelMixin +from mmrazor.registry import TASK_UTILS + + +class Channel(BaseModule): + """Channel records information about channels for pruning. + + Args: + name (str): The name of the channel. When the channel is related with + a module, the name should be the name of the module in the model. + module (Any): Module of the channel. + index (Tuple[int,int]): Index(start,end) of the Channel in the Module + node (ChannelNode, optional): A ChannelNode corresponding to the + Channel. Defaults to None. + is_output_channel (bool, optional): Is the channel output channel. + Defaults to True. + """ + + # init + + def __init__(self, + name, + module, + index, + node=None, + is_output_channel=True) -> None: + super().__init__() + self.name = name + self.module: nn.Module = module + self.index = index + self.start = index[0] + self.end = index[1] + + self.node = node + + self.is_output_channel = is_output_channel + + @classmethod + def init_from_cfg(cls, model: nn.Module, config: Dict): + """init a Channel using a config which can be generated by + self.config_template()""" + name = config['name'] + start = config['start'] + end = config['end'] + is_output_channel = config['is_output_channel'] + + name2module = dict(model.named_modules()) + name2module.pop('') + module = name2module[name] if name in name2module else None + return Channel( + name, module, (start, end), is_output_channel=is_output_channel) + + # config template + + def config_template(self): + """Generate a config template which can be used to initialize a Channel + by cls.init_from_cfg(**kwargs)""" + + return { + 'name': str(self.name), + 'start': self.start, + 'end': self.end, + 'is_output_channel': self.is_output_channel + } + + # basic properties + + @property + def num_channels(self) -> int: + """The number of channels in the Channel.""" + return self.index[1] - self.index[0] + + @property + def is_mutable(self) -> bool: + """If the channel is prunable.""" + if self.module is not None: + has_prama = len(list(self.module.parameters())) != 0 + is_dynamic_op = isinstance(self.module, DynamicChannelMixin) + return (not has_prama) or is_dynamic_op + else: + is_unmutable = self.name in [ + 'input_placeholder', 'output_placeholder' + ] + return not is_unmutable + + def __repr__(self) -> str: + return (f'{self.__class__.__name__}(' + f'{self.name}, index={self.index}, ' + f'is_output_channel=' + f'{"true" if self.is_output_channel else "false"}, ' + ')') + + def __eq__(self, obj: object) -> bool: + if isinstance(obj, Channel): + return self.name == obj.name \ + and self.module == obj.module \ + and self.index == obj.index \ + and self.is_output_channel == obj.is_output_channel \ + and self.node == obj.node + else: + return False + + +# Channel && ChannelUnit + + +class ChannelUnit(BaseModule): + """A unit of Channels. + + A ChannelUnit has two list, input_related and output_related, to store + the Channels. These Channels are dependent on each other, and have to + have the same number of activated number of channels. + + Args: + num_channels (int): the number of channels of Channel object. + """ + + # init methods + + def __init__(self, num_channels: int, **kwargs): + super().__init__() + + self.num_channels = num_channels + self.output_related: List[nn.Module] = list() + self.input_related: List[nn.Module] = list() + self.init_args: Dict = { + } # is used to generate new channel unit with same args + + @classmethod + def init_from_cfg(cls, model: nn.Module, config: Dict) -> 'ChannelUnit': + """init a ChannelUnit using a config which can be generated by + self.config_template()""" + + def auto_fill_channel_config(channel_config: Dict, + is_output_channel: bool, + unit_config: Dict = config): + """Fill channel config with default values.""" + if 'start' not in channel_config: + channel_config['start'] = 0 + if 'end' not in channel_config: + channel_config['end'] = unit_config['init_args'][ + 'num_channels'] + channel_config['is_output_channel'] = is_output_channel + + config = copy.deepcopy(config) + if 'channels' in config: + channels = config.pop('channels') + else: + channels = None + unit = cls(**(config['init_args'])) + if channels is not None: + for channel_config in channels['input_related']: + auto_fill_channel_config(channel_config, False) + unit.add_input_related( + Channel.init_from_cfg(model, channel_config)) + for channel_config in channels['output_related']: + auto_fill_channel_config(channel_config, True) + unit.add_output_related( + Channel.init_from_cfg(model, channel_config)) + return unit + + @classmethod + def init_from_channel_unit(cls, + unit: 'ChannelUnit', + args: Dict = {}) -> 'ChannelUnit': + """Initial a object of current class from a ChannelUnit object.""" + args['num_channels'] = unit.num_channels + mutable_unit = cls(**args) + mutable_unit.input_related = unit.input_related + mutable_unit.output_related = unit.output_related + return mutable_unit + + @classmethod + def init_from_channel_analyzer(cls, model, analyzer=None): + """Init MutableChannelUnits from a ChannelAnalyzer.""" + + if analyzer is None: + from mmrazor.models.task_modules.tracer import ChannelAnalyzer + analyzer = ChannelAnalyzer() + if isinstance(analyzer, dict): + analyzer = TASK_UTILS.build(analyzer) + unit_config = analyzer.analyze(model) + return [cls.init_from_cfg(model, cfg) for cfg in unit_config.values()] + + # tools + + @property + def name(self) -> str: + """str: name of the unit""" + if len(self.output_related) + len(self.input_related) > 0: + first_module = (list(self.output_related) + + list(self.input_related))[0] + first_module_name = f'{first_module.name}_{first_module.index}' + else: + first_module_name = 'unitx' + name = f'{first_module_name}_{self.num_channels}' + return getattr(self, '_name', name) + + @name.setter + def name(self, unit_name) -> None: + self._name = unit_name + + @property + def alias(self) -> str: + """str: alias of the unit""" + return self.name + + def config_template(self, + with_init_args=False, + with_channels=False) -> Dict: + """Generate a config template which can be used to initialize a + ChannelUnit by cls.init_from_cfg(**kwargs)""" + config = {} + if with_init_args: + config['init_args'] = {'num_channels': self.num_channels} + if with_channels: + config['channels'] = self._channel_dict() + return config + + # node operations + + def add_output_related(self, channel: Channel): + """Add a Channel which is output related.""" + assert channel.is_output_channel + if channel not in self.output_related: + self.output_related.append(channel) + + def add_input_related(self, channel: Channel): + """Add a Channel which is input related.""" + assert channel.is_output_channel is False + if channel not in self.input_related: + self.input_related.append(channel) + + # others + + def extra_repr(self) -> str: + s = super().extra_repr() + s += f'name={self.name}' + return s + + # private methods + + def _channel_dict(self) -> Dict: + """Return channel config.""" + info = { + 'input_related': + [channel.config_template() for channel in self.input_related], + 'output_related': + [channel.config_template() for channel in self.output_related], + } + return info diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dcff_channel_unit.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dcff_channel_unit.py new file mode 100755 index 000000000..743a6473c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dcff_channel_unit.py @@ -0,0 +1,50 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List, Union + +import torch.nn as nn + +from mmrazor.models.architectures import dynamic_ops +from mmrazor.registry import MODELS +from ..mutable_channel_container import MutableChannelContainer +from .sequential_mutable_channel_unit import SequentialMutableChannelUnit + + +@MODELS.register_module() +class DCFFChannelUnit(SequentialMutableChannelUnit): + """``DCFFChannelUnit`` is for supernet DCFF and based on + OneShotMutableChannelUnit. In DCFF supernet, each module only has one + choice. The channel choice is fixed before training. + + Args: + num_channels (int): The raw number of channels. + candidate_choices (List[Union[int, float]], optional): + A list of candidate width numbers or ratios. Each + candidate indicates how many channels to be reserved. + Defaults to [1.0](choice_mode='number'). + choice_mode (str, optional): Mode of candidates. + One of "ratio" or "number". Defaults to 'ratio'. + divisor (int): Used to make choice divisible. + min_value (int): the minimal value used when make divisible. + min_ratio (float): the minimal ratio used when make divisible. + """ + + def __init__(self, + num_channels: int, + candidate_choices: List[Union[int, float]] = [1.0], + choice_mode: str = 'ratio', + divisor: int = 1, + min_value: int = 1, + min_ratio: float = 0.9) -> None: + super().__init__(num_channels, choice_mode, divisor, min_value, + min_ratio) + + def prepare_for_pruning(self, model: nn.Module): + """In ``DCFFChannelGroup`` nn.Conv2d is replaced with FuseConv2d.""" + self._replace_with_dynamic_ops( + model, { + nn.Conv2d: dynamic_ops.FuseConv2d, + nn.BatchNorm2d: dynamic_ops.DynamicBatchNorm2d, + nn.Linear: dynamic_ops.DynamicLinear + }) + self._register_channel_container(model, MutableChannelContainer) + self._register_mutable_channel(self.mutable_channel) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dmcp_channel_unit.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dmcp_channel_unit.py new file mode 100755 index 000000000..144127420 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dmcp_channel_unit.py @@ -0,0 +1,50 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch.nn as nn + +from mmrazor.models.architectures import dynamic_ops +from mmrazor.registry import MODELS +from ..mutable_channel_container import MutableChannelContainer +from .sequential_mutable_channel_unit import SequentialMutableChannelUnit + + +@MODELS.register_module() +class DMCPChannelUnit(SequentialMutableChannelUnit): + """``DMCPChannelUnit`` is for supernet DMCP and based on + OneShotMutableChannelUnit. In DMCP supernet, each module only has one + choice. The channel choice is fixed before training. + + Note: + In dmcpunit, a new attribute `activated_tensor_channels` is defined + in self.mutable_channel, which is specifically used to store the number + of channels in the form of tensor. Defaults to None. + + Args: + num_channels (int): The raw number of channels. + choice_mode (str, optional): Mode of candidates. + One of "ratio" or "number". Defaults to 'ratio'. + divisor (int): Used to make choice divisible. + min_value (int): the minimal value used when make divisible. + min_ratio (float): the minimal ratio used when make divisible. + """ + + def __init__(self, + num_channels: int, + choice_mode: str = 'number', + divisor: int = 1, + min_value: int = 1, + min_ratio: float = 0.5) -> None: + super().__init__(num_channels, choice_mode, divisor, min_value, + min_ratio) + self.mutable_channel.activated_tensor_channels = None + + def prepare_for_pruning(self, model: nn.Module): + """In ``DMCPChannelGroup`` nn.BatchNorm2d is replaced with + DMCPBatchNorm2d.""" + self._replace_with_dynamic_ops( + model, { + nn.Conv2d: dynamic_ops.DynamicConv2d, + nn.BatchNorm2d: dynamic_ops.DMCPBatchNorm2d, + nn.Linear: dynamic_ops.DynamicLinear + }) + self._register_channel_container(model, MutableChannelContainer) + self._register_mutable_channel(self.mutable_channel) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/group_fisher_unit.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/group_fisher_unit.py new file mode 100755 index 000000000..7d33f4232 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/group_fisher_unit.py @@ -0,0 +1,7 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This file includes the modules in the impl folder. + +As it only records impl modules, it is not initialized automatically. +""" +from mmrazor.implementations.pruning.group_fisher import \ + GroupFisherChannelUnit # noqa diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/l1_mutable_channel_unit.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/l1_mutable_channel_unit.py new file mode 100755 index 000000000..8b3c258ad --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/l1_mutable_channel_unit.py @@ -0,0 +1,82 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Union + +import torch +import torch.nn as nn + +from mmrazor.registry import MODELS +from ..simple_mutable_channel import SimpleMutableChannel +from .sequential_mutable_channel_unit import SequentialMutableChannelUnit + + +@MODELS.register_module() +class L1MutableChannelUnit(SequentialMutableChannelUnit): + """Implementation of L1-norm pruning algorithm. It compute the l1-norm of + modules and preferly prune the modules with less l1-norm. + + Please refer to papre `https://arxiv.org/pdf/1608.08710.pdf` for more + detail. + """ + + def __init__(self, + num_channels: int, + choice_mode='number', + divisor=1, + min_value=1, + min_ratio=0.9) -> None: + super().__init__(num_channels, choice_mode, divisor, min_value, + min_ratio) + self.mutable_channel = SimpleMutableChannel(num_channels) + + # choices + + @property + def current_choice(self) -> Union[int, float]: + num = self.mutable_channel.activated_channels + if self.is_num_mode: + return num + else: + return self._num2ratio(num) + + @current_choice.setter + def current_choice(self, choice: Union[int, float]): + int_choice = self._get_valid_int_choice(choice) + mask = self._generate_mask(int_choice).bool() + self.mutable_channel.current_choice = mask + + # private methods + + def _generate_mask(self, choice: int) -> torch.Tensor: + """Generate mask using choice.""" + norm = self._get_unit_norm() + idx = norm.topk(choice)[1] + mask = torch.zeros([self.num_channels]).to(idx.device) + mask.scatter_(0, idx, 1) + return mask + + def _get_l1_norm(self, module: Union[nn.modules.conv._ConvNd, nn.Linear], + start, end): + """Get l1-norm of a module.""" + if isinstance(module, nn.modules.conv._ConvNd): + weight = module.weight.flatten(1) # out_c * in_c * k * k + elif isinstance(module, nn.Linear): + weight = module.weight # out_c * in_c + weight = weight[start:end] + norm = weight.abs().mean(dim=[1]) + return norm + + def _get_unit_norm(self): + """Get l1-norm of the unit by averaging the l1-norm of the moduls in + the unit.""" + avg_norm = 0 + module_num = 0 + for channel in self.output_related: + if isinstance(channel.module, + nn.modules.conv._ConvNd) or isinstance( + channel.module, nn.Linear): + norm = self._get_l1_norm(channel.module, channel.start, + channel.end) + avg_norm += norm + module_num += 1 + avg_norm = avg_norm / module_num + return avg_norm diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.ipynb b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.ipynb new file mode 100755 index 000000000..bc40d191b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.ipynb @@ -0,0 +1,314 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# MutableChannelUnit" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each MutableChannelUnit is a basic unit for pruning. It records all channels which are dependent on each other.\n", + "Below, we will introduce you about:\n", + "1. The data structure of MutableChannelUnit.\n", + "2. How to prune the model with a MutableChannelUnit.\n", + "3. How to get MutableChannelUnits.\n", + "4. How to develop a new MutableChannelUnit for a new pruning algorithm.\n", + "

    \"MutableChannelUnit\"

    " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The Data Structure of MutableChannelUnit" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, let's parse a model and get several MutableChannelUnits." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# define a model\n", + "from mmengine.model import BaseModel\n", + "from torch import nn\n", + "from collections import OrderedDict\n", + "\n", + "class MyModel(nn.Module):\n", + "\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.net = nn.Sequential(\n", + " OrderedDict([('conv0', nn.Conv2d(3, 8, 3, 1, 1)),\n", + " ('relu', nn.ReLU()),\n", + " ('conv1', nn.Conv2d(8, 16, 3, 1, 1))]))\n", + " self.pool = nn.AdaptiveAvgPool2d(1)\n", + " self.head = nn.Linear(16, 1000)\n", + "\n", + " def forward(self, x):\n", + " feature = self.net(x)\n", + " pool = self.pool(feature).flatten(1)\n", + " return self.head(pool)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# There are multiple types of MutableChannelUnits. Here, We take SequentialMutableChannelUnit as the example.\n", + "from mmrazor.models.mutables.mutable_channel.units import SequentialMutableChannelUnit\n", + "from mmrazor.structures.graph import ModuleGraph\n", + "from typing import List\n", + "\n", + "model = MyModel()\n", + "units: List[\n", + " SequentialMutableChannelUnit] = SequentialMutableChannelUnit.init_from_channel_analyzer(model) # type: ignore\n", + "print(\n", + " f'This model has {len(units)} MutableChannelUnit(SequentialMutableChannelUnit).'\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "unit1=units[1]\n", + "print(unit1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As shown above, each MutableChannelUnit has four important attributes: \n", + "1. name: str\n", + "2. output_related: ModuleList\n", + "3. input_related: ModuleList\n", + "4. mutable_channel: BaseMutableChannel\n", + "\n", + "\"name\" is the identifier of the MutableChannelUnit. It's automatically generated usually.\n", + "\n", + "\"output_related\" and \"input_related\" are two ModuleLists. They store all Channels with channel dependency.\n", + "The difference is that the \"output_related\" includes output channels and the \"input_related\" includes input channels.\n", + "All these channels\n", + "\n", + "\"mutable_channel\" is a BaseMutableChannel used to control the channel mask of modules. The mutable_channel is registered to the modules whose channels are stored in \"output_related\" and \"input_related\"." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## How to prune the model with a MutableChannelUnit." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are three steps to prune the model using a MutableChannelUnit:\n", + "1. replace modules, whose channel are stored in the \"output_related\" and \"input_related\", with dynamic ops which are able to deal with mutable number of channels.\n", + "2. register the \"mutable_channel\" to the replaced dynamic ops.\n", + "3. change the choice of the \"mutable_channel\".\n", + "\n", + "For simplicity, we run step 1 and 2 with one method \"prepare_for_pruning\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# We run \"prepare_for_pruning\" once before pruning to run step 1 and 2 above.\n", + "unit1.prepare_for_pruning(model)\n", + "print(f'The current choice of unit1 is {unit1.current_choice}.')\n", + "print(model.net.conv0)\n", + "print(model.net.conv1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We prune the model by changing the current_choice of the MutableChannelUnits." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sampled_choice=unit1.sample_choice()\n", + "print(f'We get a sampled choice {sampled_choice}.')\n", + "unit1.current_choice=sampled_choice\n", + "print(model.net.conv0)\n", + "print(model.net.conv1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Besides, different types of MutableChannelUnit may have different types of choices. Please read documents for more details." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## How to get MutableChannelUnits." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are three ways to get MutableChannelUnits.\n", + "1. Using a tracer.\n", + " This way, firstly, converts a model to a graph, then converts the graph to MutableChannelUnits. It automatically returns all available MutableChannelUnits.\n", + "2. Using a config.\n", + " This way uses a config to initialize a MutableChannelUnit.\n", + "3. Using a predefined model.\n", + " This way parses a predefined model with dynamic ops. It returns all available MutableChannelUnits.\n", + "\n", + "All these three ways have corresponding documents in the README of ChannelMutator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# 1. using tracer\n", + "def get_mutable_channel_units_using_tracer(model):\n", + " units = SequentialMutableChannelUnit.init_from_channel_analyzer(model)\n", + " return units\n", + "\n", + "\n", + "model = MyModel()\n", + "units = get_mutable_channel_units_using_tracer(model)\n", + "print(f'The model has {len(units)} MutableChannelUnits.')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# 2. using config\n", + "config = {\n", + " 'init_args': {\n", + " 'num_channels': 8,\n", + " },\n", + " 'channels': {\n", + " 'input_related': [{\n", + " 'name': 'net.conv1',\n", + " }],\n", + " 'output_related': [{\n", + " 'name': 'net.conv0',\n", + " }]\n", + " },\n", + " 'choice': 8\n", + "}\n", + "unit=SequentialMutableChannelUnit.init_from_cfg(model, config)\n", + "print(unit)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# 3. using predefined model\n", + "\n", + "from mmrazor.models.architectures.dynamic_ops import DynamicConv2d, DynamicLinear\n", + "from mmrazor.models.mutables import MutableChannelUnit, MutableChannelContainer,SquentialMutableChannel\n", + "from collections import OrderedDict\n", + "\n", + "class MyDynamicModel(BaseModel):\n", + "\n", + " def __init__(self):\n", + " super().__init__(None, None)\n", + " self.net = nn.Sequential(\n", + " OrderedDict([('conv0', DynamicConv2d(3, 8, 3, 1, 1)),\n", + " ('relu', nn.ReLU()),\n", + " ('conv1', DynamicConv2d(8, 16, 3, 1, 1))]))\n", + " self.pool = nn.AdaptiveAvgPool2d(1)\n", + " self.head = DynamicLinear(16, 1000)\n", + "\n", + " # register MutableChannelContainer\n", + " MutableChannelUnit._register_channel_container(\n", + " self, MutableChannelContainer)\n", + " self._register_mutables()\n", + "\n", + " def forward(self, x):\n", + " feature = self.net(x)\n", + " pool = self.pool(feature).flatten(1)\n", + " return self.head(pool)\n", + "\n", + " def _register_mutables(self):\n", + " mutable1 = SquentialMutableChannel(8)\n", + " mutable2 = SquentialMutableChannel(16)\n", + " MutableChannelContainer.register_mutable_channel_to_module(\n", + " self.net.conv0, mutable1, is_to_output_channel=True)\n", + " MutableChannelContainer.register_mutable_channel_to_module(\n", + " self.net.conv1, mutable1, is_to_output_channel=False)\n", + "\n", + " MutableChannelContainer.register_mutable_channel_to_module(\n", + " self.net.conv1, mutable2, is_to_output_channel=True)\n", + " MutableChannelContainer.register_mutable_channel_to_module(\n", + " self.head, mutable2, is_to_output_channel=False)\n", + "model=MyDynamicModel()\n", + "units=SequentialMutableChannelUnit.init_from_predefined_model(model) \n", + "print(f'The model has {len(units)} MutableChannelUnits.')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.9.13 ('lab2max')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "e31a827d0913016ad78e01c7b97f787f4b9e53102dd62d238e8548bcd97ff875" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.py new file mode 100755 index 000000000..251214f70 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.py @@ -0,0 +1,308 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This module defines MutableChannelUnit.""" +import abc +# from collections import set +from typing import Dict, List, Type, TypeVar + +import torch +import torch.nn as nn + +from mmrazor.models.architectures.dynamic_ops.mixins import DynamicChannelMixin +from mmrazor.models.mutables import DerivedMutable +from mmrazor.models.mutables.mutable_channel import (BaseMutableChannel, + MutableChannelContainer) +from mmrazor.models.utils import get_module_device +from .channel_unit import Channel, ChannelUnit + + +class MutableChannelUnit(ChannelUnit): + # init methods + def __init__(self, num_channels: int, **kwargs) -> None: + """MutableChannelUnit inherits from ChannelUnit, which manages channels + with channel-dependency. Compared with ChannelUnit, MutableChannelUnit + defines the core interfaces for pruning. By inheriting + MutableChannelUnit, we can implement a variant pruning and nas + algorithm. These apis includes. + + - basic property + - name + - is_mutable + - before pruning + - prepare_for_pruning + - pruning stage + - current_choice + - sample_choice + - after pruning + - fix_chosen + + Args: + num_channels (int): dimension of the channels of the Channel + objects in the unit. + """ + + super().__init__(num_channels) + + @classmethod + def init_from_cfg(cls, model: nn.Module, config: Dict): + """init a Channel using a config which can be generated by + self.config_template(), include init choice.""" + unit = super().init_from_cfg(model, config) + # TO DO: add illegal judgement here? + if 'choice' in config: + unit.current_choice = config['choice'] + return unit + + @classmethod + def init_from_mutable_channel(cls, mutable_channel: BaseMutableChannel): + unit = cls(mutable_channel.num_channels) + return unit + + @classmethod + def init_from_predefined_model(cls, model: nn.Module): + """Initialize units using the model with pre-defined dynamicops and + mutable-channels.""" + + def process_container(container: MutableChannelContainer, + module, + module_name, + mutable2units, + is_output=True): + for index, mutable in container.mutable_channels.items(): + derived_choices = mutable.current_choice + if isinstance(derived_choices, torch.Tensor): + derived_choices = derived_choices.sum().item() + if isinstance(mutable, DerivedMutable): + source_mutables: set = \ + mutable._trace_source_mutables() + source_channel_mutables = [ + mutable for mutable in source_mutables + if isinstance(mutable, BaseMutableChannel) + ] + assert len(source_channel_mutables) == 1, ( + 'only support one mutable channel ' + 'used in DerivedMutable') + mutable = source_channel_mutables[0] + + if mutable not in mutable2units: + mutable2units[mutable] = cls.init_from_mutable_channel( + mutable) + + unit: MutableChannelUnit = mutable2units[mutable] + if is_output: + unit.add_output_related( + Channel( + module_name, + module, + index, + is_output_channel=is_output)) + else: + unit.add_input_related( + Channel( + module_name, + module, + index, + is_output_channel=is_output)) + + mutable2units: Dict = {} + for name, module in model.named_modules(): + if isinstance(module, DynamicChannelMixin): + in_container: MutableChannelContainer = \ + module.get_mutable_attr( + 'in_channels') + out_container: MutableChannelContainer = \ + module.get_mutable_attr( + 'out_channels') + process_container(in_container, module, name, mutable2units, + False) + process_container(out_container, module, name, mutable2units, + True) + units = list(mutable2units.values()) + return units + + # properties + + @property + def mutable_prefix(self) -> str: + """Mutable prefix.""" + return 'channel' + + @property + def is_mutable(self) -> bool: + """If the channel-unit is prunable.""" + + def traverse(channels: List[Channel]): + has_dynamic_op = False + all_channel_prunable = True + for channel in channels: + if channel.is_mutable is False: + all_channel_prunable = False + break + if isinstance(channel.module, DynamicChannelMixin): + has_dynamic_op = True + return has_dynamic_op, all_channel_prunable + + input_has_dynamic_op, input_all_prunable = traverse(self.input_related) + output_has_dynamic_op, output_all_prunable = traverse( + self.output_related) + + return len(self.output_related) > 0 \ + and len(self.input_related) > 0 \ + and input_has_dynamic_op \ + and input_all_prunable \ + and output_has_dynamic_op \ + and output_all_prunable + + def config_template(self, + with_init_args=False, + with_channels=False) -> Dict: + """Return the config template of this unit. By default, the config + template only includes a key 'choice'. + + Args: + with_init_args (bool): if the config includes args for + initialization. + with_channels (bool): if the config includes info about + channels. the config with info about channels can used to + parse channel units without tracer. + """ + config = super().config_template(with_init_args, with_channels) + config['choice'] = self.current_choice + return config + + # before pruning: prepare a model + + @abc.abstractmethod + def prepare_for_pruning(self, model): + """Post process after parse units. + + For example, we need to register mutables to dynamic-ops. + """ + raise NotImplementedError + + # pruning: choice-related + + @property + def current_choice(self): + """Choice of this unit.""" + raise NotImplementedError() + + @current_choice.setter + def current_choice(self, choice) -> None: + """setter of current_choice.""" + raise NotImplementedError() + + @abc.abstractmethod + def sample_choice(self): + """Randomly sample a valid choice and return.""" + raise NotImplementedError() + + # after pruning + + def fix_chosen(self, choice=None): + """Make the channels in this unit fixed.""" + if choice is not None: + self.current_choice = choice + + # private methods + + def _replace_with_dynamic_ops( + self, model: nn.Module, + dynamicop_map: Dict[Type[nn.Module], Type[DynamicChannelMixin]]): + """Replace torch modules with dynamic-ops.""" + + def replace_op(model: nn.Module, name: str, module: nn.Module): + names = name.split('.') + for sub_name in names[:-1]: + model = getattr(model, sub_name) + + setattr(model, names[-1], module) + + def get_module(model, name): + names = name.split('.') + for sub_name in names: + model = getattr(model, sub_name) + return model + + for channel in list(self.input_related) + list(self.output_related): + if isinstance(channel.module, nn.Module): + module = get_module(model, channel.name) + if type(module) in dynamicop_map: + new_module = dynamicop_map[type(module)].convert_from( + module).to(get_module_device(module)) + replace_op(model, channel.name, new_module) + channel.module = new_module + else: + channel.module = module + + @staticmethod + def _register_channel_container( + model: nn.Module, container_class: Type[MutableChannelContainer]): + """register channel container for dynamic ops.""" + device = get_module_device(model) + for module in model.modules(): + if isinstance(module, DynamicChannelMixin): + in_channels = getattr(module, + module.attr_mappings['in_channels'], 0) + if module.get_mutable_attr('in_channels') is None: + module.register_mutable_attr( + 'in_channels', + container_class(in_channels).to(device)) + out_channels = getattr(module, + module.attr_mappings['out_channels'], 0) + if module.get_mutable_attr('out_channels') is None: + + module.register_mutable_attr( + 'out_channels', + container_class(out_channels).to(device)) + + def _register_mutable_channel(self, mutable_channel: BaseMutableChannel): + # register mutable_channel + for channel in list(self.input_related) + list(self.output_related): + module = channel.module + if isinstance(module, DynamicChannelMixin): + container: MutableChannelContainer + if channel.is_output_channel and module.get_mutable_attr( + 'out_channels') is not None: + container = module.get_mutable_attr('out_channels') + elif channel.is_output_channel is False \ + and module.get_mutable_attr('in_channels') is not None: + container = module.get_mutable_attr('in_channels') + else: + raise NotImplementedError() + + if channel.num_channels == self.num_channels: + mutable_channel_ = mutable_channel + start = channel.start + end = channel.end + elif channel.num_channels > self.num_channels: + + if channel.num_channels % self.num_channels == 0: + ratio = channel.num_channels // self.num_channels + else: + ratio = channel.num_channels / self.num_channels + + mutable_channel_ = \ + mutable_channel.expand_mutable_channel(ratio) + start = channel.start + end = channel.end + else: + raise NotImplementedError() + + if (start, end) in container.mutable_channels: + existed = container.mutable_channels[(start, end)] + if not isinstance(existed, DerivedMutable): + assert mutable_channel is existed + else: + source_mutables = list( + existed._trace_source_mutables()) + is_same = [ + mutable_channel is mutable + for mutable in source_mutables + ] + assert any(is_same), 'existed a mutable channel.' + + else: + container.register_mutable(mutable_channel_, start, end) + + +ChannelUnitType = TypeVar('ChannelUnitType', bound=MutableChannelUnit) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/one_shot_mutable_channel_unit.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/one_shot_mutable_channel_unit.py new file mode 100755 index 000000000..220d49b41 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/one_shot_mutable_channel_unit.py @@ -0,0 +1,139 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import random +from typing import Dict, List, Union + +import torch.nn as nn + +from mmrazor.registry import MODELS +from ..oneshot_mutable_channel import OneShotMutableChannel +from .sequential_mutable_channel_unit import SequentialMutableChannelUnit + + +@MODELS.register_module() +class OneShotMutableChannelUnit(SequentialMutableChannelUnit): + """OneShotMutableChannelUnit is for single path supernet such as AutoSlim. + In single path supernet, each module only has one choice invoked at the + same time. A path is obtained by sampling all the available choices. It is + the base class for one shot mutable channel. + + Args: + num_channels (_type_): The raw number of channels. + candidate_choices (List[Union[int, float]], optional): + A list of candidate width ratios. Each + candidate indicates how many channels to be reserved. + Defaults to [0.5, 1.0](choice_mode='ratio'). + choice_mode (str, optional): Mode of candidates. + One of "ratio" or "number". Defaults to 'ratio'. + divisor (int): Used to make choice divisible. + min_value (int): the minimal value used when make divisible. + min_ratio (float): the minimal ratio used when make divisible. + """ + + def __init__(self, + num_channels: int, + candidate_choices: List[Union[int, float]] = [0.5, 1.0], + choice_mode='ratio', + divisor=1, + min_value=1, + min_ratio=0.9) -> None: + super().__init__(num_channels, choice_mode, divisor, min_value, + min_ratio) + + candidate_choices = copy.copy(candidate_choices) + if candidate_choices == []: + candidate_choices.append( + self.num_channels if self.is_num_mode else 1.0) + self.candidate_choices = self._prepare_candidate_choices( + candidate_choices, choice_mode) + + self.mutable_channel = OneShotMutableChannel(num_channels, + self.candidate_choices, + choice_mode) + + self.unit_predefined = False + + @classmethod + def init_from_mutable_channel(cls, mutable_channel: OneShotMutableChannel): + unit = cls(mutable_channel.num_channels, + mutable_channel.candidate_choices, + mutable_channel.choice_mode) + mutable_channel.candidate_choices = unit.candidate_choices + unit.mutable_channel = mutable_channel + return unit + + def prepare_for_pruning(self, model: nn.Module): + """Prepare for pruning.""" + if not self.unit_predefined: + super().prepare_for_pruning(model) + self.current_choice = self.max_choice + + # ~ + + def config_template(self, + with_init_args=False, + with_channels=False) -> Dict: + """Config template of the OneShotMutableChannelUnit.""" + config = super().config_template(with_init_args, with_channels) + if with_init_args: + init_cfg = config['init_args'] + init_cfg.pop('choice_mode') + init_cfg.update({ + 'candidate_choices': self.candidate_choices, + 'choice_mode': self.choice_mode + }) + return config + + # choice + + @property + def current_choice(self) -> Union[int, float]: + """Get current choice.""" + return super().current_choice + + @current_choice.setter + def current_choice(self, choice: Union[int, float]): + """Set current choice.""" + assert choice in self.candidate_choices + int_choice = self._get_valid_int_choice(choice) + choice_ = int_choice if self.is_num_mode else self._num2ratio( + int_choice) + self.mutable_channel.current_choice = choice_ + + def sample_choice(self) -> Union[int, float]: + """Sample a valid choice.""" + rand_idx = random.randint(0, len(self.candidate_choices) - 1) + return self.candidate_choices[rand_idx] + + @property + def min_choice(self) -> Union[int, float]: + """Get Minimal choice.""" + return self.candidate_choices[0] + + @property + def max_choice(self) -> Union[int, float]: + """Get Maximal choice.""" + return self.candidate_choices[-1] + + # private methods + + def _prepare_candidate_choices(self, candidate_choices: List, + choice_mode) -> List: + """Process candidate_choices.""" + choice_type = int if choice_mode == 'number' else float + for choice in candidate_choices: + assert isinstance(choice, choice_type) + if self.is_num_mode: + candidate_choices_ = [ + self._make_divisible(choice) for choice in candidate_choices + ] + else: + candidate_choices_ = [ + self._num2ratio(self._make_divisible(self._ratio2num(choice))) + for choice in candidate_choices + ] + if candidate_choices_ != candidate_choices: + self._make_divisible_info(candidate_choices, candidate_choices_) + + candidate_choices_ = sorted(candidate_choices_) + return candidate_choices_ diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/sequential_mutable_channel_unit.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/sequential_mutable_channel_unit.py new file mode 100755 index 000000000..d32c5fead --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/sequential_mutable_channel_unit.py @@ -0,0 +1,157 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import random +from typing import Dict, Union + +import torch.nn as nn +from mmcv.cnn.bricks import Conv2dAdaptivePadding +from mmengine import MMLogger +from mmengine.model.utils import _BatchNormXd +from mmengine.utils.dl_utils.parrots_wrapper import \ + SyncBatchNorm as EngineSyncBatchNorm + +from mmrazor.models.architectures import dynamic_ops +from mmrazor.registry import MODELS +from ..mutable_channel_container import MutableChannelContainer +from ..sequential_mutable_channel import SquentialMutableChannel +from .mutable_channel_unit import MutableChannelUnit + + +# TODO change the name of SequentialMutableChannelUnit +@MODELS.register_module() +class SequentialMutableChannelUnit(MutableChannelUnit): + """SequentialMutableChannelUnit accepts a intger(number) or float(ratio) as + the choice, which indicates how many of the channels are remained from left + to right, like 11110000. + + Args: + num_channels (int): number of channels. + choice_mode (str): mode of choice, which is one of 'number' or 'ratio'. + divisor (int): Used to make choice divisible. + min_value (int): the minimal value used when make divisible. + min_ratio (float): the minimal ratio used when make divisible. + """ + + def __init__( + self, + num_channels: int, + choice_mode='number', + # args for make divisible + divisor=1, + min_value=1, + min_ratio=0.9) -> None: + super().__init__(num_channels) + assert choice_mode in ['ratio', 'number'] + self.choice_mode = choice_mode + + self.mutable_channel: SquentialMutableChannel = \ + SquentialMutableChannel(num_channels, choice_mode=choice_mode) + + # for make_divisible + self.divisor = divisor + self.min_value = min_value + self.min_ratio = min_ratio + + @classmethod + def init_from_mutable_channel(cls, + mutable_channel: SquentialMutableChannel): + unit = cls(mutable_channel.num_channels, mutable_channel.choice_mode) + unit.mutable_channel = mutable_channel + return unit + + def prepare_for_pruning(self, model: nn.Module): + """Prepare for pruning, including register mutable channels.""" + # register MutableMask + self._replace_with_dynamic_ops( + model, { + Conv2dAdaptivePadding: + dynamic_ops.DynamicConv2dAdaptivePadding, + nn.Conv2d: dynamic_ops.DynamicConv2d, + nn.BatchNorm2d: dynamic_ops.DynamicBatchNorm2d, + nn.Linear: dynamic_ops.DynamicLinear, + nn.SyncBatchNorm: dynamic_ops.DynamicSyncBatchNorm, + EngineSyncBatchNorm: dynamic_ops.DynamicSyncBatchNorm, + _BatchNormXd: dynamic_ops.DynamicBatchNormXd, + }) + self._register_channel_container(model, MutableChannelContainer) + self._register_mutable_channel(self.mutable_channel) + + # ~ + + @property + def is_num_mode(self): + return self.choice_mode == 'number' + + def fix_chosen(self, choice=None): + """fix chosen.""" + super().fix_chosen(choice) + self.mutable_channel.fix_chosen() + + def config_template(self, + with_init_args=False, + with_channels=False) -> Dict: + """Template of config.""" + config = super().config_template(with_init_args, with_channels) + if with_init_args: + init_args: Dict = config['init_args'] + init_args.update( + dict( + choice_mode=self.choice_mode, + divisor=self.divisor, + min_value=self.min_value, + min_ratio=self.min_ratio)) + return config + + # choice + + @property + def current_choice(self) -> Union[int, float]: + """return current choice.""" + return self.mutable_channel.current_choice + + @current_choice.setter + def current_choice(self, choice: Union[int, float]): + """set choice.""" + choice_num_ = self._get_valid_int_choice(choice) + self.mutable_channel.current_choice = choice_num_ + + def sample_choice(self) -> Union[int, float]: + """Sample a choice in (0,1]""" + num_choice = random.randint(1, self.num_channels) + num_choice = self._make_divisible(num_choice) + if self.is_num_mode: + return num_choice + else: + return self._num2ratio(num_choice) + + # private methods + def _get_valid_int_choice(self, choice: Union[float, int]) -> int: + choice_num = self._ratio2num(choice) + choice_num_ = self._make_divisible(choice_num) + if choice_num != choice_num_: + self._make_divisible_info(choice, self.current_choice) + return choice_num_ + + def _make_divisible(self, choice_int: int): + """Make the choice divisible.""" + from mmrazor.models.utils import make_divisible + return make_divisible(choice_int, self.divisor, self.min_value, + self.min_ratio) + + def _num2ratio(self, choice: Union[int, float]) -> float: + """Convert the a number choice to a ratio choice.""" + if isinstance(choice, float): + return choice + else: + return choice / self.num_channels + + def _ratio2num(self, choice: Union[int, float]) -> int: + """Convert the a ratio choice to a number choice.""" + if isinstance(choice, int): + return choice + else: + return max(1, int(self.num_channels * choice)) + + def _make_divisible_info(self, choice, new_choice): + logger = MMLogger.get_current_instance() + logger.info(f'The choice={choice}, which is set to {self.name}, ' + f'is changed to {new_choice} for a divisible choice.') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/slimmable_channel_unit.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/slimmable_channel_unit.py new file mode 100755 index 000000000..a51dce80b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/slimmable_channel_unit.py @@ -0,0 +1,59 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +from typing import List, Union + +import torch.nn as nn + +from mmrazor.models.architectures import dynamic_ops +from mmrazor.registry import MODELS +from ..mutable_channel_container import MutableChannelContainer +from .one_shot_mutable_channel_unit import OneShotMutableChannelUnit + + +@MODELS.register_module() +class SlimmableChannelUnit(OneShotMutableChannelUnit): + """A type of ``MutableChannelUnit`` to train several subnets together. + + Args: + num_channels (int): The raw number of channels. + candidate_choices (List[Union[int, float]], optional): + A list of candidate width ratios. Each + candidate indicates how many channels to be reserved. + Defaults to [0.5, 1.0](choice_mode='ratio'). + choice_mode (str, optional): Mode of candidates. + One of 'ratio' or 'number'. Defaults to 'number'. + divisor (int, optional): Used to make choice divisible. + min_value (int, optional): The minimal value used when make divisible. + min_ratio (float, optional): The minimal ratio used when make + divisible. + """ + + def __init__(self, + num_channels: int, + candidate_choices: List[Union[int, float]] = [], + choice_mode='number', + divisor=1, + min_value=1, + min_ratio=0.9) -> None: + super().__init__(num_channels, candidate_choices, choice_mode, divisor, + min_value, min_ratio) + + def prepare_for_pruning(self, model: nn.Module): + """Prepare for pruning.""" + self._replace_with_dynamic_ops( + model, { + nn.Conv2d: dynamic_ops.DynamicConv2d, + nn.BatchNorm2d: dynamic_ops.SwitchableBatchNorm2d, + nn.Linear: dynamic_ops.DynamicLinear + }) + self.alter_candidates_of_switchbn(self.candidate_choices) + self._register_channel_container(model, MutableChannelContainer) + self._register_mutable_channel(self.mutable_channel) + + def alter_candidates_of_switchbn(self, candidates: List): + """Change candidates of SwitchableBatchNorm2d.""" + for channel in list(self.output_related) + list(self.input_related): + if isinstance(channel.module, dynamic_ops.SwitchableBatchNorm2d) \ + and len(channel.module.candidate_bn) == 0: + channel.module.init_candidates(candidates) + self.current_choice = self.max_choice diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/utils.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/utils.py new file mode 100755 index 000000000..41601ac7a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/utils.py @@ -0,0 +1,80 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +from typing import List + +import torch + +from mmrazor.models.mutables.mutable_channel.units import \ + SequentialMutableChannelUnit +from mmrazor.utils import print_log + + +def assert_model_is_changed(tensors1, tensors2): + """Return if the tensors has the same shape (length).""" + shape1 = get_shape(tensors1, only_length=True) + shape2 = get_shape(tensors2, only_length=True) + assert shape1 == shape2, f'{shape1}!={shape2}' + + +def get_shape(tensor, only_length=False): + """Get the shape of a tensor list/tuple/dict. + + Args: + tensor (Union[List,Tuple,Dict,Tensor]): input tensors. + only_length (bool, optional): If only return the length of the tensors. + Defaults to False. + """ + if isinstance(tensor, torch.Tensor): + if only_length: + return len(tensor.shape) + else: + return tensor.shape + elif isinstance(tensor, list) or isinstance(tensor, tuple): + shapes = [] + for x in tensor: + shapes.append(get_shape(x, only_length)) + return shapes + elif isinstance(tensor, dict): + shapes = {} + for key in tensor: + shapes[key] = get_shape(tensor[key], only_length) + return shapes + else: + raise NotImplementedError( + f'unsuppored type{type(tensor)} to get shape of tensors.') + + +def forward_units(model, try_units: List[SequentialMutableChannelUnit], + units: List[SequentialMutableChannelUnit], demo_input, + template_output): + """Forward a model with MutableChannelUnits and assert if the result + changed.""" + model.eval() + for unit in units: + unit.current_choice = 1.0 + for unit in try_units: + unit.current_choice = min(max(0.1, unit.sample_choice()), 0.9) + if isinstance(demo_input, dict): + tensors = model(**demo_input) + else: + tensors = model(demo_input) + assert_model_is_changed(template_output, tensors) + + +def find_mutable(model, try_units, units, demo_input, template_tensors): + """Find really mutable MutableChannelUnits in some MutableChannelUnits.""" + if len(try_units) == 0: + return [] + try: + forward_units(model, try_units, units, demo_input, template_tensors) + return try_units + except Exception: + if len(try_units) == 1: + print_log(f'Find an unmutable unit {try_units[0]}', level='debug') + return [] + else: + num = len(try_units) + return find_mutable(model, try_units[:num // 2], units, demo_input, + template_tensors) + find_mutable( + model, try_units[num // 2:], units, + demo_input, template_tensors) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/__init__.py new file mode 100755 index 000000000..bcf10c3a8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/__init__.py @@ -0,0 +1,11 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .diff_mutable_module import (DiffChoiceRoute, DiffMutableModule, + DiffMutableOP, OneHotMutableOP) +from .mutable_module import MutableModule +from .one_shot_mutable_module import OneShotMutableModule, OneShotMutableOP + +__all__ = [ + 'DiffMutableModule', 'DiffMutableOP', 'DiffChoiceRoute', + 'OneShotMutableOP', 'OneShotMutableModule', 'MutableModule', + 'OneHotMutableOP' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/diff_mutable_module.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/diff_mutable_module.py new file mode 100755 index 000000000..e524ec67c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/diff_mutable_module.py @@ -0,0 +1,582 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import abstractmethod +from functools import partial +from typing import Any, Callable, Dict, List, Optional, Tuple, Union + +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch import Tensor + +from mmrazor.registry import MODELS +from mmrazor.utils.typing import DumpChosen +from .mutable_module import MutableModule + +PartialType = Callable[[Any, Optional[nn.Parameter]], Any] + + +class DiffMutableModule(MutableModule): + """Base class for differentiable mutables. + + Args: + module_kwargs (dict[str, dict], optional): Module initialization named + arguments. Defaults to None. + alias (str, optional): alias of the `MUTABLE`. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 5 initializer including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. + + Note: + :meth:`forward_all` is called when calculating FLOPs. + """ + + def __init__(self, **kwargs) -> None: + super().__init__(**kwargs) + + @abstractmethod + def sample_choice(self, arch_param: Tensor): + """Sample choice according arch parameters.""" + raise NotImplementedError + + def forward(self, x: Any, arch_param: Optional[nn.Parameter] = None): + """Calls either :func:`forward_fixed` or :func:`forward_arch_param` + depending on whether :func:`is_fixed` is ``True`` and whether + :func:`arch_param` is None. + + To reduce the coupling between `Mutable` and `Mutator`, the + `arch_param` is generated by the `Mutator` and is passed to the + forward function as an argument. + + Note: + :meth:`forward_fixed` is called when in `fixed` mode. + :meth:`forward_arch_param` is called when in `unfixed` mode. + + Args: + x (Any): input data for forward computation. + arch_param (nn.Parameter, optional): the architecture parameters + for ``DiffMutableModule``. + + Returns: + Any: the result of forward + """ + if self.is_fixed: + return self.forward_fixed(x) + else: + if arch_param is None: + return self.forward_all(x) + else: + return self.forward_arch_param(x, arch_param=arch_param) + + def compute_arch_probs(self, arch_param: nn.Parameter) -> Tensor: + """compute chosen probs according to architecture params.""" + return F.softmax(arch_param, -1) + + @abstractmethod + def forward_arch_param(self, x, arch_param: nn.Parameter): + """Forward when the mutable is not fixed. + + All subclasses must implement this method. + """ + + def set_forward_args(self, arch_param: nn.Parameter) -> None: + """Interface for modifying the arch_param using partial.""" + forward_with_default_args: PartialType = \ + partial(self.forward, arch_param=arch_param) + setattr(self, 'forward', forward_with_default_args) + + +@MODELS.register_module() +class DiffMutableOP(DiffMutableModule): + """A type of ``MUTABLES`` for differentiable architecture search, such as + DARTS. Search the best module by learnable parameters `arch_param`. + + Args: + candidates (dict[str, dict]): the configs for the candidate + operations. + fix_threshold (float): The threshold that determines whether to fix + the choice of current module as the op with the maximum `probs`. + It happens when the maximum prob is `fix_threshold` or more higher + then all the other probs. Default to 1.0. + module_kwargs (dict[str, dict], optional): Module initialization named + arguments. Defaults to None. + alias (str, optional): alias of the `MUTABLE`. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 5 initializer including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. + """ + + def __init__( + self, + candidates: Dict[str, Dict], + fix_threshold: float = 1.0, + module_kwargs: Optional[Dict[str, Dict]] = None, + alias: Optional[str] = None, + init_cfg: Optional[Dict] = None, + ) -> None: + super().__init__( + module_kwargs=module_kwargs, alias=alias, init_cfg=init_cfg) + assert len(candidates) >= 1, \ + f'Number of candidate op must greater than or equal to 1, ' \ + f'but got: {len(candidates)}' + + self._is_fixed = False + if fix_threshold < 0 or fix_threshold > 1.0: + raise ValueError( + f'The fix_threshold should be in [0, 1]. Got {fix_threshold}.') + self.fix_threshold = fix_threshold + self._candidates = self._build_ops(candidates, self.module_kwargs) + + @staticmethod + def _build_ops(candidates: Dict[str, Dict], + module_kwargs: Optional[Dict[str, Dict]]) -> nn.ModuleDict: + """Build candidate operations based on candidates configures. + + Args: + candidates (dict[str, dict]): the configs for the candidate + operations. + module_kwargs (dict[str, dict], optional): Module initialization + named arguments. + + Returns: + ModuleDict (dict[str, Any], optional): the key of ``ops`` is + the name of each choice in configs and the value of ``ops`` + is the corresponding candidate operation. + """ + ops = nn.ModuleDict() + for name, op_cfg in candidates.items(): + assert name not in ops + if module_kwargs is not None: + op_cfg.update(module_kwargs) + ops[name] = MODELS.build(op_cfg) + return ops + + def forward_fixed(self, x) -> Tensor: + """Forward when the mutable is in `fixed` mode. + + Args: + x (Any): x could be a Torch.tensor or a tuple of + Torch.tensor, containing input data for forward computation. + + Returns: + Tensor: the result of forward the fixed operation. + """ + return sum(self._candidates[choice](x) for choice in self._chosen) + + def forward_arch_param(self, x, arch_param: nn.Parameter) -> Tensor: + """Forward with architecture parameters. + + Args: + x (Any): x could be a Torch.tensor or a tuple of + Torch.tensor, containing input data for forward computation. + arch_param (str, optional): architecture parameters for + `DiffMutableModule` + + + Returns: + Tensor: the result of forward with ``arch_param``. + """ + + # compute the probs of choice + probs = self.compute_arch_probs(arch_param=arch_param) + + # forward based on probs + outputs = list() + for prob, module in zip(probs, self._candidates.values()): + if prob > 0.: + outputs.append(prob * module(x)) + + return sum(outputs) + + def forward_all(self, x) -> Tensor: + """Forward all choices. Used to calculate FLOPs. + + Args: + x (Any): x could be a Torch.tensor or a tuple of + Torch.tensor, containing input data for forward computation. + + Returns: + Tensor: the result of forward all of the ``choice`` operation. + """ + outputs = list() + for op in self._candidates.values(): + outputs.append(op(x)) + return sum(outputs) + + def fix_chosen(self, chosen: Union[str, List[str]]) -> None: + """Fix mutable with `choice`. This operation would convert `unfixed` + mode to `fixed` mode. The :attr:`is_fixed` will be set to True and only + the selected operations can be retained. + + Args: + chosen (str): the chosen key in ``MUTABLE``. + Defaults to None. + """ + if self.is_fixed: + raise AttributeError( + 'The mode of current MUTABLE is `fixed`. ' + 'Please do not call `fix_chosen` function again.') + + if isinstance(chosen, str): + chosen = [chosen] + + for c in self.choices: + if c not in chosen: + self._candidates.pop(c) + + self._chosen = chosen + self.is_fixed = True + + def sample_choice(self, arch_param: Tensor) -> str: + """Sample choice based on arch_parameters.""" + return self.choices[torch.argmax(arch_param).item()] + + def dump_chosen(self) -> DumpChosen: + chosen = self.export_chosen() + meta = dict(all_choices=self.choices) + return DumpChosen(chosen=chosen, meta=meta) + + def export_chosen(self) -> str: + assert self.current_choice is not None + return self.current_choice + + @property + def choices(self) -> List[str]: + """list: all choices. """ + return list(self._candidates.keys()) + + +@MODELS.register_module() +class OneHotMutableOP(DiffMutableOP): + """A type of ``MUTABLES`` for one-hot sample based architecture search, + such as DSNAS. Search the best module by learnable parameters `arch_param`. + + Args: + candidates (dict[str, dict]): the configs for the candidate + operations. + module_kwargs (dict[str, dict], optional): Module initialization named + arguments. Defaults to None. + alias (str, optional): alias of the `MUTABLE`. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 5 initializer including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. + """ + + def sample_weights(self, + arch_param: nn.Parameter, + probs: torch.Tensor, + random_sample: bool = False) -> Tensor: + """Use one-hot distributions to sample the arch weights based on the + arch params. + + Args: + arch_param (nn.Parameter): architecture parameters for + `DiffMutableModule`. + probs (Tensor): the probs of choice. + random_sample (bool): Whether to random sample arch weights or not + Defaults to False. + + Returns: + Tensor: Sampled one-hot arch weights. + """ + import torch.distributions as D + if random_sample: + uni = torch.ones_like(arch_param) + m = D.one_hot_categorical.OneHotCategorical(uni) + else: + m = D.one_hot_categorical.OneHotCategorical(probs=probs) + return m.sample() + + def forward_arch_param( + self, + x: Any, + arch_param: nn.Parameter, + ) -> Tensor: + """Forward with architecture parameters. + + Args: + x (Any): x could be a Torch.tensor or a tuple of + Torch.tensor, containing input data for forward computation. + arch_param (str, optional): architecture parameters for + `DiffMutableModule`. + + Returns: + Tensor: the result of forward with ``arch_param``. + """ + + # compute the probs of choice + probs = self.compute_arch_probs(arch_param=arch_param) + + if not self.is_fixed: + self.arch_weights = self.sample_weights(arch_param, probs) + sorted_param = torch.topk(probs, 2) + index = ( + sorted_param[0][0] - sorted_param[0][1] >= self.fix_threshold) + if index: + self.fix_chosen(self.choices[index]) + + if self.is_fixed: + index = self.choices.index(self._chosen[0]) + self.arch_weights.data.zero_() + self.arch_weights.data[index].fill_(1.0) + self.arch_weights.requires_grad_() + + # forward based on self.arch_weights + outputs = list() + for prob, module in zip(self.arch_weights, self._candidates.values()): + if prob > 0.: + outputs.append(prob * module(x)) + + return sum(outputs) + + +@MODELS.register_module() +class DiffChoiceRoute(DiffMutableModule): + """A type of ``MUTABLES`` for Neural Architecture Search, which can select + inputs from different edges in a differentiable or non-differentiable way. + It is commonly used in DARTS. + + Args: + edges (nn.ModuleDict): the key of `edges` is the name of different + edges. The value of `edges` can be :class:`nn.Module` or + :class:`DiffMutableModule`. + with_arch_param (bool): whether forward with arch_param. When set to + `True`, a differentiable way is adopted. When set to `False`, + a non-differentiable way is adopted. + alias (str, optional): alias of the `DiffChoiceRoute`. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 6 initializers including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. + + Examples: + >>> import torch + >>> import torch.nn as nn + >>> edges_dict=nn.ModuleDict() + >>> edges_dict.add_module('first_edge', nn.Conv2d(32, 32, 3, 1, 1)) + >>> edges_dict.add_module('second_edge', nn.Conv2d(32, 32, 5, 1, 2)) + >>> edges_dict.add_module('third_edge', nn.MaxPool2d(3, 1, 1)) + >>> edges_dict.add_module('fourth_edge', nn.MaxPool2d(5, 1, 2)) + >>> edges_dict.add_module('fifth_edge', nn.MaxPool2d(7, 1, 3)) + >>> diff_choice_route_cfg = dict( + ... type="DiffChoiceRoute", + ... edges=edges_dict, + ... with_arch_param=True, + ... ) + >>> arch_param + Parameter containing: + tensor([-6.1426e-04, 2.3596e-04, 1.4427e-03, 7.1668e-05, + -8.9739e-04], requires_grad=True) + >>> x = [torch.randn(4, 32, 64, 64) for _ in range(5)] + >>> output=diffchoiceroute.forward_arch_param(x, arch_param) + >>> output.shape + torch.Size([4, 32, 64, 64]) + """ + + def __init__( + self, + edges: nn.ModuleDict, + num_chosen: int = 2, + with_arch_param: bool = False, + alias: Optional[str] = None, + init_cfg: Optional[Dict] = None, + ) -> None: + super().__init__(alias=alias, init_cfg=init_cfg) + assert len(edges) >= 1, \ + f'Number of edges must greater than or equal to 1, ' \ + f'but got: {len(edges)}' + + self._with_arch_param = with_arch_param + self._is_fixed = False + self._candidates: nn.ModuleDict = edges + self.num_chosen = num_chosen + + def forward(self, x: Any, arch_param: Optional[nn.Parameter] = None): + """Calls either :func:`forward_fixed` or :func:`forward_arch_param` + depending on whether :func:`is_fixed` is ``True`` and whether + :func:`arch_param` is None. + + To reduce the coupling between `Mutable` and `Mutator`, the + `arch_param` is generated by the `Mutator` and is passed to the + forward function as an argument. + + Note: + :meth:`forward_fixed` is called when in `fixed` mode. + :meth:`forward_arch_param` is called when in `unfixed` mode. + + Args: + x (Any): input data for forward computation. + arch_param (nn.Parameter, optional): the architecture parameters + for ``DiffMutableModule``. + + Returns: + Any: the result of forward + """ + if self.is_fixed: + return self.forward_fixed(x) + else: + if arch_param is not None and self._with_arch_param: + return self.forward_arch_param(x, arch_param=arch_param) + else: + return self.forward_all(x) + + def forward_fixed(self, inputs: Union[List, Tuple]) -> Tensor: + """Forward when the mutable is in `fixed` mode. + + Args: + inputs (Union[List[Any], Tuple[Any]]): inputs could be a list or + a tuple of Torch.tensor, containing input data for + forward computation. + + Returns: + Tensor: the result of forward the fixed operation. + """ + assert self._chosen is not None, \ + 'Please call fix_chosen before calling `forward_fixed`.' + + outputs = list() + for choice, x in zip(self._unfixed_choices, inputs): + if choice in self._chosen: + outputs.append(self._candidates[choice](x)) + return sum(outputs) + + def forward_arch_param(self, x, arch_param: nn.Parameter) -> Tensor: + """Forward with architecture parameters. + + Args: + x (list[Any] | tuple[Any]]): x could be a list or a tuple + of Torch.tensor, containing input data for forward selection. + arch_param (nn.Parameter): architecture parameters for + for ``DiffMutableModule``. + + Returns: + Tensor: the result of forward with ``arch_param``. + """ + assert len(x) == len(self._candidates), \ + f'Length of `edges` {len(self._candidates)} should be ' \ + f'same as the length of inputs {len(x)}.' + + probs = self.compute_arch_probs(arch_param=arch_param) + + outputs = list() + for prob, module, input in zip(probs, self._candidates.values(), x): + if prob > 0: + # prob may equal to 0 in gumbel softmax. + outputs.append(prob * module(input)) + + return sum(outputs) + + def forward_all(self, x): + """Forward all choices. + + Args: + x (Any): x could be a Torch.tensor or a tuple of + Torch.tensor, containing input data for forward computation. + + Returns: + Tensor: the result of forward all of the ``choice`` operation. + """ + assert len(x) == len(self._candidates), \ + f'Lenght of edges {len(self._candidates)} should be same as ' \ + f'the length of inputs {len(x)}.' + + outputs = list() + for op, input in zip(self._candidates.values(), x): + outputs.append(op(input)) + + return sum(outputs) + + def fix_chosen(self, chosen: List[str]) -> None: + """Fix mutable with `choice`. This operation would convert to `fixed` + mode. The :attr:`is_fixed` will be set to True and only the selected + operations can be retained. + + Args: + chosen (list(str)): the chosen key in ``MUTABLE``. + """ + self._unfixed_choices = self.choices + + if self.is_fixed: + raise AttributeError( + 'The mode of current MUTABLE is `fixed`. ' + 'Please do not call `fix_chosen` function again.') + + for c in self.choices: + if c not in chosen: + self._candidates.pop(c) + + self._chosen = chosen + self.is_fixed = True + + @property + def choices(self) -> List[str]: + """list: all choices. """ + return list(self._candidates.keys()) + + def dump_chosen(self) -> DumpChosen: + chosen = self.export_chosen() + meta = dict(all_choices=self.choices) + return DumpChosen(chosen=chosen, meta=meta) + + def export_chosen(self) -> str: + assert self.current_choice is not None + return self.current_choice + + def sample_choice(self, arch_param: Tensor) -> List[str]: + """sample choice based on `arch_param`.""" + sort_idx = torch.argsort(-arch_param).cpu().numpy().tolist() + choice_idx = sort_idx[:self.num_chosen] + choice = [self.choices[i] for i in choice_idx] + return choice + + +@MODELS.register_module() +class GumbelChoiceRoute(DiffChoiceRoute): + """A type of ``MUTABLES`` for Neural Architecture Search using Gumbel-Max + trick, which can select inputs from different edges in a differentiable or + non-differentiable way. It is commonly used in DARTS. + + Args: + edges (nn.ModuleDict): the key of `edges` is the name of different + edges. The value of `edges` can be :class:`nn.Module` or + :class:`DiffMutableModule`. + tau (float): non-negative scalar temperature in gumbel softmax. + hard (bool): if `True`, the returned samples will be discretized as + one-hot vectors, but will be differentiated as if it is the soft + sample in autograd. Defaults to `True`. + with_arch_param (bool): whether forward with arch_param. When set to + `True`, a differentiable way is adopted. When set to `False`, + a non-differentiable way is adopted. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 6 initializers including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. + """ + + def __init__( + self, + edges: nn.ModuleDict, + tau: float = 1.0, + hard: bool = True, + with_arch_param: bool = False, + alias: Optional[str] = None, + init_cfg: Optional[Dict] = None, + ) -> None: + super().__init__( + edges=edges, + with_arch_param=with_arch_param, + alias=alias, + init_cfg=init_cfg) + self.tau = tau + self.hard = hard + + def compute_arch_probs(self, arch_param: nn.Parameter) -> Tensor: + """Compute chosen probs by Gumbel-Max trick.""" + return F.gumbel_softmax( + arch_param, tau=self.tau, hard=self.hard, dim=-1) + + def set_temperature(self, tau: float) -> None: + """Set temperature of gumbel softmax.""" + self.tau = tau diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/mutable_module.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/mutable_module.py new file mode 100755 index 000000000..6e03df285 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/mutable_module.py @@ -0,0 +1,97 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import abstractmethod +from typing import Any, Dict, List, Optional + +from ..base_mutable import BaseMutable + + +class MutableModule(BaseMutable): + """Base Class for mutables. Mutable means a searchable module widely used + in Neural Architecture Search(NAS). + + It mainly consists of some optional operations, and achieving + searchable function by handling choice with ``MUTATOR``. + + All subclass should implement the following APIs and the other + abstract method in ``BaseMutable``: + + - ``forward()`` + - ``forward_all()`` + - ``forward_fix()`` + - ``choices()`` + + Args: + module_kwargs (dict[str, dict], optional): Module initialization named + arguments. Defaults to None. + alias (str, optional): alias of the `MUTABLE`. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 5 initializer including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. + """ + + def __init__(self, + module_kwargs: Optional[Dict[str, Dict]] = None, + alias: Optional[str] = None, + init_cfg: Optional[Dict] = None) -> None: + super().__init__(alias, init_cfg) + + self.module_kwargs = module_kwargs + self._current_choice = None + + @property + def mutable_prefix(self) -> str: + """Mutable prefix.""" + return 'module' + + @property + def max_choice(self): + """max_choice shouldn't exist.""" + raise AttributeError( + 'MutableModule does not have the attr `max choice`.') + + @property + def min_choice(self): + """min_choice shouldn't exist.""" + raise AttributeError( + 'MutableModule does not have the attr `min choice`.') + + @property + def current_choice(self): + """Current choice will affect :meth:`forward` and will be used in + :func:`mmrazor.core.subnet.utils.export_fix_subnet` or mutator. + """ + return self._current_choice + + @current_choice.setter + def current_choice(self, choice) -> None: + """Current choice setter will be executed in mutator.""" + self._current_choice = choice + + @property + @abstractmethod + def choices(self) -> List[str]: + """list: all choices. All subclasses must implement this method.""" + + @abstractmethod + def forward(self, x: Any) -> Any: + """Forward computation.""" + + @abstractmethod + def forward_fixed(self, x): + """Forward with the fixed mutable. + + All subclasses must implement this method. + """ + + @abstractmethod + def forward_all(self, x): + """Forward all choices. + + All subclasses must implement this method. + """ + + @property + def num_choices(self) -> int: + """Number of choices.""" + return len(self.choices) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/one_shot_mutable_module.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/one_shot_mutable_module.py new file mode 100755 index 000000000..434b05079 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/one_shot_mutable_module.py @@ -0,0 +1,299 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import random +from abc import abstractmethod +from typing import Any, Dict, List, Optional, Union + +import numpy as np +import torch.nn as nn +from torch import Tensor + +from mmrazor.registry import MODELS +from mmrazor.utils.typing import DumpChosen +from .mutable_module import MutableModule + + +class OneShotMutableModule(MutableModule): + """Base class for one shot mutable module. A base type of ``MUTABLES`` for + single path supernet such as Single Path One Shot. + + All subclass should implement the following APIs and the other + abstract method in ``MutableModule``: + + - ``sample_choice()`` + - ``forward_choice()`` + + Note: + :meth:`forward_all` is called when calculating FLOPs. + """ + + def forward(self, x: Any) -> Any: + """Calls either :func:`forward_fixed` or :func:`forward_choice` + depending on whether :func:`is_fixed` is ``True`` and whether + :func:`current_choice` is None. + + Note: + :meth:`forward_fixed` is called in `fixed` mode. + :meth:`forward_all` is called in `unfixed` mode with + :func:`current_choice` is None. + :meth:`forward_choice` is called in `unfixed` mode with + :func:`current_choice` is not None. + + Args: + x (Any): input data for forward computation. + choice (CHOICE_TYPE, optional): the chosen key in ``MUTABLE``. + + Returns: + Any: the result of forward + """ + if self.is_fixed: + return self.forward_fixed(x) + if self.current_choice is None: + return self.forward_all(x) + else: + return self.forward_choice(x, choice=self.current_choice) + + @abstractmethod + def sample_choice(self) -> str: + """Sample random choice. + + Returns: + str: the chosen key in ``MUTABLE``. + """ + + @abstractmethod + def forward_choice(self, x, choice: str): + """Forward with the unfixed mutable and current_choice is not None. + + All subclasses must implement this method. + """ + + +@MODELS.register_module() +class OneShotMutableOP(OneShotMutableModule): + """A type of ``MUTABLES`` for single path supernet, such as Single Path One + Shot. In single path supernet, each choice block only has one choice + invoked at the same time. A path is obtained by sampling all the choice + blocks. + + Args: + candidates (dict[str, dict]): the configs for the candidate + operations. + module_kwargs (dict[str, dict], optional): Module initialization named + arguments. Defaults to None. + alias (str, optional): alias of the `MUTABLE`. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 5 initializer including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. + + Examples: + >>> import torch + >>> from mmrazor.models.mutables import OneShotMutableOP + + >>> candidates = nn.ModuleDict({ + ... 'conv3x3': nn.Conv2d(32, 32, 3, 1, 1), + ... 'conv5x5': nn.Conv2d(32, 32, 5, 1, 2), + + >>> input = torch.randn(1, 32, 64, 64) + >>> op = OneShotMutableOP(candidates) + + >>> op.choices + ['conv3x3', 'conv5x5', 'conv7x7'] + >>> op.num_choices + 3 + >>> op.is_fixed + False + + >>> op.current_choice = 'conv3x3' + >>> unfix_output = op.forward(input) + >>> torch.all(unfixed_output == candidates['conv3x3'](input)) + True + + >>> op.fix_chosen('conv3x3') + >>> fix_output = op.forward(input) + >>> torch.all(fix_output == unfix_output) + True + + >>> op.choices + ['conv3x3'] + >>> op.num_choices + 1 + >>> op.is_fixed + True + """ + + def __init__( + self, + candidates: Union[Dict[str, Dict], nn.ModuleDict], + module_kwargs: Optional[Dict[str, Dict]] = None, + alias: Optional[str] = None, + init_cfg: Optional[Dict] = None, + ) -> None: + super().__init__( + module_kwargs=module_kwargs, alias=alias, init_cfg=init_cfg) + assert len(candidates) >= 1, \ + f'Number of candidate op must greater than 1, ' \ + f'but got: {len(candidates)}' + + self._chosen: Optional[str] = None + if isinstance(candidates, dict): + self._candidates = self._build_ops(candidates, self.module_kwargs) + elif isinstance(candidates, nn.ModuleDict): + self._candidates = candidates + else: + raise TypeError('candidata_ops should be a `dict` or ' + f'`nn.ModuleDict` instance, but got ' + f'{type(candidates)}') + + assert len(self._candidates) >= 1, \ + f'Number of candidate op must greater than or equal to 1, ' \ + f'but got {len(self._candidates)}' + + @staticmethod + def _build_ops( + candidates: Union[Dict[str, Dict], nn.ModuleDict], + module_kwargs: Optional[Dict[str, Dict]] = None) -> nn.ModuleDict: + """Build candidate operations based on choice configures. + + Args: + candidates (dict[str, dict] | :obj:`nn.ModuleDict`): the configs + for the candidate operations or nn.ModuleDict. + module_kwargs (dict[str, dict], optional): Module initialization + named arguments. + + Returns: + ModuleDict (dict[str, Any], optional): the key of ``ops`` is + the name of each choice in configs and the value of ``ops`` + is the corresponding candidate operation. + """ + if isinstance(candidates, nn.ModuleDict): + return candidates + + ops = nn.ModuleDict() + for name, op_cfg in candidates.items(): + assert name not in ops + if module_kwargs is not None: + op_cfg.update(module_kwargs) + ops[name] = MODELS.build(op_cfg) + return ops + + def forward_fixed(self, x: Any) -> Tensor: + """Forward with the `fixed` mutable. + + Args: + x (Any): x could be a Torch.tensor or a tuple of + Torch.tensor, containing input data for forward computation. + + Returns: + Tensor: the result of forward the fixed operation. + """ + return self._candidates[self._chosen](x) + + def forward_choice(self, x, choice: str) -> Tensor: + """Forward with the `unfixed` mutable and current choice is not None. + + Args: + x (Any): x could be a Torch.tensor or a tuple of + Torch.tensor, containing input data for forward computation. + choice (str): the chosen key in ``OneShotMutableOP``. + + Returns: + Tensor: the result of forward the ``choice`` operation. + """ + assert isinstance(choice, str) and choice in self.choices + return self._candidates[choice](x) + + def forward_all(self, x) -> Tensor: + """Forward all choices. Used to calculate FLOPs. + + Args: + x (Any): x could be a Torch.tensor or a tuple of + Torch.tensor, containing input data for forward computation. + + Returns: + Tensor: the result of forward all of the ``choice`` operation. + """ + outputs = list() + for op in self._candidates.values(): + outputs.append(op(x)) + return sum(outputs) + + def fix_chosen(self, chosen: str) -> None: + """Fix mutable with subnet config. This operation would convert + `unfixed` mode to `fixed` mode. The :attr:`is_fixed` will be set to + True and only the selected operations can be retained. + + Args: + chosen (str): the chosen key in ``MUTABLE``. Defaults to None. + """ + if self.is_fixed: + raise AttributeError( + 'The mode of current MUTABLE is `fixed`. ' + 'Please do not call `fix_chosen` function again.') + + for c in self.choices: + if c != chosen: + self._candidates.pop(c) + + self._chosen = chosen + self.is_fixed = True + + def dump_chosen(self) -> DumpChosen: + chosen = self.export_chosen() + meta = dict(all_choices=self.choices) + return DumpChosen(chosen=chosen, meta=meta) + + def export_chosen(self) -> str: + assert self.current_choice is not None + return self.current_choice + + def sample_choice(self) -> str: + """uniform sampling.""" + return np.random.choice(self.choices, 1)[0] + + @property + def choices(self) -> List[str]: + """list: all choices. """ + return list(self._candidates.keys()) + + +@MODELS.register_module() +class OneShotProbMutableOP(OneShotMutableOP): + """Sampling candidate operation according to probability. + + Args: + candidates (dict[str, dict]): the configs for the candidate + operations. + choice_probs (list): the probability of sampling each + candidate operation. + module_kwargs (dict[str, dict], optional): Module initialization named + arguments. Defaults to None. + alias (str, optional): alias of the `MUTABLE`. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 5 initializer including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. + """ + + def __init__(self, + candidates: Dict[str, Dict], + choice_probs: list = None, + module_kwargs: Optional[Dict[str, Dict]] = None, + alias: Optional[str] = None, + init_cfg: Optional[Dict] = None) -> None: + super().__init__( + candidates=candidates, + module_kwargs=module_kwargs, + alias=alias, + init_cfg=init_cfg) + assert choice_probs is not None + assert sum(choice_probs) - 1 < np.finfo(np.float64).eps, \ + f'Please make sure the sum of the {choice_probs} is 1.' + self.choice_probs = choice_probs + + def sample_choice(self) -> str: + """Sampling with probabilities.""" + assert len(self.choice_probs) == len(self._candidates.keys()) + choice = random.choices( + self.choices, weights=self.choice_probs, k=1)[0] + return choice diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/__init__.py new file mode 100755 index 000000000..f83c93fe9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .mutable_value import MutableValue, OneShotMutableValue + +__all__ = ['MutableValue', 'OneShotMutableValue'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/mutable_value.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/mutable_value.py new file mode 100755 index 000000000..146e886d0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/mutable_value.py @@ -0,0 +1,246 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import random +from typing import Any, Dict, List, Optional, Tuple, Union + +from mmrazor.registry import MODELS +from mmrazor.utils.typing import DumpChosen +from ..base_mutable import BaseMutable +from ..derived_mutable import DerivedMethodMixin, DerivedMutable + +Value = Union[int, float] + + +@MODELS.register_module() +class MutableValue(BaseMutable, DerivedMethodMixin): + """Base class for mutable value. + + A mutable value is actually a mutable that adds some functionality to a + list containing objects of the same type. + + Args: + value_list (list): List of value, each value must have the same type. + default_value (any, optional): Default value, must be one in + `value_list`. Default to None. + alias (str, optional): alias of the `MUTABLE`. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 5 initializer including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. + """ + + def __init__(self, + value_list: List[Value], + default_value: Optional[Any] = None, + alias: Optional[str] = None, + init_cfg: Optional[Dict] = None) -> None: + super().__init__(alias, init_cfg) + + self._check_is_same_type(value_list) + self._value_list = value_list + + if default_value is None: + default_value = value_list[0] + self.current_choice = default_value + + @staticmethod + def _check_is_same_type(value_list: List[Any]) -> None: + """Check whether value in `value_list` has the same type.""" + if len(value_list) == 1: + return + + for i in range(1, len(value_list)): + is_same_type = type(value_list[i - 1]) is \ + type(value_list[i]) # noqa: E721 + if not is_same_type: + raise TypeError( + 'All elements in `value_list` must have same ' + f'type, but both types {type(value_list[i-1])} ' + f'and type {type(value_list[i])} exist.') + + @property + def mutable_prefix(self) -> str: + """Mutable prefix.""" + return 'value' + + @property + def choices(self) -> List[Any]: + """List of choices.""" + return self._value_list + + def fix_chosen(self, chosen: Value) -> None: + """Fix mutable value with subnet config. + + Args: + chosen (dict): the information of chosen. + """ + if self.is_fixed: + raise RuntimeError('MutableValue can not be fixed twice') + + assert chosen in self.choices + + self.current_choice = chosen + self.is_fixed = True + + def dump_chosen(self) -> DumpChosen: + """Dump information of chosen. + + Returns: + Dict[str, Any]: Dumped information. + """ + chosen = self.export_chosen() + meta = dict(all_choices=self.choices) + return DumpChosen(chosen=chosen, meta=meta) + + def export_chosen(self): + return self.current_choice + + @property + def num_choices(self) -> int: + """Number of all choices. + + Returns: + int: Number of choices. + """ + return len(self.choices) + + @property + def current_choice(self) -> Value: + """Current choice of mutable value.""" + return self._current_choice + + @current_choice.setter + def current_choice(self, choice: Any) -> Any: + """Setter of current choice.""" + if choice not in self.choices: + raise ValueError(f'Expected choice in: {self.choices}, ' + f'but got: {choice}') + + self._current_choice = choice + + def __rmul__(self, other) -> DerivedMutable: + """Please refer to method :func:`__mul__`.""" + return self * other + + def __mul__(self, other: Union[int, float]) -> DerivedMutable: + """Overload `*` operator. + + Args: + other (int): Expand ratio. + + Returns: + DerivedMutable: Derived expand mutable. + """ + if isinstance(other, int): + return self.derive_expand_mutable(other) + elif isinstance(other, float): + return self.derive_expand_mutable(other) + raise TypeError(f'Unsupported type {type(other)} for mul!') + + def __floordiv__(self, other: Union[int, Tuple[int, + int]]) -> DerivedMutable: + """Overload `//` operator. + + Args: + other: (int, tuple): divide ratio for int or + (divide ratio, divisor) for tuple. + + Returns: + DerivedMutable: Derived divide mutable. + """ + if isinstance(other, int): + return self.derive_divide_mutable(other) + elif isinstance(other, float): + return self.derive_divide_mutable(int(other)) + if isinstance(other, tuple): + assert len(other) == 2 + return self.derive_divide_mutable(*other) + + raise TypeError(f'Unsupported type {type(other)} for div!') + + def __repr__(self) -> str: + s = self.__class__.__name__ + s += f'(value_list={self._value_list}, ' + s += f'current_choice={self.current_choice})' + + return s + + +# TODO +# 1. use comparable for type hint +# 2. use mixin +@MODELS.register_module() +class OneShotMutableValue(MutableValue): + """Class for one-shot mutable value. + + one-shot mutable value provides `sample_choice` method and `min_choice`, + `max_choice` properties on the top of mutable value. + + Args: + value_list (list): List of value, each value must have the same type. + default_value (any, optional): Default value, must be one in + `value_list`. Default to None. + alias (str, optional): alias of the `MUTABLE`. + init_cfg (dict, optional): initialization configuration dict for + ``BaseModule``. OpenMMLab has implement 5 initializer including + `Constant`, `Xavier`, `Normal`, `Uniform`, `Kaiming`, + and `Pretrained`. + """ + + def __init__(self, + value_list: List[Any], + default_value: Optional[Any] = None, + alias: Optional[str] = None, + init_cfg: Optional[Dict] = None) -> None: + value_list = sorted(value_list) + # set default value as max value + if default_value is None: + default_value = value_list[-1] + + super().__init__( + value_list=value_list, + default_value=default_value, + alias=alias, + init_cfg=init_cfg) + + def sample_choice(self) -> Any: + """Random sampling from choices. + + Returns: + Any: Selected choice. + """ + return random.choice(self.choices) + + @property + def max_choice(self) -> Any: + """Max choice of all choices. + + Returns: + Any: Max choice. + """ + return self.choices[-1] + + @property + def min_choice(self) -> Any: + """Min choice of all choices. + + Returns: + Any: Min choice. + """ + return self.choices[0] + + def __mul__(self, other) -> DerivedMutable: + """Overload `*` operator. + + Args: + other (int, SquentialMutableChannel): Expand ratio or + SquentialMutableChannel. + + Returns: + DerivedMutable: Derived expand mutable. + """ + from ..mutable_channel import SquentialMutableChannel + + if isinstance(other, SquentialMutableChannel): + return other * self + + return super().__mul__(other) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/__init__.py new file mode 100755 index 000000000..179b4455d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/__init__.py @@ -0,0 +1,10 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .channel_mutator import (ChannelMutator, DCFFChannelMutator, + DMCPChannelMutator, OneShotChannelMutator, + SlimmableChannelMutator) +from .nas_mutator import NasMutator + +__all__ = [ + 'ChannelMutator', 'DCFFChannelMutator', 'DMCPChannelMutator', + 'SlimmableChannelMutator', 'NasMutator', 'OneShotChannelMutator' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/base_mutator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/base_mutator.py new file mode 100755 index 000000000..994ba5e6d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/base_mutator.py @@ -0,0 +1,53 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import ABC, abstractmethod +from typing import Dict, Generic, Optional, TypeVar + +from mmengine.model import BaseModule +from torch.nn import Module + +from ..mutables.base_mutable import BaseMutable + +MUTABLE_TYPE = TypeVar('MUTABLE_TYPE', bound=BaseMutable) + + +class BaseMutator(ABC, BaseModule, Generic[MUTABLE_TYPE]): + """The base class for mutator. + + Mutator is mainly used for subnet management, it usually provides functions + such as sampling and setting of subnets. + + All subclasses should implement the following APIs: + + - ``prepare_from_supernet()`` + - ``search_space`` + + Args: + init_cfg (dict, optional): The config to control the initialization. + """ + + def __init__(self, init_cfg: Optional[Dict] = None) -> None: + super().__init__(init_cfg=init_cfg) + + @abstractmethod + def prepare_from_supernet(self, supernet: Module) -> None: + """Do some necessary preparations with supernet. + + Args: + supernet (:obj:`torch.nn.Module`): The supernet to be searched + in your algorithm. + """ + + @property + @abstractmethod + def search_groups(self) -> Dict: + """Search group of the supernet. + + Note: + Search group is different from search space. The key of search + group is called ``group_id``, and the value is corresponding + searchable modules. The searchable modules will have the same + search space if they are in the same group. + + Returns: + dict: Search group. + """ diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/__init__.py new file mode 100755 index 000000000..6bc1a953f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/__init__.py @@ -0,0 +1,11 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .channel_mutator import ChannelMutator +from .dcff_channel_mutator import DCFFChannelMutator +from .dmcp_channel_mutator import DMCPChannelMutator +from .one_shot_channel_mutator import OneShotChannelMutator +from .slimmable_channel_mutator import SlimmableChannelMutator + +__all__ = [ + 'SlimmableChannelMutator', 'ChannelMutator', 'OneShotChannelMutator', + 'DCFFChannelMutator', 'DMCPChannelMutator' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.ipynb b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.ipynb new file mode 100755 index 000000000..58b56c783 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.ipynb @@ -0,0 +1,375 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ChannelMutator\n", + "A channel mutator is a manager of the channel structure of a model. In other words, it manages all MutableChannelUnits of a model. \n", + "ChannelMutator is the simplest channel mutator. All other channel mutators should inherit from ChannelMutator class. We take ChannelMutator as an example." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## How to Construct a ChannelMutator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Suppose we have a model archtecture defineed below" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/liukai/miniconda3/envs/lab2max/lib/python3.9/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "# define a model\n", + "from mmengine.model import BaseModel\n", + "from torch import nn\n", + "import torch\n", + "from collections import OrderedDict\n", + "\n", + "class MyModel(nn.Module):\n", + "\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.net = nn.Sequential(\n", + " OrderedDict([('conv0', nn.Conv2d(3, 8, 3, 1, 1)),\n", + " ('relu', nn.ReLU()),\n", + " ('conv1', nn.Conv2d(8, 16, 3, 1, 1))]))\n", + " self.pool = nn.AdaptiveAvgPool2d(1)\n", + " self.head = nn.Linear(16, 1000)\n", + "\n", + " def forward(self, x):\n", + " feature = self.net(x)\n", + " pool = self.pool(feature).flatten(1)\n", + " return self.head(pool)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are two steps to fully constructing a ChannelMutator object as below. \n", + "1. we need to initialize a ChannelMutator object.\n", + "2. Then we need to init the ChannelMutator object with a model." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "11/14 14:24:13 - mmengine - \u001b[5m\u001b[4m\u001b[33mWARNING\u001b[0m - add a input before net.conv0(net.conv0), error: net.conv0(net.conv0)\n", + "11/14 14:24:13 - mmengine - \u001b[5m\u001b[4m\u001b[33mWARNING\u001b[0m - add a output after head(head), error: head(head)\n", + "The mutator has 2 mutable channel units.\n" + ] + } + ], + "source": [ + "from mmrazor.models.mutators import ChannelMutator\n", + "\n", + "model = MyModel()\n", + "# initialize a ChannelMutator object\n", + "mutator = ChannelMutator(\n", + " channel_unit_cfg=dict(\n", + " type='SequentialMutableChannelUnit',\n", + " default_args=dict(choice_mode='ratio'),\n", + " units={},\n", + " ),\n", + " parse_cfg=dict(\n", + " type='ChannelAnalyzer'))\n", + "# init the ChannelMutator object with a model\n", + "mutator.prepare_from_supernet(model)\n", + "print(f'The mutator has {len(mutator.mutable_units)} mutable channel units.')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "ChannelMutator has two arguments:\n", + "1. channel_unit_cfg: config of the MutableChannelUnit to use in the ChannelMutator.\n", + "2. parse_cfg: the way to parse the model and get MutableChannelUnits." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are there ways to parse model and get MutableChannelUnits.\n", + "1. Use a tracer to get MutableChannelUnits automatically.\n", + "2. Use config dicts to indicate MutableChannelUnits.\n", + "3. Predefine MutableChannels in the model archtecture.\n", + " \n", + "The example of method 1 has been post above. We post the examples of method 2 and method 3 below." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The mutator has 2 mutable channel units.\n" + ] + } + ], + "source": [ + "# 2. use config dicts to indicate MutableChannelUnits.\n", + "from mmrazor.models.mutators import ChannelMutator\n", + "\n", + "model = MyModel()\n", + "# initialize a ChannelMutator object\n", + "mutator = ChannelMutator(\n", + " channel_unit_cfg=dict(\n", + " type='SequentialMutableChannelUnit',\n", + " default_args=dict(choice_mode='ratio'),\n", + " units={\n", + " 'net.conv0_(0, 8)_8': {\n", + " 'init_args': {\n", + " 'num_channels': 8,\n", + " },\n", + " 'channels': {\n", + " 'input_related': [{\n", + " 'name': 'net.conv1',\n", + " }],\n", + " 'output_related': [{\n", + " 'name': 'net.conv0',\n", + " }]\n", + " },\n", + " 'choice': 1.0\n", + " },\n", + " 'net.conv1_(0, 16)_16': {\n", + " 'init_args': {\n", + " 'num_channels': 16,\n", + " },\n", + " 'channels': {\n", + " 'input_related': [{\n", + " 'name': 'head',\n", + " }],\n", + " 'output_related': [{\n", + " 'name': 'net.conv1',\n", + " }]\n", + " },\n", + " 'choice': 1.0\n", + " }\n", + " }),\n", + " parse_cfg=dict(type='Config'))\n", + "# init the ChannelMutator object with a model\n", + "mutator.prepare_from_supernet(model)\n", + "print(f'The mutator has {len(mutator.mutable_units)} mutable channel units.')" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The mutator has 2 mutable channel units.\n" + ] + } + ], + "source": [ + "# 3. Predefine MutableChannels in the model archtecture.\n", + "\n", + "from mmrazor.models.architectures.dynamic_ops import DynamicConv2d, DynamicLinear\n", + "from mmrazor.models.mutables import MutableChannelUnit, MutableChannelContainer, SquentialMutableChannel\n", + "from collections import OrderedDict\n", + "\n", + "class MyDynamicModel(BaseModel):\n", + "\n", + " def __init__(self):\n", + " super().__init__(None, None)\n", + " self.net = nn.Sequential(\n", + " OrderedDict([('conv0', DynamicConv2d(3, 8, 3, 1, 1)),\n", + " ('relu', nn.ReLU()),\n", + " ('conv1', DynamicConv2d(8, 16, 3, 1, 1))]))\n", + " self.pool = nn.AdaptiveAvgPool2d(1)\n", + " self.head = DynamicLinear(16, 1000)\n", + "\n", + " # register MutableChannelContainer\n", + " MutableChannelUnit._register_channel_container(\n", + " self, MutableChannelContainer)\n", + " self._register_mutables()\n", + "\n", + " def forward(self, x):\n", + " feature = self.net(x)\n", + " pool = self.pool(feature).flatten(1)\n", + " return self.head(pool)\n", + "\n", + " def _register_mutables(self):\n", + " mutable1 = SquentialMutableChannel(8)\n", + " mutable2 = SquentialMutableChannel(16)\n", + " MutableChannelContainer.register_mutable_channel_to_module(\n", + " self.net.conv0, mutable1, is_to_output_channel=True)\n", + " MutableChannelContainer.register_mutable_channel_to_module(\n", + " self.net.conv1, mutable1, is_to_output_channel=False)\n", + "\n", + " MutableChannelContainer.register_mutable_channel_to_module(\n", + " self.net.conv1, mutable2, is_to_output_channel=True)\n", + " MutableChannelContainer.register_mutable_channel_to_module(\n", + " self.head, mutable2, is_to_output_channel=False)\n", + "\n", + "\n", + "model = MyDynamicModel()\n", + "# initialize a ChannelMutator object\n", + "mutator = ChannelMutator(\n", + " channel_unit_cfg=dict(\n", + " type='SequentialMutableChannelUnit',\n", + " default_args=dict(choice_mode='ratio'),\n", + " units={},\n", + " ),\n", + " parse_cfg=dict(type='Predefined'))\n", + "# init the ChannelMutator object with a model\n", + "mutator.prepare_from_supernet(model)\n", + "print(f'The mutator has {len(mutator.mutable_units)} mutable channel units.')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## How to Change the Structure of a Model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The structure of a model is represented by a dict where the key is the name of a MutableChannelUnit and the value is a structure choice." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{0: 8, 1: 16}\n" + ] + } + ], + "source": [ + "print(mutator.current_choices)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can change the dict to prune the model." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MyDynamicModel(\n", + " (data_preprocessor): BaseDataPreprocessor()\n", + " (net): Sequential(\n", + " (conv0): DynamicConv2d(\n", + " 3, 8, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)\n", + " (mutable_attrs): ModuleDict(\n", + " (in_channels): MutableChannelContainer(num_channels=3, activated_channels=3)\n", + " (out_channels): MutableChannelContainer(num_channels=8, activated_channels=4)\n", + " )\n", + " )\n", + " (relu): ReLU()\n", + " (conv1): DynamicConv2d(\n", + " 8, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)\n", + " (mutable_attrs): ModuleDict(\n", + " (in_channels): MutableChannelContainer(num_channels=8, activated_channels=4)\n", + " (out_channels): MutableChannelContainer(num_channels=16, activated_channels=8)\n", + " )\n", + " )\n", + " )\n", + " (pool): AdaptiveAvgPool2d(output_size=1)\n", + " (head): DynamicLinear(\n", + " in_features=16, out_features=1000, bias=True\n", + " (mutable_attrs): ModuleDict(\n", + " (in_features): MutableChannelContainer(num_channels=16, activated_channels=8)\n", + " (out_features): MutableChannelContainer(num_channels=1000, activated_channels=1000)\n", + " )\n", + " )\n", + ")\n" + ] + } + ], + "source": [ + "mutator.set_choices(\n", + " {0: 4, 1: 8}\n", + ")\n", + "print(model)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Please refer to our documents for more choices related methods." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.9.13 ('lab2max')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "e31a827d0913016ad78e01c7b97f787f4b9e53102dd62d238e8548bcd97ff875" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.py new file mode 100755 index 000000000..910992e1e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.py @@ -0,0 +1,374 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Any, Dict, Generic, List, Optional, Tuple, Type, Union + +from mmengine import fileio +from torch.nn import Module, ModuleList + +from mmrazor.models.mutables import (ChannelUnitType, MutableChannelUnit, + SequentialMutableChannelUnit) +from mmrazor.models.mutables.mutable_channel.units.channel_unit import \ + ChannelUnit +from mmrazor.models.task_modules.tracer.channel_analyzer import ChannelAnalyzer +from mmrazor.registry import MODELS, TASK_UTILS +from ..base_mutator import BaseMutator + + +@MODELS.register_module() +class ChannelMutator(BaseMutator, Generic[ChannelUnitType]): + """ChannelMutator manages the pruning structure of a model. + + Args: + channel_unit_cfg (Union[ dict, Type[MutableChannelUnit]], optional): + The config of ChannelUnits. When the channel_unit_cfg + is a dict, it should follow the template below: + channel_unit_cfg = dict( + # type of used MutableChannelUnit + type ='XxxMutableChannelUnit', + # default args for MutableChannelUnit + default_args={}, + units = { + # config of a unit + "xxx_unit_name": {}, + ... + } + ), + The config template of 'units' can be got using + MutableChannelUnit.config_template() + Defaults to SequentialMutableChannelUnit. + + parse_cfg (Dict, optional): + The config to parse the model. + Defaults to + dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer') + + init_cfg (dict, optional): initialization configuration dict for + BaseModule. + + Note: + There are three ways used in ChannelMutator to parse a model and + get MutableChannelUnits. + 1. Using tracer. It needs parse_cfg to be the config of the + ChannelAnalyzer. + 2. Using config. When parse_cfg['type']='Config'. It needs that + channel_unit_cfg['unit']['xxx_unit_name] has a key 'channels', + otherwise tracer is required. + 3. Using the model with pre-defined dynamic-ops and mutablechannels: + When parse_cfg['type']='Predefined'. + """ + + # init + + def __init__(self, + channel_unit_cfg: Union[ + dict, + Type[MutableChannelUnit]] = SequentialMutableChannelUnit, + parse_cfg: Dict = dict( + _scope_='mmrazor', + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer'), + init_cfg: Optional[Dict] = None) -> None: + + super().__init__(init_cfg) + + # tracer + if isinstance(parse_cfg, dict): + assert parse_cfg['type'] in [ + 'ChannelAnalyzer', 'Config', 'Predefined' + ] + self.parse_cfg = parse_cfg + + # units + self._name2unit: Dict[str, ChannelUnitType] = {} + self.units: ModuleList[ChannelUnitType] = ModuleList() + + # unit config + self.channel_unit_cfg = channel_unit_cfg + self.unit_class, self.unit_default_args, self.units_cfg = \ + self._parse_channel_unit_cfg( + channel_unit_cfg) + + def prepare_from_supernet(self, supernet: Module) -> None: + """Prepare from a model for pruning. + + It includes two steps: + 1. parse the model and get MutableChannelUnits. + 2. call unit.prepare_for_pruning for each unit. + """ + from mmrazor.models.utils import get_module_device + device = get_module_device(supernet) + + self._name2module = dict(supernet.named_modules()) + + if isinstance(self.parse_cfg, + ChannelAnalyzer) or 'Analyzer' in self.parse_cfg['type']: + if isinstance(self.parse_cfg, + dict) and 'from_cfg' in self.parse_cfg: + units = self._prepare_from_cfg(supernet, self.units_cfg) + else: + units = self._prepare_from_tracer(supernet, self.parse_cfg) + elif self.parse_cfg['type'] == 'Config' \ + or 'from_cfg' in self.parse_cfg: + units = self._prepare_from_cfg(supernet, self.units_cfg) + elif self.parse_cfg['type'] == 'Predefined': + units = self._prepare_from_predefined_model(supernet) + else: + raise NotImplementedError() + for i in range(len(units)): + units[i] = units[i].to(device) + units[i].prepare_for_pruning(supernet) + self._name2unit[units[i].name] = units[i] + + self.units = ModuleList(units) + + @property + def mutable_units(self) -> List[ChannelUnitType]: + """Prunable units.""" + return [unit for unit in self.units if unit.is_mutable] + + def config_template(self, + only_mutable_units=False, + with_unit_init_args=False, + with_channels=False): + """Config template of the mutator. + + Args: + only_mutable_units (bool, optional): Whether only return config of + prunable units. It can omit unmutable MutableChannelUnits + to decrease the length of the config. Defaults to False. + with_unit_init_args (bool, optional): Whether return init_args of + units. Let it be true, when you want to change the init + args of units. Defaults to False. + with_channels (bool, optional): Whether return channel info. + The channel info can initialization the units without + tracer. When you want to prune your model without a + tracer next time, let it be true. Defaults to False. + Example: + dict( + channel_unit_cfg = dict( + # type of used MutableChannelUnit + type ='XxxMutableChannelUnit', + # default args for MutableChananelUnit + default_args={}, + # config of units + units = { + # config of a unit + "xxx_unit_name": { + 'init_args':{}, # if with_unit_init_args + 'channels':{} # if with_channels + }, + ... + } + ), + # config of tracer + parse_cfg={} + ) + + + About the detail of the config of each unit, please refer to + MutableChannelUnit.config_template() + """ + # template of units + units = self.mutable_units if only_mutable_units else self.units + units_template = {} + for unit in units: + units_template[unit.name] = unit.config_template( + with_init_args=with_unit_init_args, + with_channels=with_channels) + + # template of mutator + template = dict( + type=str(self.__class__.__name__), + channel_unit_cfg=dict( + type=str(self.unit_class.__name__), + default_args=self.unit_default_args, + units=units_template), + parse_cfg=self.parse_cfg) + + return template + + def fix_channel_mutables(self): + """Fix ChannelMutables.""" + for unit in self.units: + unit.fix_chosen() + + # choice manage + + def sample_choices(self, kind: str = 'random') -> Dict[str, Any]: + """Sampling by search groups. + + The sampling result of the first mutable of each group is the sampling + result of this group. + + Returns: + Dict[int, Any]: Random choices dict. + """ + assert kind == 'random', f'unsupported the {kind} sample method.' + template = self.choice_template + for key in template: + template[key] = self._name2unit[key].sample_choice() + return template + + def set_choices(self, choices: Dict[str, Any]) -> None: + """Set mutables' current choice according to choices sample by + :func:`sample_choices`. + + Args: + choices (Dict[int, Any]): Choices dict. The key is group_id in + search groups, and the value is the sampling results + corresponding to this group. + """ + for name, choice in choices.items(): + unit = self._name2unit[name] + unit.current_choice = choice + + @property + def current_choices(self) -> Dict: + """Get current choices.""" + config = self.choice_template + for unit in self.mutable_units: + config[unit.name] = unit.current_choice + return config + + @property + def choice_template(self) -> Dict: + """Get the chocie template of the Mutator. + + Example: + { + 'xxx_unit_name': xx_choice_value, + ... + } + """ + template = {} + for unit in self.mutable_units: + template[unit.name] = unit.current_choice + return template + + @property + def search_groups(self) -> Dict[int, List]: + """Search group of the supernet. + + Note: + Search group is different from search space. The key of search + group is called ``group_id``, and the value is corresponding + searchable modules. The searchable modules will have the same + search space if they are in the same group. + + Returns: + dict: Search group. + """ + return self._search_groups + + # private methods + + def _convert_channel_unit_to_mutable(self, units: List[ChannelUnit]): + """Convert ChannelUnits to MutableChannelUnits.""" + mutable_units = [] + for unit in units: + args = copy.copy(self.unit_default_args) + if unit.name in self.units_cfg and \ + 'init_args' in self.units_cfg[unit.name]: + args = self.units_cfg[unit.name]['init_args'] + mutable_unit = self.unit_class.init_from_channel_unit(unit, args) + mutable_units.append(mutable_unit) + return mutable_units + + def _parse_channel_unit_cfg( + self, + channel_unit_cfg) -> Tuple[Type[ChannelUnitType], Dict, Dict]: + """Parse channel_unit_cfg.""" + if isinstance(channel_unit_cfg, dict): + unit_class = MODELS.module_dict[channel_unit_cfg['type']] + + default_unit_args = channel_unit_cfg[ + 'default_args'] if 'default_args' in channel_unit_cfg else {} + + unit_init_cfg = channel_unit_cfg[ + 'units'] if 'units' in channel_unit_cfg else {} + if isinstance(unit_init_cfg, str): + # load config file + unit_init_cfg = fileio.load(unit_init_cfg) + elif issubclass(channel_unit_cfg, MutableChannelUnit): + unit_class = channel_unit_cfg + default_unit_args = {} + unit_init_cfg = {} + else: + raise NotImplementedError() + return unit_class, default_unit_args, unit_init_cfg + + def _prepare_from_tracer(self, model: Module, parse_cfg: Dict): + """Initialize units using a tracer.""" + + if isinstance(parse_cfg, Dict): + tracer: ChannelAnalyzer = TASK_UTILS.build(parse_cfg) + else: + tracer = parse_cfg + unit_configs = tracer.analyze(model) + + # get ChannelUnits + units = [ + ChannelUnit.init_from_cfg(model, cfg) + for cfg in unit_configs.values() + ] + # convert to MutableChannelUnits + units = self._convert_channel_unit_to_mutable(units) + return units + + def _prepare_from_cfg(self, model, config: Dict): + """Initialize units using config dict.""" + assert isinstance(self.channel_unit_cfg, dict) + assert 'units' in self.channel_unit_cfg + config = self.channel_unit_cfg['units'] + if isinstance(config, str): + config = fileio.load(config) + assert isinstance(config, dict) + + if 'Analyzer' in self.parse_cfg['type']: + self.parse_cfg.pop('from_cfg') + tracer = TASK_UTILS.build(self.parse_cfg) + unit_configs = tracer.analyze(model) + + units = [] + for unit_key in config: + init_args = copy.deepcopy(self.unit_default_args) + if 'init_args' in config[unit_key]: + init_args.update(config[unit_key]['init_args']) + config[unit_key]['init_args'] = init_args + if 'channels' in config[unit_key]: + unit = self.unit_class.init_from_cfg(model, config[unit_key]) + unit.name = unit_key + else: + try: + unit = self._prepare_unit_from_init_cfg( + model, config[unit_key], unit_configs[unit_key]) + except ValueError: + raise ValueError( + 'Initializing channel_mutator from the config needs' + 'to include `channels` or `Analyzer` in the config.') + units.append(unit) + return units + + def _prepare_unit_from_init_cfg(self, model: Module, channel_cfg: dict, + init_cfg: dict): + """Initialize units using the init_cfg, which created by tracer.""" + unit = ChannelUnit.init_from_cfg(model, init_cfg) + unit = self._convert_channel_unit_to_mutable([unit])[0] + if 'choice' in channel_cfg: + unit.current_choice = channel_cfg['choice'] + return unit + + def _prepare_from_predefined_model(self, model: Module): + """Initialize units using the model with pre-defined dynamicops and + mutable-channels.""" + + units = self.unit_class.init_from_predefined_model(model) + + for unit in units: + unit.unit_predefined = self.unit_default_args.pop( + 'unit_predefined', False) + return units diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dcff_channel_mutator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dcff_channel_mutator.py new file mode 100755 index 000000000..5994eade4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dcff_channel_mutator.py @@ -0,0 +1,47 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Type, Union + +from mmrazor.models.architectures.dynamic_ops import FuseConv2d +from mmrazor.models.mutables import DCFFChannelUnit +from mmrazor.registry import MODELS +from .channel_mutator import ChannelMutator, ChannelUnitType + + +@MODELS.register_module() +class DCFFChannelMutator(ChannelMutator[DCFFChannelUnit]): + """DCFF channel mutable based channel mutator. It uses DCFFChannelUnit. + + Args: + channel_unit_cfg (Union[dict, Type[ChannelUnitType]], optional): + Config of MutableChannelUnits. Defaults to + dict( type='DCFFChannelUnit', units={}). + parse_cfg (Dict): The config of the tracer to parse the model. + Defaults to dict( type='BackwardTracer', + loss_calculator=dict(type='ImageClassifierPseudoLoss')). + Change loss_calculator according to task and backbone. + """ + + def __init__(self, + channel_unit_cfg: Union[dict, Type[ChannelUnitType]] = dict( + type='DCFFChannelUnit', units={}), + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer'), + **kwargs) -> None: + super().__init__(channel_unit_cfg, parse_cfg, **kwargs) + + def calc_information(self, tau: float): + """Calculate channel's kl and apply softmax pooling on channel to solve + CUDA out of memory problem. KL calculation & pool are conducted in ops. + + Args: + tau (float): temporature calculated by iter or epoch + """ + # Calculate the filter importance of the current epoch. + for layerid, unit in enumerate(self.units): + for channel in unit.output_related: + if isinstance(channel.module, FuseConv2d): + layeri_softmaxp = channel.module.get_pooled_channel(tau) + # update fuseconv op's selected layeri_softmax + channel.module.set_forward_args(choice=layeri_softmaxp) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dmcp_channel_mutator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dmcp_channel_mutator.py new file mode 100755 index 000000000..de7bbc405 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dmcp_channel_mutator.py @@ -0,0 +1,178 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import random +from typing import Any, Dict, Optional, Tuple, Type, Union + +import torch +import torch.nn as nn +from torch.nn import Module + +from mmrazor.models.mutables import DMCPChannelUnit +from mmrazor.registry import MODELS +from ...architectures import DMCPBatchNorm2d +from .channel_mutator import ChannelMutator, ChannelUnitType + + +@MODELS.register_module() +class DMCPChannelMutator(ChannelMutator[DMCPChannelUnit]): + """DMCP channel mutable based channel mutator. It uses DMCPPChannelUnit. + + Args: + channel_unit_cfg (Union[dict, Type[ChannelUnitType]], optional): + Config of MutableChannelUnits. Defaults to + dict( type='DMCPPChannelUnit', units={}). + parse_cfg (Dict): The config of the tracer to parse the model. + Defaults to dict( type='BackwardTracer', + loss_calculator=dict(type='ImageClassifierPseudoLoss')). + Change loss_calculator according to task and backbone. + pruning_cfg (Tuple): (min_sample_rate, max_sample_rate, sample_offset) + """ + + def __init__(self, + channel_unit_cfg: Union[dict, Type[ChannelUnitType]] = dict( + type='DMCPChannelUnit', units={}), + parse_cfg: Dict = dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer'), + pruning_cfg=(0.1, 1, 0.05), + **kwargs) -> None: + super().__init__(channel_unit_cfg, parse_cfg, **kwargs) + self.pruning_cfg = pruning_cfg + + def prepare_from_supernet(self, supernet: Module) -> None: + """Prepare from a model for pruning. + + It includes two steps: + 1. parse the model and get MutableChannelUnits. + 2. call unit.prepare_for_pruning for each unit. + """ + super().prepare_from_supernet(supernet) + self.prepare_arch_params(supernet) + + def _build_arch_param(self, num_choices) -> nn.Parameter: + """Build learnable architecture parameters.""" + return nn.Parameter(torch.zeros(num_choices)) + + def prepare_arch_params(self, supernet: Module) -> None: + """Prepare the arch parameters and associate them with the + corresponding op.""" + self.arch_params = nn.ParameterDict() + self._op_arch_align = dict() + self._arch_params_attr = dict() + for group_id, module in enumerate(self.units): + arch_message = self._generate_arch_message( + module.mutable_channel.num_channels) + self._arch_params_attr[str(group_id)] = arch_message + group_arch_param = self._build_arch_param(arch_message[1]) + self.arch_params[str(group_id)] = group_arch_param + + for unit in module.output_related: + self._op_arch_align[str(unit.name)] = str(group_id) + + self._bn_arch_align = dict() + for name, module in supernet.named_modules(): + if isinstance(module, DMCPBatchNorm2d): + self._bn_arch_align[module] = self._op_arch_align[str(name)] + + def _generate_arch_message(self, out_channels: int) -> tuple: + """ + Define the search space of the channel according to the pruning + rate range, where the search space consists of two parts + 1. sampled by pruning rate (that is, maximum, minimum and random + pruning rate) + 2. sampled by probability + Inputs: + out_channels (int): channel num of conv layers. + Outputs: + attr (tuple): (group_size, num_groups, min_ch) + """ + (min_rate, max_rate, rate_offset) = self.pruning_cfg + + # sampled by probability + group_size = int(rate_offset * out_channels / max_rate) + num_groups = int((max_rate - min_rate) / rate_offset + 1e-4) + min_ch = out_channels - (group_size * num_groups) + assert min_ch > 0 + assert group_size * num_groups + min_ch == out_channels + + return (group_size, num_groups, min_ch) + + def modify_supernet_forward(self, arch_train: str) -> None: + """According to the arch_train, assign the arch parameter to the + forward of the corresponding op.""" + for module, group_id in self._bn_arch_align.items(): + arch_param: Optional[nn.Parameter] = None + arch_params_attr: Optional[Tuple] = None + if arch_train: + arch_param = self.arch_params[self._bn_arch_align[module]] + arch_params_attr = self._arch_params_attr[str(group_id)] + module.set_forward_args( + arch_param=arch_param, arch_attr=arch_params_attr) + + def sample_subnet(self, mode: str, arch_train: str) -> None: + """Sampling according to the input mode.""" + choices = dict() + + for group_id, _ in enumerate(self.units): + choices[str(group_id)] = self._prune_by_arch(mode, group_id) + self.set_choices(choices) + + self.modify_supernet_forward(arch_train) + + def _prune_by_arch(self, mode: str, group_id: int) -> Union[int, Any]: + """Prune the output channels according to the specified mode. + + Inputs: + mode (list): one of ['max', 'min', 'random', 'direct', 'expected'] + group_id (int): index of units + + Outputs: + channels (int): for mode 'max'/'min'/'random'/'dirext' + channels (tensor): for mode 'expected' + """ + arch_param = self.arch_params[str(group_id)] + (group_size, num_groups, min_ch) =\ + self._arch_params_attr[str(group_id)] + + if mode == 'max': + return min_ch + group_size * num_groups + elif mode == 'min': + return min_ch + elif mode == 'random': + return min_ch + group_size * random.randint(0, num_groups) + else: + if num_groups == 0: + return min_ch + prob = torch.clamp(arch_param, min=0) + condition_prob = torch.exp(-prob) + if mode == 'direct': + direct_channel = min_ch + for i in range(num_groups): + if random.uniform(0, 1) > condition_prob[i]: + break + direct_channel += group_size + return direct_channel + elif mode == 'expected': + marginal_prob = torch.cumprod(condition_prob, dim=0) + expected_channel = (torch.sum(marginal_prob) * + group_size) + min_ch + return expected_channel + else: + raise NotImplementedError + + def set_choices(self, choices: Dict[str, Any]) -> None: + """Set mutables' current choice according to choices sample by + :func:`sample_choices`. + + Args: + choices (Dict[str, Any]): Choices dict. The key is group_id in + search groups, and the value is the sampling results + corresponding to this group. + """ + for group_id, module in enumerate(self.units): + if str(group_id) not in choices.keys(): + # allow optional target_prune_ratio + continue + choice = choices[str(group_id)] + module.current_choice = choice + module.mutable_channel.activated_tensor_channels = choice diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/group_fisher_mutator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/group_fisher_mutator.py new file mode 100755 index 000000000..cde31bacf --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/group_fisher_mutator.py @@ -0,0 +1,7 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This file includes the modules in the impl folder. + +As it only records impl modules, it is not initialized automatically. +""" +from mmrazor.implementations.pruning.group_fisher import \ + GroupFisherChannelMutator # noqa diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/one_shot_channel_mutator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/one_shot_channel_mutator.py new file mode 100755 index 000000000..cc008b0b8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/one_shot_channel_mutator.py @@ -0,0 +1,70 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict, Type, Union + +from mmrazor.models.mutables import OneShotMutableChannelUnit +from mmrazor.registry import MODELS +from .channel_mutator import ChannelMutator, ChannelUnitType + + +@MODELS.register_module() +class OneShotChannelMutator(ChannelMutator[OneShotMutableChannelUnit]): + """OneShotChannelMutator based on ChannelMutator. It use + OneShotMutableChannelUnit by default. + + Args: + channel_unit_cfg (Union[dict, Type[ChannelUnitType]], optional): + Config of MutableChannelUnits. Defaults to + dict( type='OneShotMutableChannelUnit', + default_args=dict( num_blocks=8, min_blocks=2 ) ). + """ + + def __init__(self, + channel_unit_cfg: Union[dict, Type[ChannelUnitType]] = dict( + type='OneShotMutableChannelUnit', + default_args=dict(num_blocks=8, min_blocks=2)), + **kwargs) -> None: + + super().__init__(channel_unit_cfg, **kwargs) + + @property + def max_choices(self) -> Dict: + """Get max choice for each unit in choice_template.""" + max_choices = copy.deepcopy(self.choice_template) + for key in self.choice_template: + max_choices[key] = self._name2unit[key].max_choice + return max_choices + + @property + def min_choices(self) -> Dict: + """Get min choice for each unit in choice_template.""" + min_choices = copy.deepcopy(self.choice_template) + for key in self.choice_template: + min_choices[key] = self._name2unit[key].min_choice + return min_choices + + def sample_choices(self, kind: str = 'random') -> Dict: + """Sample choice for each unit in choice_template.""" + choices = copy.deepcopy(self.choice_template) + for key in self.choice_template: + if kind == 'max': + choices[key] = self._name2unit[key].max_choice + elif kind == 'min': + choices[key] = self._name2unit[key].min_choice + elif kind == 'random': + choices[key] = self._name2unit[key].sample_choice() + else: + raise NotImplementedError() + return choices + + def set_max_choices(self): + """Set max choice for each unit in choice_template.""" + for name, choice in self.max_choices.items(): + unit = self._name2unit[name] + unit.current_choice = choice + + def set_min_choices(self): + """Set min choice for each unit in choice_template.""" + for name, choice in self.min_choices.items(): + unit = self._name2unit[name] + unit.current_choice = choice diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/slimmable_channel_mutator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/slimmable_channel_mutator.py new file mode 100755 index 000000000..c3da419bf --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/slimmable_channel_mutator.py @@ -0,0 +1,82 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Optional + +from mmrazor.models.mutables import SlimmableChannelUnit +from mmrazor.registry import MODELS +from .channel_mutator import ChannelMutator + + +@MODELS.register_module() +class SlimmableChannelMutator(ChannelMutator[SlimmableChannelUnit]): + """SlimmableChannelMutator is the default ChannelMutator for + SlimmableNetwork algorithm. + + Args: + channel_unit_cfg (Dict): The config of ChannelUnits. Defaults to + dict( type='SlimmableChannelUnit', units={}). + parse_cfg (Dict): The config of the tracer to parse the model. + Defaults to dict( type='BackwardTracer', + loss_calculator=dict(type='ImageClassifierPseudoLoss')). + init_cfg (dict, optional): initialization configuration dict for + BaseModule. + """ + + def __init__(self, + channel_unit_cfg=dict(type='SlimmableChannelUnit', units={}), + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer'), + init_cfg: Optional[Dict] = None) -> None: + + super().__init__(channel_unit_cfg, parse_cfg, init_cfg) + + self.subnets = self._prepare_subnets(self.units_cfg) + + def set_choices(self, config: Dict[str, float]): # type: ignore[override] + """Set choices.""" + for name, choice in config.items(): + unit = self._name2unit[name] + unit.current_choice = choice + + def sample_choices(self): + """Sample choices(pruning structure).""" + raise RuntimeError + + # private methods + + def _prepare_subnets(self, unit_cfg: Dict) -> List[Dict[str, int]]: + """Prepare subnet config. + + Args: + unit_cfg (Dict[str, Dict[str]]): Config of the units. + unit_cfg follows the below template: + { + 'xx_unit_name':{ + 'init_args':{ + 'candidate_choices':[c1,c2,c3...],... + },... + },... + } + Every unit must have the same number of candidate_choices, and + the candidate in the list of candidate_choices with the same + position compose a subnet. + + Returns: + List[Dict[str, int]]: config of the subnets. + """ + subnets: List[Dict[str, int]] = [] + num_subnets = 0 + for key in unit_cfg: + num_subnets = len(unit_cfg[key]['init_args']['candidate_choices']) + break + for _ in range(num_subnets): + subnets.append({}) + for key in unit_cfg: + assert num_subnets == len( + unit_cfg[key]['init_args']['candidate_choices']) + for i, value in enumerate( + unit_cfg[key]['init_args']['candidate_choices']): + subnets[i][key] = value + + return subnets diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/group_mixin.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/group_mixin.py new file mode 100755 index 000000000..569f01ebc --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/group_mixin.py @@ -0,0 +1,261 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from collections import Counter +from typing import Dict, List + +from torch.nn import Module + +from mmrazor.models.mutables import MutableValue +from mmrazor.models.mutables.mutable_module import MutableModule +from .base_mutator import MUTABLE_TYPE + + +class GroupMixin(): + """A mixin for :class:`BaseMutator`, which can group mutables by + ``custom_group`` and ``alias``(see more information in + :class:`MUTABLE_TYPE`). Grouping by alias and module name are both + supported. + + Note: + Apart from user-defined search group, all other searchable + modules(mutable) will be grouped separately. + + The main difference between using alias and module name for + grouping is that the alias is One-to-Many while the module + name is One-to-One. + + When using both alias and module name in `custom_group`, the + priority of alias is higher than that of module name. + + If alias is set in `custom_group`, then its corresponding module + name should not be in the `custom_group`. + + Moreover, there should be no duplicate keys in the `custom_group`. + + Example: + >>> import torch + >>> from mmrazor.models import DiffModuleMutator + + >>> # Assume that a toy model consists of three mutables + >>> # whose name are op1,op2,op3. The corresponding + >>> # alias names of the three mutables are a1, a1, a2. + >>> model = ToyModel() + + >>> # Using alias for grouping + >>> mutator = DiffModuleMutator(custom_group=[['a1'], ['a2']]) + >>> mutator.prepare_from_supernet(model) + >>> mutator.search_groups + {0: [op1, op2], 1: [op3]} + + >>> # Using module name for grouping + >>> mutator = DiffModuleMutator(custom_group=[['op1', 'op2'], ['op3']]) + + >>> # Using module name for grouping + >>> mutator.prepare_from_supernet(model) + >>> mutator.search_groups + {0: [op1, op2], 1: [op3]} + + >>> # Using both alias and module name for grouping + >>> mutator = DiffModuleMutator(custom_group=[['a2'], ['op2']]) + >>> mutator.prepare_from_supernet(model) + >>> # The last operation would be grouped + >>> mutator.search_groups + {0: [op3], 1: [op2], 2: [op1]} + + """ + + def is_supported_mutable(self, module): + """Judge whether is a supported mutable.""" + for mutable_type in [MutableModule, MutableValue]: + if isinstance(module, mutable_type): + return True + return False + + def _build_name_mutable_mapping( + self, supernet: Module) -> Dict[str, MUTABLE_TYPE]: + """Mapping module name to mutable.""" + name2mutable: Dict[str, MUTABLE_TYPE] = dict() + for name, module in supernet.named_modules(): + if self.is_supported_mutable(module): + name2mutable[name] = module + elif hasattr(module, 'source_mutables'): + for each_mutable in module.source_mutables: + if self.is_supported_mutable(each_mutable): + name2mutable[name] = each_mutable + + self._name2mutable = name2mutable + + return name2mutable + + def _build_alias_names_mapping(self, + supernet: Module) -> Dict[str, List[str]]: + """Mapping alias to module names.""" + alias2mutable_names: Dict[str, List[str]] = dict() + + def _append(key, dict, name): + if key not in dict: + dict[key] = [name] + else: + dict[key].append(name) + + for name, module in supernet.named_modules(): + if self.is_supported_mutable(module): + if module.alias is not None: + _append(module.alias, alias2mutable_names, name) + elif hasattr(module, 'source_mutables'): + for each_mutable in module.source_mutables: + if self.is_supported_mutable(each_mutable): + if each_mutable.alias is not None: + _append(each_mutable.alias, alias2mutable_names, + name) + + return alias2mutable_names + + def build_search_groups( + self, supernet: Module, + custom_groups: List[List[str]]) -> Dict[str, List[MUTABLE_TYPE]]: + """Build search group with ``custom_group`` and ``alias``(see more + information in :class:`MUTABLE_TYPE`). Grouping by alias and module + name are both supported. + + Args: + supernet (:obj:`torch.nn.Module`): The supernet to be searched + in your algorithm. + support_mutables (Type): Mutable type that can be grouped. + custom_group (list, optional): User-defined search groups. + All searchable modules that are not in ``custom_group`` will be + grouped separately. + + Return: + search_groups (Dict[str, List[MUTABLE_TYPE]]): The built + search_groups. + """ + name2mutable: Dict[ + str, MUTABLE_TYPE] = self._build_name_mutable_mapping(supernet) + alias2mutable_names = self._build_alias_names_mapping(supernet) + + # Check whether the custom group is valid + if len(custom_groups) > 0: + self._check_valid_groups(alias2mutable_names, name2mutable, + custom_groups) + + # Construct search_groups based on user-defined group + search_groups: Dict[str, List[MUTABLE_TYPE]] = dict() + + current_group_nums = 0 + grouped_mutable_names: List[str] = list() + grouped_alias: List[str] = list() + for group in custom_groups: + group_mutables = list() + for item in group: + if item in alias2mutable_names: + # if the item is from alias name + mutable_names: List[str] = alias2mutable_names[item] + grouped_alias.append(item) + group_mutables.extend( + [name2mutable[n] for n in mutable_names]) + grouped_mutable_names.extend(mutable_names) + else: + # if the item is in name2mutable + group_mutables.append(name2mutable[item]) + grouped_mutable_names.append(item) + + # TODO: fix prefix when constructing custom groups. + prefix = name2mutable[item].mutable_prefix + group_name = prefix + '_' + str(current_group_nums) + search_groups[group_name] = group_mutables + current_group_nums += 1 + + # Construct search_groups based on alias + for alias, mutable_names in alias2mutable_names.items(): + if alias not in grouped_alias: + # Check whether all current names are already grouped + flag_all_grouped = True + for mutable_name in mutable_names: + if mutable_name not in grouped_mutable_names: + flag_all_grouped = False + + # If not all mutables are already grouped + if not flag_all_grouped: + prefix = name2mutable[mutable_names[0]].mutable_prefix + group_name = prefix + '_' + str(current_group_nums) + search_groups[group_name] = [] + for mutable_name in mutable_names: + if mutable_name not in grouped_mutable_names: + search_groups[group_name].append( + name2mutable[mutable_name]) + grouped_mutable_names.append(mutable_name) + current_group_nums += 1 + + # check whether all the mutable objects are in the search_groups + for name, module in supernet.named_modules(): + if self.is_supported_mutable(module): + if name in grouped_mutable_names: + continue + else: + prefix = module.mutable_prefix + group_name = prefix + '_' + str(current_group_nums) + search_groups[group_name] = [module] + current_group_nums += 1 + elif hasattr(module, 'source_mutables'): + for each_mutable in module.source_mutables: + if self.is_supported_mutable(each_mutable): + if name in grouped_mutable_names: + continue + else: + prefix = each_mutable.mutable_prefix + group_name = prefix + '_' + str(current_group_nums) + search_groups[group_name] = [each_mutable] + current_group_nums += 1 + + grouped_counter = Counter(grouped_mutable_names) + + # find duplicate keys + duplicate_keys = list() + for key, count in grouped_counter.items(): + if count > 1: + duplicate_keys.append(key) + + assert len(grouped_mutable_names) == len( + list(set(grouped_mutable_names))), \ + 'There are duplicate keys in grouped mutable names. ' \ + f'The duplicate keys are {duplicate_keys}. ' \ + 'Please check if there are duplicate keys in the `custom_group`.' + + return search_groups + + def _check_valid_groups(self, alias2mutable_names: Dict[str, List[str]], + name2mutable: Dict[str, MUTABLE_TYPE], + custom_group: List[List[str]]) -> None: + """Check if all keys are legal.""" + aliases = [*alias2mutable_names.keys()] + module_names = [*name2mutable.keys()] + + expanded_custom_group: List[str] = [ + _ for group in custom_group for _ in group + ] + legal_keys: List[str] = [*aliases, *module_names] + + for key in expanded_custom_group: + if key not in legal_keys: + raise AssertionError( + f'The key: {key} in `custom_group` is not legal. ' + f'Legal keys are: {legal_keys}. ' + 'Make sure that the keys are either alias or mutable name') + + # when the mutable has alias attribute, the corresponding module + # name should not be used in `custom_group`. + used_aliases = list() + for group in custom_group: + for key in group: + if key in aliases: + used_aliases.append(key) + + for alias_key in used_aliases: + mutable_names: List = alias2mutable_names[alias_key] + # check whether module name is in custom group + for mutable_name in mutable_names: + if mutable_name in expanded_custom_group: + raise AssertionError( + f'When a mutable is set alias attribute :{alias_key},' + f'the corresponding module name {mutable_name} should ' + f'not be used in `custom_group` {custom_group}.') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/nas_mutator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/nas_mutator.py new file mode 100755 index 000000000..4636a899c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/nas_mutator.py @@ -0,0 +1,260 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import warnings +from typing import Dict, List, Optional + +import torch +import torch.nn as nn +from mmengine.model import ModuleList +from torch.nn import Module + +from mmrazor.models.architectures.dynamic_ops.mixins import DynamicChannelMixin +from mmrazor.models.mutables.mutable_module import MutableModule +from mmrazor.registry import MODELS +from .base_mutator import MUTABLE_TYPE, BaseMutator +from .group_mixin import GroupMixin + + +@MODELS.register_module() +class NasMutator(BaseMutator[MUTABLE_TYPE], GroupMixin): + """The base class for mutable based mutator. + + Args: + custom_groups (list[list[str]], optional): User-defined search groups. + All searchable modules that are not in ``custom_group`` will be + grouped separately. + """ + + def __init__(self, + custom_groups: Optional[List[List[str]]] = None, + init_cfg: Optional[Dict] = None) -> None: + super().__init__(init_cfg) + + if custom_groups is None: + custom_groups = [] + self._custom_groups = custom_groups + self._search_groups: Optional[Dict[str, List[MUTABLE_TYPE]]] = None + + def prepare_from_supernet(self, supernet: Module) -> None: + """Do some necessary preparations with supernet. + + Note: + For mutable based mutator, we need to build search group first. + + Args: + supernet (:obj:`torch.nn.Module`): The supernet to be searched + in your algorithm. + """ + self._search_groups = dict() + + # prepare for channel mutables + if self.has_channel(supernet): + units = self._prepare_from_predefined_model(supernet) + self.mutable_units = [unit for unit in units if unit.is_mutable] + + _channel_groups = dict() + for id, unit in enumerate(ModuleList(self.mutable_units)): + _channel_groups['channel' + '_' + str(id)] = [unit] + self._search_groups.update(_channel_groups) + else: + self.mutable_units = [] + + # prepare for value mutables + _value_groups: Dict[str, List[MUTABLE_TYPE]] = \ + self.build_search_groups(supernet, self._custom_groups) + self._search_groups.update(_value_groups) + + def prepare_arch_params(self): + """This function will build searchable params for each layer, which are + generally used in differentiable search algorithms, such as Darts' + series. + + Each name corresponds to an search param, so the Mutables with the same + name share the same search param. + """ + self._arch_params = nn.ParameterDict() + + for name, mutables in self.search_groups.items(): + if isinstance(mutables[0], MutableModule): + self._arch_params[name] = nn.Parameter( + torch.randn(mutables[0].num_choices) * 1e-3) + + self._modify_supernet_forward() + + def has_channel(self, supernet): + """Whether to build channel space.""" + for module in supernet.modules(): + if isinstance(module, DynamicChannelMixin): + if module.get_mutable_attr('out_channels') or \ + module.get_mutable_attr('in_channels'): + return True + return False + + @property + def search_groups(self) -> Dict[str, List[MUTABLE_TYPE]]: + """Search group of supernet. + + Note: + For mutable based mutator, the search group is composed of + corresponding mutables. + + Raises: + RuntimeError: Called before search group has been built. + + Returns: + Dict[int, List[MUTABLE_TYPE]]: Search group. + """ + if self._search_groups is None: + raise RuntimeError( + 'Call `prepare_from_supernet` first to get the search space.') + return self._search_groups + + @property + def arch_params(self) -> nn.ParameterDict: + """Search params of supernet. + + Note: + For mutable based mutator, the search group is composed of + corresponding mutables. + + Raises: + RuntimeError: Called before search group has been built. + + Returns: + Dict[int, List[MUTABLE_TYPE]]: Search group. + """ + if self._arch_params is None: + raise RuntimeError( + 'Call `prepare_arch_params` first to get the search params.') + return self._arch_params + + def _prepare_from_predefined_model(self, model: Module): + """Initialize units using the model with pre-defined dynamic-ops and + mutable-channels.""" + from mmrazor.models.mutables import OneShotMutableChannelUnit + + self._name2unit: Dict = {} + units = OneShotMutableChannelUnit.init_from_predefined_model(model) + + for unit in units: + unit.current_choice = unit.max_choice + self._name2unit[unit.name] = unit + + return units + + def _modify_supernet_forward(self): + """Modify the DiffMutableModule's default arch_param in forward. + + In MMRazor, the `DiffMutableModule` needs `arch_param` in the forward. + Here we use partial function to assign the corresponding `arch_param` + to each `DiffMutableModule`. + """ + for name, mutables in self.search_groups.items(): + for mutable in mutables: + if isinstance(mutable, MutableModule): + mutable.set_forward_args(arch_param=self.arch_params[name]) + + # choice manage + + def sample_choices(self, kind='random') -> Dict: + """Random sample choices by search space.""" + choices = dict() + for name, mutables in self.search_groups.items(): + if hasattr(self, + 'arch_params') and name in self.arch_params.keys(): + arch_param = self.arch_params[name] + choices[name] = mutables[0].sample_choice(arch_param) + else: + if kind == 'max': + choices[name] = mutables[0].max_choice + elif kind == 'min': + choices[name] = mutables[0].min_choice + elif kind == 'random': + choices[name] = mutables[0].sample_choice() + else: + raise NotImplementedError() + return choices + + def set_choices(self, choices: Dict) -> None: + """Set choices for each mutable in search space.""" + for name, mutables in self.search_groups.items(): + choice = choices[name] + + for mutable in mutables: + mutable.current_choice = choice # type: ignore + + @property + def max_choices(self) -> Dict: + """Get max choices for each mutable in search space.""" + max_choices = dict() + warned = False + for name, mutables in self.search_groups.items(): + if hasattr(self, + 'arch_params') and name in self.arch_params.keys(): + arch_param = self.arch_params[name] + max_choices[name] = mutables[0].sample_choice(arch_param) + if not warned: + warnings.warn('mutables with `arch param` detected. ' + 'which is not supposed to have max choices. ' + 'Sample by arch params instead.') + warned = True + else: + max_choices[name] = mutables[0].max_choice + + return max_choices + + @property + def min_choices(self) -> Dict: + """Get min choices for each mutable in search space.""" + min_choices = dict() + warned = False + for name, mutables in self.search_groups.items(): + if hasattr(self, + 'arch_params') and name in self.arch_params.keys(): + arch_param = self.arch_params[name] + min_choices[name] = mutables[0].sample_choice(arch_param) + if not warned: + warnings.warn('mutables with `arch param` detected. ' + 'which is not supposed to have min choices. ' + 'Sample by arch params instead.') + warned = True + else: + min_choices[name] = mutables[0].min_choice + + return min_choices + + @property + def current_choices(self) -> Dict: + """Get current choices by search space.""" + current_choices = dict() + for name, mutables in self.search_groups.items(): + current_choices[name] = mutables[0].current_choice + + return current_choices + + def set_max_choices(self): + """Set max choices for each mutable in search space.""" + warned = False + for name, mutables in self.search_groups.items(): + choice = self.max_choices[name] + if hasattr(self, + 'arch_params') and name in self.arch_params.keys(): + if not warned: + warnings.warn('mutables with `arch param` detected. ' + '`set_max_choices` is not available for it.') + warned = True + for mutable in mutables: + mutable.current_choice = choice + + def set_min_choices(self): + """Set min choices for each mutable in search space.""" + warned = False + for name, mutables in self.search_groups.items(): + choice = self.min_choices[name] + if hasattr(self, + 'arch_params') and name in self.arch_params.keys(): + if not warned: + warnings.warn('mutables with `arch param` detected. ' + '`set_max_choices` is not available for it.') + warned = True + for mutable in mutables: + mutable.current_choice = choice diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/observers/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/observers/__init__.py new file mode 100755 index 000000000..84d1677dd --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/observers/__init__.py @@ -0,0 +1,9 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .base import BaseObserver +from .lsq import LSQObserver, LSQPerChannelObserver +from .torch_observers import register_torch_observers + +__all__ = [ + 'BaseObserver', 'register_torch_observers', 'LSQObserver', + 'LSQPerChannelObserver' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/observers/base.py b/cv/distiller/CWD/mmrazor/mmrazor/models/observers/base.py new file mode 100755 index 000000000..ce226cb48 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/observers/base.py @@ -0,0 +1,8 @@ +# Copyright (c) OpenMMLab. All rights reserved. +try: + from torch.ao.quantization.observer import UniformQuantizationObserverBase +except ImportError: + from mmrazor.utils import get_placeholder + UniformQuantizationObserverBase = get_placeholder('torch>=1.13') + +BaseObserver = UniformQuantizationObserverBase diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/observers/lsq.py b/cv/distiller/CWD/mmrazor/mmrazor/models/observers/lsq.py new file mode 100755 index 000000000..ccab3b0e6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/observers/lsq.py @@ -0,0 +1,129 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import math + +import torch +import torch.distributed as dist + +from mmrazor.registry import MODELS + +try: + from torch.ao.quantization.observer import (MinMaxObserver, + PerChannelMinMaxObserver) +except ImportError: + from mmrazor.utils import get_placeholder + MinMaxObserver = get_placeholder('torch>=1.13') + PerChannelMinMaxObserver = get_placeholder('torch>=1.13') + + +def sync_tensor(tensor): + """Synchronize the target tensor during distributed training.""" + if torch.distributed.is_initialized() and tensor.is_cuda: + tensor.data = tensor.data / dist.get_world_size() + dist.all_reduce(tensor.data) + return tensor + + +class LSQObserverMixIn: + """A mixin class for LSQObserver which can provide the initialized + floating-point scale factor.""" + + def __init__(self): + self.tensor_norm = None + + @torch.jit.export + def _calculate_scale(self): + """Calculate the initialized floating-point scale factor. + + Each layer of weights and each layer of activations has a distinct step + size, represented as a fp32 value, initialized to 2<|v|> / sqrt(Q_p), + computed on either the initial weights values or the first batch of + activations, respectively. + """ + scale = 2 * self.tensor_norm / math.sqrt(self.quant_max) + sync_tensor(scale) + return scale + + +@MODELS.register_module() +class LSQObserver(MinMaxObserver, LSQObserverMixIn): + """LSQ observer. + + Paper: Learned Step Size Quantization. + """ + + def __init__(self, *args, **kwargs): + MinMaxObserver.__init__(self, *args, **kwargs) + LSQObserverMixIn.__init__(self) + + def forward(self, x_orig): + """Records the running minimum, maximum and tensor_norm of ``x``.""" + if x_orig.numel() == 0: + return x_orig + x = x_orig.detach() # avoid keeping autograd tape + x = x.to(self.min_val.dtype) + self.tensor_norm = x.abs().mean() + min_val_cur, max_val_cur = torch.aminmax(x) + min_val = torch.min(min_val_cur, self.min_val) + max_val = torch.max(max_val_cur, self.max_val) + self.min_val.copy_(min_val) + self.max_val.copy_(max_val) + return x_orig + + @torch.jit.export + def calculate_qparams(self): + """Calculates the quantization parameters.""" + _, zero_point = MinMaxObserver.calculate_qparams(self) + scale = LSQObserverMixIn._calculate_scale(self) + return scale, zero_point + + +@MODELS.register_module() +class LSQPerChannelObserver(PerChannelMinMaxObserver, LSQObserverMixIn): + """LSQ per-channel observer. + + Paper: Learned Step Size Quantization. + """ + + def __init__(self, *args, **kwargs): + PerChannelMinMaxObserver.__init__(self, *args, **kwargs) + LSQObserverMixIn.__init__(self) + + def forward(self, x_orig): + """Records the per-channel running minimum, maximum and tensor_norm of + ``x``.""" + if x_orig.numel() == 0: + return x_orig + x = x_orig.detach() # avoid keeping autograd tape + min_val = self.min_val + max_val = self.max_val + x_dim = x.size() + + new_axis_list = [i for i in range(len(x_dim))] # noqa: C416 + new_axis_list[self.ch_axis] = 0 + new_axis_list[0] = self.ch_axis + y = x.permute(new_axis_list) + # Need to match dtype of min/max because the updates to buffers + # are done in place and types need to match for comparisons + y = y.to(self.min_val.dtype) + y = torch.flatten(y, start_dim=1) + + self.tensor_norm = y.abs().mean(1) + + if min_val.numel() == 0 or max_val.numel() == 0: + min_val, max_val = torch.aminmax(y, dim=1) + else: + min_val_cur, max_val_cur = torch.aminmax(y, dim=1) + min_val = torch.min(min_val_cur, min_val) + max_val = torch.max(max_val_cur, max_val) + self.min_val.resize_(min_val.shape) + self.max_val.resize_(max_val.shape) + self.min_val.copy_(min_val) + self.max_val.copy_(max_val) + return x_orig + + @torch.jit.export + def calculate_qparams(self): + """Calculates the quantization parameters.""" + _, zero_point = PerChannelMinMaxObserver.calculate_qparams(self) + scale = LSQObserverMixIn._calculate_scale(self) + return scale, zero_point diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/observers/torch_observers.py b/cv/distiller/CWD/mmrazor/mmrazor/models/observers/torch_observers.py new file mode 100755 index 000000000..4e540667a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/observers/torch_observers.py @@ -0,0 +1,66 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import inspect +from typing import List + +import torch + +from mmrazor.registry import MODELS + +try: + import torch.ao.quantization.observer as torch_observer_src + from torch.ao.quantization.observer import PerChannelMinMaxObserver +except ImportError: + from mmrazor.utils import get_package_placeholder + torch_observer_src = get_package_placeholder('torch>=1.13') + PerChannelMinMaxObserver = get_package_placeholder('torch>=1.13') + + +@torch.jit.export +def reset_min_max_vals(self): + """Resets the min/max values. + + `min_val` and `max_val` are always be on cpu in the pytorch version of this + method. + """ + min_val = torch.rand(0, ) + max_val = torch.rand(0, ) + self.min_val.resize_(min_val.shape).copy_(min_val) + self.max_val.resize_(max_val.shape).copy_(max_val) + + +PerChannelMinMaxObserver.reset_min_max_vals = reset_min_max_vals + + +# TORCH_observers = register_torch_observers() +# TORCH_observers including: +# FixedQParamsObserver +# HistogramObserver +# MinMaxObserver +# MovingAverageMinMaxObserver +# MovingAveragePerChannelMinMaxObserver +# NoopObserver +# ObserverBase +# PerChannelMinMaxObserver +# PlaceholderObserver +# RecordingObserver +# ReuseInputObserver +# UniformQuantizationObserverBase +def register_torch_observers() -> List[str]: + """Register observers in ``torch.ao.quantization.observer`` to the + ``MODELS`` registry. + + Returns: + List[str]: A list of registered observers' name. + """ + torch_observers = [] + for module_name in dir(torch_observer_src): + if module_name.startswith('__') or module_name.startswith('_') or \ + module_name.startswith('default'): + continue + _observer = getattr(torch_observer_src, module_name) + if inspect.isclass(_observer) and issubclass( + _observer, torch_observer_src.ObserverBase): + if MODELS.get(module_name) is None: + MODELS.register_module(module=_observer) + torch_observers.append(module_name) + return torch_observers diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/__init__.py new file mode 100755 index 000000000..a26bb1322 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/__init__.py @@ -0,0 +1,11 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .academic_quantizer import AcademicQuantizer +from .base import BaseQuantizer +from .native_quantizer import TorchNativeQuantizer +from .openvino_quantizer import OpenVINOQuantizer +from .tensorrt_quantizer import TensorRTQuantizer + +__all__ = [ + 'BaseQuantizer', 'AcademicQuantizer', 'TorchNativeQuantizer', + 'TensorRTQuantizer', 'OpenVINOQuantizer' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/academic_quantizer.py b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/academic_quantizer.py new file mode 100755 index 000000000..0dbe6dcdd --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/academic_quantizer.py @@ -0,0 +1,170 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional + +import torch + +from mmrazor.models.task_modules.tracer import build_graphmodule +from mmrazor.models.utils import str2class +from mmrazor.registry import MODELS +from mmrazor.structures.quantization import BackendConfigs, QConfigHandler +from .base import BaseQuantizer + +try: + from torch.ao.quantization.fx import prepare + from torch.ao.quantization.fx.custom_config import (FuseCustomConfig, + PrepareCustomConfig) + from torch.ao.quantization.qconfig_mapping import QConfigMapping + from torch.ao.quantization.quantize_fx import _fuse_fx +except ImportError: + from mmrazor.utils import get_placeholder + prepare = get_placeholder('torch>=1.13') + FuseCustomConfig = get_placeholder('torch>=1.13') + PrepareCustomConfig = get_placeholder('torch>=1.13') + QConfigMapping = get_placeholder('torch>=1.13') + _fuse_fx = get_placeholder('torch>=1.13') + +GLOBAL_DICT_KEY = '_global_' +OBJECT_TYPE_DICT_KEY = 'object_type' +MODULE_NAME_DICT_KEY = 'module_name' + +# keys can be used in `prepare_custom_config` of `AcademicQuantizer`. +FLOAT_TO_OBSERVED_DICT_KEY = 'float_to_observed_custom_module_class' +PRESERVED_ATTRIBUTES_DICT_KEY = 'preserved_attributes' + + +@MODELS.register_module() +class AcademicQuantizer(BaseQuantizer): + """Quantizer for academic researching. Different from some quantizers for + deploying, `AcademicQuantizer` is without the interfaces for deployment, + but it has more flexible functions for quantizing your model. With its + help, you can custom configuration qconfig for differenet OP by + `qconfig_mapping` to implement customized experiments, including using + custom fakquant, trying mixed precision quantization, comparing different + quantization scheme and so on. + + Args: + qconfig_mapping (Dict): Mapping from model ops to qconfig to configure + how a model is quantized. You can specify qconfigs using the + following keys (in increasing match priority): + ``_global_`` : sets the global (default) qconfig + ``object_type`` : sets the qconfig for a given module type, + function, or method name + ``module_name`` : sets the qconfig for modules matching the + given module name + tracer (Dict): It can be used to trace the float model to generate the + corresponding graph, which contributes to prepare for quantizing + the float model with code-free. Default to + `dict(type='mmrazor.CustomTracer')`. + prepare_custom_config (Optional[Dict]): Custom configuration for + :func:`~torch.ao.quantization.fx.prepare`. You can specify the + follow: + ``float_to_observed_custom_module_class`` : a list of dict that + mapping from float module classes to observed module + classes, e.g. + `[('FloatCustomModule', 'ObservedCustomModule')]` + ``preserved_attributes``: a list of attributes that persist + even if they are not used in ``forward``, e.g. + `['attr1', 'attr2']` + """ + + def __init__(self, + qconfig_mapping: Dict, + tracer: Dict = dict(type='mmrazor.CustomTracer'), + prepare_custom_config: Optional[Dict] = None): + super().__init__(tracer) + self.qconfig_mapping = self.gen_qconfig_mapping(qconfig_mapping) + self.prepare_custom_config = self.gen_prepare_custom_config( + prepare_custom_config) + self.backend_config = BackendConfigs[self.backend] + self.example_inputs = (torch.randn(1, 3, 224, 224), ) + + @property + def backend(self): + """The key of the corresponding backend config.""" + return 'academic' + + def prepare(self, model, concrete_args=None): + """Prepare for quantizing model, which includes as follows: + + 1. Swap floatfunctional with FXFloatFunctional; + 2. Trace model to generate `GraphModule`; + 2. Fuse some OPs combination, such as conv + bn, conv + relu and so on; + 3. Swap some conv or linear module with QAT Modules which contain + weight fakequant nodes; + 4. Insert required fakequant nodes for activation. + step 3 and step 4 are implemented in + :func:`~torch.ao.quantization.fx.prepare` + """ + self.swap_ff_with_fxff(model) + traced_graph = self.tracer.trace(model, concrete_args=concrete_args) + graph_module = build_graphmodule(model, traced_graph) + preserved_attributes = self.prepare_custom_config.preserved_attributes + for attr_name in preserved_attributes: + setattr(graph_module, attr_name, getattr(model, attr_name)) + fuse_custom_config = FuseCustomConfig().set_preserved_attributes( + preserved_attributes) + + # set the training modes of all modules to True to `_fuse_fx` correctly + # todo: check freezebn + self.sync_module_training_mode(graph_module, mode=True) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + fuse_custom_config=fuse_custom_config) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + prepare_custom_config=self.prepare_custom_config, + backend_config=self.backend_config) + for attr_name in preserved_attributes: + setattr(prepared, attr_name, getattr(model, attr_name)) + + return prepared + + def gen_qconfig_mapping(self, qconfig_mapping: Dict): + """Convert qconfig_mapping in config file to `QConfigMapping`. + + `QConfigMapping` is a custom class for mapping from model ops to + :class:`torch.ao.quantization.QConfig` s. + """ + conf = QConfigMapping() + if GLOBAL_DICT_KEY in qconfig_mapping: + qconfig = QConfigHandler( + qconfig_mapping[GLOBAL_DICT_KEY]).convert() + conf.set_global(qconfig) + + for object_type, qconfig in qconfig_mapping.get( + OBJECT_TYPE_DICT_KEY, []): + qconfig = QConfigHandler(qconfig).convert() + conf.set_object_type(str2class(object_type), qconfig) + + for module_name, qconfig in qconfig_mapping.get( + MODULE_NAME_DICT_KEY, []): + qconfig = QConfigHandler(qconfig).convert() + conf.set_module_name(module_name, qconfig) + + return conf + + def gen_prepare_custom_config(self, prepare_custom_config: Optional[Dict]): + """Convert prepare_custom_config in config file to + `PrepareCustomConfig`. + + `PrepareCustomConfig` is a custom class for custom configurating + :func:`~torch.ao.quantization.fx.prepare`. + """ + conf = PrepareCustomConfig() + if prepare_custom_config is None: + return conf + else: + for float_class_str, observed_class_str in prepare_custom_config.get( # noqa: E501 + FLOAT_TO_OBSERVED_DICT_KEY, []): + float_class = MODELS.get(float_class_str) + observed_class = MODELS.get(observed_class_str) + conf.set_float_to_observed_mapping(float_class, observed_class) + conf.set_preserved_attributes( + prepare_custom_config.get(PRESERVED_ATTRIBUTES_DICT_KEY, [])) + return conf diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/base.py b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/base.py new file mode 100755 index 000000000..78c8163c7 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/base.py @@ -0,0 +1,87 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import abstractmethod +from typing import Dict + +import torch +import torch.nn as nn +from mmengine.model import BaseModule +from mmengine.model.utils import _BatchNormXd + +from mmrazor.registry import TASK_UTILS + + +class BaseQuantizer(BaseModule): + """Base class for quantizers. Its role for several subclass is as follows: + 1. Provide tracer for tracing model for all subclass. + 2. Define some common abstract methods, such as `prepare`. + 3. Provide some common functional interfaces, such as `swap_ff_with_fxff`. + + Args: + tracer (Dict): It can be used to trace the float model to generate the + corresponding graph, which contributes to prepare for quantizing + the float model with code-free. + """ + + def __init__(self, tracer: Dict): + super().__init__() + self.tracer = TASK_UTILS.build(tracer) + + def sync_module_training_mode(self, model, mode=True): + """Synchronize the training modes. + + Note that modes of conv and bn must be the same during ``_fuse_fx``. + """ + for module in model.modules(): + module.training = mode + return + + @staticmethod + def convert_batchnorm2d(model): + """Helper function to convert all :attr:`_BatchNormXd` layers and + :class:`torch.nn.SyncBatchNorm` layers in the model to + :class:`torch.nn.BatchNorm2d` layers. + """ + # todo: Convert all `_BatchNormXd` and `SyncBatchNorm` + # layers to `BatchNorm2d` layers but they may be :attr:`BatchNorm*D` + # layers + module_checklist = [nn.modules.batchnorm.SyncBatchNorm, _BatchNormXd] + + def traverse(module: nn.Module): + for child_name, child in module.named_children(): + if isinstance(child, tuple(module_checklist)): + bn = nn.BatchNorm2d(child.num_features, child.eps, + child.momentum, child.affine, + child.track_running_stats) + setattr(module, child_name, bn) + else: + traverse(child) + + traverse(model) + + @abstractmethod + def prepare(self, model): + """Prepare for quantizing model, which usually includes as follows: + + 1. Swap floatfunctional with FXFloatFunctional; + 2. Trace model to generate `GraphModule`; + 2. Fuse some OPs combination, such as conv + bn, conv + relu and so on; + 3. Swap some conv or linear module with QAT Modules which contain + weight fakequant nodes; + 4. Insert required fakequant nodes for activation. + 5. (Optional) Delete some redundant fakequant nodes according to the + special requirement of the backend for deployment. + """ + pass + + def swap_ff_with_fxff(self, model: torch.nn.Module): + """Swap FloatFunctional with FXFloatFunctional.""" + modules_to_swap = [] + for name, module in model.named_children(): + if isinstance(module, torch.ao.nn.quantized.FloatFunctional): + modules_to_swap.append(name) + else: + self.swap_ff_with_fxff(module) + + for name in modules_to_swap: + del model._modules[name] + model._modules[name] = torch.ao.nn.quantized.FXFloatFunctional() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/__init__.py new file mode 100755 index 000000000..b8153289d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .openvino_quantize_exporter import OpenVinoQuantizeExportor +from .tensorrt_quantize_exporter import TensorRTExplicitExporter + +__all__ = ['OpenVinoQuantizeExportor', 'TensorRTExplicitExporter'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/base_quantize_exporter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/base_quantize_exporter.py new file mode 100755 index 000000000..6527d3207 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/base_quantize_exporter.py @@ -0,0 +1,167 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List + +from mmengine import print_log + +from .optim_utils import ONNXOptimUtils + +try: + import onnx + from onnx import numpy_helper +except ImportError: + from mmrazor.utils import get_package_placeholder + onnx = get_package_placeholder('No module named onnx') + numpy_helper = get_package_placeholder('No module named onnx.numpy_helper') + +SUPPORT_QWEIGHT_NODE = ['Gemm', 'Conv', 'ConvTranspose'] + +PERCHANNEL_FAKEQUANTIZER = [ + 'FakeQuantizeLearnablePerchannelAffine', 'FixedPerChannelAffine' +] +PERTENSOR_FAKEQUANTIZER = ['LearnablePerTensorAffine', 'FixedPerTensorAffine'] + +ALL_FAKEQUANTIZER = PERCHANNEL_FAKEQUANTIZER + PERTENSOR_FAKEQUANTIZER + + +def _parse_attrs(node_attrs): + attrs = {} + for attr in node_attrs: + if attr.type == onnx.AttributeProto.AttributeType.INTS: + attrs[attr.name] = tuple(attr.ints) + elif attr.type == onnx.AttributeProto.AttributeType.INT: + attrs[attr.name] = attr.i + elif attr.type == onnx.AttributeProto.AttributeType.FLOATS: + attrs[attr.name] = tuple(attr.floats) + elif attr.type == onnx.AttributeProto.AttributeType.FLOAT: + attrs[attr.name] = attr.f + elif attr.type == onnx.AttributeProto.AttributeType.TENSOR: + attrs[attr.name] = numpy_helper.to_array(attr.t) + elif attr.type == onnx.AttributeProto.AttributeType.STRING: + attrs[attr.name] = str(attr.s) + elif attr.type == onnx.AttributeProto.AttributeType.STRINGS: + attrs[attr.name] = tuple([str(x) for x in attr.strings]) + else: + raise Exception('ATTR Type [{}] Not Supported!'.format(attr.type)) + return attrs + + +class BaseQuantizeExportor(): + + optimizer = ONNXOptimUtils + + def __init__(self, onnx_model, export_path) -> None: + + if isinstance(onnx_model, str): + self.onnx_model = onnx.load(onnx_model) + elif isinstance(onnx_model, onnx.ModelProto): + self.onnx_model = onnx_model + else: + raise TypeError + + self.export_path = export_path + self._init_mappings_from_onnx(self.onnx_model) + + self.optimizer.remove_fake_pad_op(self.onnx_model, self.name2data, + self.input2node, self.output2node) + + self._remap_input_and_node() + self._remap_output_and_node() + + @property + def graph(self): + """The onnx model's graph.""" + return self.onnx_model.graph + + def _init_mappings_from_onnx(self, onnx_model): + """Build necessary mappings in a onnx model.""" + + self.input2node = self.optimizer.map_input_and_node(onnx_model) + self.output2node = self.optimizer.map_output_and_node(onnx_model) + self.name2data = self.optimizer.map_name_and_data(onnx_model) + + def _remap_input_and_node(self): + """Rebuild the mapping from input name to a (node, input index) + tuple.""" + self.input2node = self.optimizer.map_input_and_node(self.onnx_model) + + def _remap_output_and_node(self): + """Rebuild the mapping from a node's output name to this node.""" + self.output2node = self.optimizer.map_output_and_node(self.onnx_model) + + def parse_qparams(self, node: onnx.NodeProto): + """Parse the quantize-related parameters based on a node.""" + tensor_name, scale, zero_point = node.input[:3] + + scale, zero_point = self.name2data[scale], self.name2data[zero_point] + if len(node.input) > 3: + qmin, qmax = node.input[-2:] + qmin, qmax = self.name2data[qmin], self.name2data[qmax] + elif len(node.attribute) > 0: + qparams = _parse_attrs(node.attribute) + qmin = qparams['quant_min'] + qmax = qparams['quant_max'] + else: + print_log(f'qmin and qmax are not found for <{node.name}>!') + qmax = qmin = None + return tensor_name, scale, zero_point, qmin, qmax + + def collect_symbolic_nodes(self, onnx_model: onnx.ModelProto): + """Collect all the fakequant nodes from a onnx model.""" + symbolic_nodes = list() + for node in onnx_model.graph.node: + if node.op_type in ALL_FAKEQUANTIZER: + symbolic_nodes.append(node) + return symbolic_nodes + + def _get_constant_inputs(self, node: onnx.NodeProto): + """Get the constant input node for the current node.""" + constant_nodes = list() + output2node = self.output2node + for inp in node.input: + if inp in output2node and output2node[inp].op_type == 'Constant': + cnode = output2node[inp] + + constant_nodes.append(cnode) + return constant_nodes + + def _collect_symbolic_constant_inputs(self, symbolic_nodes: List): + """Collect these constant nodes which is the input of all the symbolic + node.""" + + collected_constant_names = set() + constant_inputs = list() + for node in symbolic_nodes: + constant_inputs = self._get_constant_inputs(node) + for constant in constant_inputs: + if constant.name in collected_constant_names: + continue + constant_inputs.append(constant) + collected_constant_names.add(constant.name) + return constant_inputs + + def _remove_symbolic_related_from_onnx(self, symbolic_nodes: List, + symbolic_constant_inputs: List): + """Remove these out of date fakequant nodes and theirs constant input + nodes.""" + for node in symbolic_nodes: + self.onnx_model.graph.node.remove(node) + + # Remove symbolic related constant nodes. The constant node which is + # only used by those symbolic nodes can be removed. + + def _is_standalone_constant_node(constant): + for node in self.onnx_model.graph.node: + for input_name in node.input: + # A constant node always has one output. + if input_name == constant.output[0]: + return False + return True + + for constant in symbolic_constant_inputs: + if _is_standalone_constant_node(constant): + self.onnx_model.graph.node.remove(constant) + + def export(self): + """Export end to end onnx model.""" + # todo: is it a abstract method? + raise NotImplementedError diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/openvino_quantize_exporter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/openvino_quantize_exporter.py new file mode 100755 index 000000000..e706251ca --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/openvino_quantize_exporter.py @@ -0,0 +1,159 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +from typing import List + +import numpy as np +from google.protobuf.internal.containers import RepeatedScalarFieldContainer + +try: + import onnx + from onnx import helper, numpy_helper +except ImportError: + from mmrazor.utils import get_package_placeholder + onnx = get_package_placeholder('No module named onnx') + numpy_helper = get_package_placeholder('No module named onnx.numpy_helper') + helper = get_package_placeholder('No module named onnx.helper') + +from .base_quantize_exporter import BaseQuantizeExportor + + +class OpenVinoQuantizeExportor(BaseQuantizeExportor): + + def __init__(self, onnx_model, export_path) -> None: + super().__init__(onnx_model, export_path) + + def _build_backend_node_from_symbolic(self, node: onnx.NodeProto, + tensor_name: str, qmin: np.ndarray, + qmax: np.ndarray): + """Build new onnx nodes which can be deployed to the specific backend. + + These nodes will be used to replace those symbolic nodes in the + original onnx model. + """ + qmax = int(qmax) + qmin = int(qmin) + levels = qmax - qmin + 1 + # adjust weight levels + # if levels == 128: + # levels = 256 + # qmax = qmax * 2 + 1 + # qmin = qmin * 2 + output_name = node.output[0] + # Create a node (FakeQuantize) + keys = ['input_min', 'input_max', 'output_min', 'output_max'] + input_names = [f'{tensor_name}_{key}' for key in keys] + backend_node = helper.make_node( + 'FakeQuantize', # node name + [tensor_name, *input_names], # inputs + [output_name], # outputs + levels=levels, # Attributes + domain='org.openvinotoolkit', + name=node.name) + return backend_node + + def _build_backend_initializer(self, + names: RepeatedScalarFieldContainer[str], + scale: np.ndarray, zero_point: np.ndarray, + qmin: np.ndarray, qmax: np.ndarray, + shape: List[int]): + """Build onnx initializers which can be deployed to specific + backend.""" + + scale = np.abs(np.asarray(scale, dtype=np.float64).reshape(-1)) + zero_point = np.clip( + np.asarray(np.round(zero_point), dtype=np.int32).reshape(-1), + a_min=qmin, + a_max=qmax) + + qrange = float(qmax - qmin) + input_range = scale * qrange + input_high = (qmax - zero_point).astype( + np.float64) * input_range / qrange + input_low = input_high - input_range + input_low_size = input_low.size + + if input_low_size != 1: + input_low = input_low.reshape(*shape) + input_high = input_high.reshape(*shape) + + input_low = input_low.astype(np.float32) + input_high = input_high.astype(np.float32) + + initializers = list() + for init_name, value_tensor in zip( + names, [input_low, input_high, input_low, input_high]): + init = numpy_helper.from_array(value_tensor) + init.name = init_name + initializers.append(init) + return initializers + + def build_backend_nodes_and_initializers(self, symbolic_nodes: List): + """Build new onnx nodes and initializers which can be deployed to + specific backend.""" + backend_nodes = list() + backend_initializers = list() + for node in symbolic_nodes: + tensor_name, scale, zero_point, qmin, qmax = self.parse_qparams( + node) + new_node = self._build_backend_node_from_symbolic( + node, tensor_name, qmin, qmax) + backend_nodes.append(new_node) + + try: + # If the successor node (such as a conv node) has weight, + # we need get the length of the weight's shape. And ensure + # the length of the weight's shape and the new node's + # input shape (such as input_low and input_high) is the same. + next_node = self.input2node[node.output[0]][0][0] + # node for save weights + fake_node = self.output2node[next_node.input[1]] + tensor = self.name2data[fake_node.input[0]] + shape_length = len(tensor.shape) + new_shape = [-1] + [1] * (shape_length - 1) + except Exception: + new_shape = [-1] + + # The first element of new_node.input is the tensor name. + new_init_names = new_node.input[1:] + new_initializers = self._build_backend_initializer( + new_init_names, scale, zero_point, qmin, qmax, new_shape) + backend_initializers.extend(new_initializers) + return backend_nodes, backend_initializers + + def _insert_initializers_to_onnx(self, initializers: List): + """Insert onnx initializers to the onnx graph.""" + inserted_init_names = set() + for init in initializers: + if init.name in inserted_init_names: + continue + + self.onnx_model.graph.initializer.append(init) + inserted_init_names.add(init.name) + + def _replace_symbolic_related(self): + """Replacing symbolic related nodes and initializers in the original + onnx model with new nodes and initializers that can be deployed to the + specific backend.""" + + symbolic_nodes = self.collect_symbolic_nodes(self.onnx_model) + + collect_func = self._collect_symbolic_constant_inputs + # Usually different activation fakequants share the same constant + # input, and different weight fakequants share the same constant input. + symbolic_constant_inputs = collect_func(symbolic_nodes) + + build_func = self.build_backend_nodes_and_initializers + new_nodes, new_initializers = build_func(symbolic_nodes) + + self._insert_initializers_to_onnx(new_initializers) + + self._remove_symbolic_related_from_onnx(symbolic_nodes, + symbolic_constant_inputs) + + self.onnx_model.graph.node.extend(new_nodes) + self.optimizer.optimize(self.onnx_model) + + def export(self): + """Export end to end onnx model.""" + self._replace_symbolic_related() + onnx.save(self.onnx_model, self.export_path) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/optim_utils.py b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/optim_utils.py new file mode 100755 index 000000000..f4adc5ee1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/optim_utils.py @@ -0,0 +1,265 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict, List, Optional + +from mmengine import print_log + +try: + import onnx + from onnx import numpy_helper +except ImportError: + from mmrazor.utils import get_package_placeholder + onnx = get_package_placeholder('No module named onnx') + numpy_helper = get_package_placeholder('No module named onnx.numpy_helper') + + +class ONNXOptimUtils(): + + @classmethod + def map_name_and_data(cls, onnx_model: onnx.ModelProto): + """Build the mapping from a data's name to the data itself.""" + params = {} + for init in onnx_model.graph.initializer: + params[init.name] = numpy_helper.to_array(init) + for node in onnx_model.graph.node: + # If two zero_points are identity, one is a reference to the other + # after optimized by onnx. + if node.op_type == 'Identity' and len(node.input) == 1 and \ + node.input[0] in params: + params[node.output[0]] = copy.deepcopy(params[node.input[0]]) + if node.op_type == 'Constant': + for attr in node.attribute: + if attr.name == 'value': + params[node.output[0]] = numpy_helper.to_array(attr.t) + return params + + @classmethod + def map_name_and_initializer(cls, + onnx_model: onnx.ModelProto, + allow_redundant=True): + """Build the mapping from a initializer's output name to this + initializer.""" + + initializers = dict() + + for idx, init in enumerate(onnx_model.graph.initializer): + initializers[init.name] = (init, idx) + + return initializers + + @classmethod + def map_output_and_node(cls, onnx_model: onnx.ModelProto): + """Build the mapping from a node's output name to this node.""" + output2node = dict() + for node in onnx_model.graph.node: + for output_name in node.output: + output2node[output_name] = node + return output2node + + @classmethod + def map_input_and_node(cls, onnx_model: onnx.ModelProto): + """Build the mapping from input name to a (node, input index) tuple.""" + + input2node: Dict[str, List] = dict() + for node in onnx_model.graph.node: + for idx, input_name in enumerate(node.input): + if input_name not in input2node: + input2node[input_name] = [] + input2node[input_name].append([node, idx]) + return input2node + + @classmethod + def remove_node_from_onnx(cls, node: onnx.NodeProto, + onnx_model: onnx.ModelProto): + """Removes a node from node list.""" + onnx_model.graph.node.remove(node) + + @classmethod + def remove_initializer_from_onnx(cls, initializer: onnx.TensorProto, + onnx_model: onnx.ModelProto): + """Inserts the initializer at the specified position.""" + onnx_model.graph.initializer.remove(initializer) + + @classmethod + def remove_fake_pad_op(cls, onnx_model, name2data, inp2node, out2node): + nodes_to_be_removed = [] + for idx, node in enumerate(onnx_model.graph.node): + if node.op_type == 'Pad': + pads = name2data[node.input[1]] + if all([x == 0 for x in pads]): + print_log(f'Remove pad op: <{node.name}>.') + next_nodes = inp2node[node.output[0]] + for next_node, idx in next_nodes: + next_node.input[idx] = node.input[0] + nodes_to_be_removed.append(node) + + for node in nodes_to_be_removed: + onnx_model.graph.node.remove(node) + + @classmethod + def insert_node_to_onnx(cls, + node: onnx.NodeProto, + onnx_model: onnx.ModelProto, + idx: int = 0): + """Inserts the node at the specified position.""" + onnx_model.graph.node.insert(idx, node) + + @classmethod + def find_standalone_nodes(cls, + onnx_model: onnx.ModelProto, + input2node: Optional[Dict] = None, + output2node: Optional[Dict] = None): + """Find unused nodes.""" + + if input2node is None: + input2node = cls.map_input_and_node(onnx_model) + if output2node is None: + output2node = cls.map_output_and_node(onnx_model) + + def _is_standalone_node(node, input2node, output2node): + for input_name in node.input: + if input_name in output2node: + return False + + for out_node in node.output: + if out_node in input2node: + return False + + return True + + standalone_nodes = list() + for node in onnx_model.graph.node: + + if _is_standalone_node(node, input2node, output2node): + standalone_nodes.append(node) + return standalone_nodes + + @classmethod + def find_redundant_initializers(cls, + onnx_model: onnx.ModelProto, + input2node: Optional[Dict] = None): + """Find unused initializers.""" + if input2node is None: + input2node = cls.map_input_and_node(onnx_model) + + initializers = cls.map_name_and_initializer(onnx_model) + redundant_initializers = list() + redundant_set = set() + for name, init_and_idx in initializers.items(): + if name not in input2node and name not in redundant_set: + # init_and_idx[0] is onnx.onnx_ml_pb2.TensorProto + # init_and_idx[1] is a integer index + redundant_initializers.append(init_and_idx[0]) + redundant_set.add(name) + return redundant_initializers + + @classmethod + def topo_sort(cls, + onnx_model: onnx.ModelProto, + initializers: Optional[Dict] = None, + inplace: bool = True): + """Topologically sort the nodes in a directed acyclic graph. + + Note that nodes in a directed acyclic graph may be out of order + after replacing symbolic related nodes with new nodes. + + Args: + onnx_model (onnx.ModelProto): The onnx model to be sorted + topologically. + initializers (Dict | Optional): The mapping from name to + initializers. Default to None. + inplace (bool): Can optionally do the operation in-place. + Defaults to True. + """ + + if inplace: + _onnx_model = onnx_model + else: + _onnx_model = copy.deepcopy(onnx_model) + + if initializers is None: + initializers = cls.map_name_and_initializer( + _onnx_model, allow_redundant=True) + + # A node may have multiple outputs. The first output name of a node + # named `/conv/Conv` is `/conv/Conv_output_0` + output_name2node = {} + for node in _onnx_model.graph.node: + for output_name in node.output: + output_name2node[output_name] = node + for node in _onnx_model.graph.input: + output_name2node[node.name] = node + + name2node = {node.name: node for node in _onnx_model.graph.node} + + graph: Dict[str, + List] = {node.name: [] + for node in _onnx_model.graph.node} + for node in _onnx_model.graph.input: + graph[node.name] = [] + + indegree = {node.name: 0 for node in _onnx_model.graph.node} + + # Build graph + for i, node in enumerate(_onnx_model.graph.node): + for input_name in node.input: + if input_name not in initializers: + indegree[node.name] += 1 + prev_node = output_name2node[input_name] + graph[prev_node.name].append(node) + + graph_input = [node.name for node in _onnx_model.graph.input] + root = graph_input.copy() + sorted_nodes = [] + + # There are some nodes whose input are all initializers. + for node_name, in_degree in indegree.items(): + if in_degree == 0: + root.append(node_name) + + while root: + node_name = root.pop() + # There is no intersection between graph_input and + # _onnx_model.graph.node + if node_name not in graph_input: + node = name2node[node_name] + sorted_nodes.append(node) + for next_node in graph[node_name]: + indegree[next_node.name] -= 1 + if indegree[next_node.name] == 0: + root.append(next_node.name) + + num_nodes = len(_onnx_model.graph.node) + if len(sorted_nodes) != num_nodes: + raise RuntimeError('The graph is not a DAG.') + + for _ in range(num_nodes): + _onnx_model.graph.node.pop() + for node in sorted_nodes: + _onnx_model.graph.node.append(node) + + return _onnx_model + + @classmethod + def optimize(cls, onnx_model): + """Remove standalone nodes and redundant initializers, and + topologically sort the nodes in a directed acyclic graph.""" + + input2node = cls.map_input_and_node(onnx_model) + output2node = cls.map_output_and_node(onnx_model) + + standalone_nodes = cls.find_standalone_nodes(onnx_model, input2node, + output2node) + for node in standalone_nodes: + cls.remove_node_from_onnx(node, onnx_model) + print_log(f'Remove node {node.name}') + + redundant_inits = cls.find_redundant_initializers( + onnx_model, input2node) + for init in redundant_inits: + cls.remove_initializer_from_onnx(init, onnx_model) + print_log(f'Remove initializer {init.name}') + + sorted_onnx_model = cls.topo_sort(onnx_model) + + return sorted_onnx_model diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/tensorrt_quantize_exporter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/tensorrt_quantize_exporter.py new file mode 100755 index 000000000..cde430b08 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/tensorrt_quantize_exporter.py @@ -0,0 +1,49 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np + +try: + import onnx +except ImportError: + from mmrazor.utils import get_package_placeholder + onnx = get_package_placeholder('No module named onnx') + +from .base_quantize_exporter import BaseQuantizeExportor + + +class TensorRTExplicitExporter(BaseQuantizeExportor): + + def __init__(self, onnx_model, export_path) -> None: + super().__init__(onnx_model, export_path) + + def _build_backend_node_from_symbolic(self, node): + quantize_linear_node = onnx.helper.make_node( + 'QuantizeLinear', node.input[:3], [node.name + '_quantized_out'], + node.name + '_quantized') + dequantize_linear_node = onnx.helper.make_node( + 'DequantizeLinear', + [node.name + '_quantized_out'] + quantize_linear_node.input[1:3], + node.output, node.name + '_dequantized') + return [quantize_linear_node, dequantize_linear_node] + + def build_backend_nodes(self, symbolic_nodes): + backend_nodes = list() + for node in symbolic_nodes: + _, _, zero_point, qmin, qmax = self.parse_qparams(node) + assert qmax - qmin in ( + 2**8 - 1, 2**8 - + 2), 'Only 8 bit quantization support deployment to ONNX.' + assert not np.any(zero_point != 0), \ + 'This pass is only supposed to be used with TensorRT ' \ + 'Backend which does not support asymmetric quantization.' + new_nodes = self._build_backend_node_from_symbolic(node) + backend_nodes.extend(new_nodes) + return backend_nodes + + def export(self): + symbolic_nodes = self.collect_symbolic_nodes(self.onnx_model) + new_nodes = self.build_backend_nodes(symbolic_nodes) + for node in symbolic_nodes: + self.onnx_model.graph.node.remove(node) + self.onnx_model.graph.node.extend(new_nodes) + self.optimizer.optimize(self.onnx_model) + onnx.save(self.onnx_model, self.export_path) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/native_quantizer.py b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/native_quantizer.py new file mode 100755 index 000000000..7b6f2f9ad --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/native_quantizer.py @@ -0,0 +1,446 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Any, Dict, List, Optional, Tuple, Union + +import torch +from mmengine.config import Config + +try: + from torch.ao.quantization import (disable_observer, enable_fake_quant, + enable_observer) + from torch.ao.quantization.fx import prepare + from torch.ao.quantization.fx.graph_module import ObservedGraphModule + from torch.ao.quantization.qconfig_mapping import ( + _FIXED_QPARAMS_OP_TO_OBSERVER, FixedQParamsFakeQuantize, QConfig, + QConfigMapping, default_weight_fake_quant) + from torch.ao.quantization.quantize_fx import _fuse_fx + from torch.fx.graph_module import GraphModule + from torch.nn.intrinsic.qat import modules as qat_fused_modules + from torch.nn.qat import modules as qat_modules + from torch.onnx import register_custom_op_symbolic +except ImportError: + from mmrazor.utils import get_package_placeholder, get_placeholder + GraphModule = get_placeholder('torch>=1.13') + ObservedGraphModule = get_placeholder('torch>=1.13') + enable_fake_quant = get_placeholder('torch>=1.13') + disable_observer = get_placeholder('torch>=1.13') + enable_observer = get_placeholder('torch>=1.13') + prepare = get_placeholder('torch>=1.13') + QConfigMapping = get_placeholder('torch>=1.13') + _fuse_fx = get_placeholder('torch>=1.13') + qat_fused_modules = get_package_placeholder('torch>=1.13') + qat_modules = get_package_placeholder('torch>=1.13') + _FIXED_QPARAMS_OP_TO_OBSERVER = get_package_placeholder('torch>=1.13') + FixedQParamsFakeQuantize = get_package_placeholder('torch>=1.13') + QConfig = get_package_placeholder('torch>=1.13') + default_weight_fake_quant = get_package_placeholder('torch>=1.13') + +from mmrazor import digit_version +from mmrazor.models.task_modules.tracer import build_graphmodule +from mmrazor.models.task_modules.tracer.fx import ( + del_fakequant_after_function, del_fakequant_after_method, + del_fakequant_after_module, del_fakequant_after_op, + del_fakequant_before_function, del_fakequant_before_method, + del_fakequant_before_module, del_fakequant_before_op) +from mmrazor.models.utils import str2class +from mmrazor.registry import MODELS +from mmrazor.structures.quantization import BackendConfigs, QConfigHandler +from .base import BaseQuantizer + +if digit_version(torch.__version__) >= digit_version('1.13.0'): + SUPPORT_QAT_MODULES: Tuple = ( + qat_fused_modules.ConvBn1d, qat_fused_modules.ConvBn2d, + qat_fused_modules.ConvBn3d, qat_fused_modules.ConvBnReLU1d, + qat_fused_modules.ConvBnReLU2d, qat_fused_modules.ConvBnReLU3d, + qat_fused_modules.ConvReLU1d, qat_fused_modules.ConvReLU2d, + qat_fused_modules.ConvReLU3d, qat_fused_modules.LinearBn1d, + qat_fused_modules.LinearReLU, qat_modules.Conv1d, qat_modules.Conv2d, + qat_modules.Conv3d, qat_modules.Linear) + + MERGE_BN_MAPPINGS: Dict = { + qat_fused_modules.ConvBn1d: qat_modules.Conv1d, + qat_fused_modules.ConvBn2d: qat_modules.Conv2d, + qat_fused_modules.ConvBn3d: qat_modules.Conv3d, + qat_fused_modules.ConvBnReLU1d: qat_fused_modules.ConvReLU1d, + qat_fused_modules.ConvBnReLU2d: qat_fused_modules.ConvReLU2d, + qat_fused_modules.ConvBnReLU3d: qat_fused_modules.ConvReLU3d, + qat_fused_modules.LinearBn1d: qat_modules.Linear + } + + def fake_quantize_per_channel_affine(g, x, scale, zero_point, ch_axis, + quant_min, quant_max): + return g.op('mmrazor::FixedPerChannelAffine', x, scale, zero_point, + ch_axis, quant_min, quant_max) + + register_custom_op_symbolic('::fake_quantize_per_channel_affine', + fake_quantize_per_channel_affine, 11) + + def fake_quantize_per_tensor_affine(g, x, scale, zero_point, quant_min, + quant_max): + return g.op('mmrazor::FixedPerTensorAffine', x, scale, zero_point, + quant_min, quant_max) + + register_custom_op_symbolic('::fake_quantize_per_tensor_affine', + fake_quantize_per_tensor_affine, 11) + +else: + SUPPORT_QAT_MODULES = () + MERGE_BN_MAPPINGS = {} + + +@MODELS.register_module() +class TorchNativeQuantizer(BaseQuantizer): + """Native class for quantizer. + + Args: + global_qconfig (Union[Dict, Config]): Config for quantization details + of weight and activation include observer, quantizer, and qscheme. + no_observer_modules (Optional[List]): Modules don't need observer. + To fit different backend, we need qconfig to determine the modules + which don't need observer. + tracer (Dict): Config for tracer to trace modules for torch fx . + + Raises: + NotImplementedError: _description_ + + Examples: + >>> global_qconfig = dict( + ... w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + ... a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + ... w_fake_quant=dict(type='mmrazor.FakeQuantize'), + ... a_fake_quant=dict(type='mmrazor.FakeQuantize'), + ... w_qscheme=dict( + ... qdtype='qint8', bit=8, is_symmetry=True, + ... is_symmetric_range=True), + ... a_qscheme=dict( + ... qdtype='quint8', bit=8, is_symmetry=True, + ... averaging_constant=0.1), +) + """ + + def __init__(self, + global_qconfig: Union[Dict, Config], + no_observer_modules: Optional[List] = None, + tracer: Dict = dict(type='CustomTracer'), + extra_redundant_fakequants: Dict = dict( + extra_module_prev_wo_fakequant=tuple(), + extra_module_next_wo_fakequant=tuple(), + extra_function_prev_wo_fakequant=tuple(), + extra_function_next_wo_fakequant=tuple(), + extra_method_prev_wo_fakequant=tuple(), + extra_method_next_wo_fakequant=tuple(), + extra_op_prev_wo_fakequant=tuple(), + extra_op_next_wo_fakequant=tuple())): + super().__init__(tracer) + self.qconfig = QConfigHandler(global_qconfig) + if self.qconfig.w_qscheme.is_per_channel: + w_mode = 'per_channel' + else: + w_mode = 'per_tensor' + if self.qconfig.a_qscheme.is_per_channel: + a_mode = 'per_channel' + else: + a_mode = 'per_tensor' + assert w_mode in self.support_w_modes + assert a_mode in self.support_a_modes + + self.qconfig_mapping = self.gen_qconfig_mapping( + self.qconfig, no_observer_modules) + self.no_observer_modules = no_observer_modules + + self.backend_config = BackendConfigs[self.backend] + self.example_inputs = (torch.randn(1, 3, 224, 224), ) + + self.extra_redundant_fakequants = extra_redundant_fakequants + + def gen_qconfig_mapping(self, qconfig, no_observer_modules): + """Convert qconfig in config file to `QConfigMapping`. + + `QConfigMapping` is a custom class for mapping from model ops to + :class:`torch.ao.quantization.QConfig` s. + """ + qconfig_mapping = QConfigMapping().set_global(qconfig.convert()) + + if no_observer_modules is not None: + no_observer_modules = str2class(no_observer_modules) + for mod in no_observer_modules: + qconfig_mapping.set_object_type(mod, None) + + fixed_qparams_observer_to_qconfig = {} + for fixed_qparams_op, observer in _FIXED_QPARAMS_OP_TO_OBSERVER.items( + ): + if observer in fixed_qparams_observer_to_qconfig: + fixed_qparams_qconfig = fixed_qparams_observer_to_qconfig[ + observer] + else: + activation = FixedQParamsFakeQuantize.with_args( + observer=observer) + + fixed_qparams_qconfig = QConfig( + activation=activation, weight=default_weight_fake_quant) + fixed_qparams_observer_to_qconfig[ + observer] = fixed_qparams_qconfig + qconfig_mapping.set_object_type(fixed_qparams_op, + fixed_qparams_qconfig) + + return qconfig_mapping + + @property + def backend(self): + """The key of the corresponding backend config.""" + return 'native' + + @property + def support_w_modes(self): + """Supported quantization modes for weight about per_tensor or + per_channel.""" + return ('per_tensor', 'per_channel') + + @property + def support_a_modes(self): + """Supported quantization modes for activation about per_tensor or + per_channel.""" + return ('per_tensor') + + def export_onnx(self, model: Union[torch.nn.Module, torch.jit.ScriptModule, + torch.jit.ScriptFunction], + args: Union[Tuple[Any, ...], + torch.Tensor], output_path: str, **kwargs): + """Export the onnx model that can be deployed to a native backend.""" + torch.onnx.export(model, args, output_path, **kwargs) + + def prepare(self, model, concrete_args=None): + """prepare graph to ObservedGraphModule. + + Returns: + ObservedGraphModule: GraphModules after fuse and observer. + + Notes: + 'graph_module' after '_fuse_fx()' function will fuse conv, BN, ReLU + into modules in SUPPORT_QAT_MODULES. + 'graph_module' after 'prepare()' function will become observed. + + Notes: + Keep `is_qat` is True is because in Pytorch when `is_qat` is false, + the `_fuse_fx()` function only fuse module into `nn.Squential`. + In mmrazor, we aim to add more ptq algorithm into our pipeline such + as Adaround, these kind of ptq method have some additional + fake_quant operations that we need it to be fused into our + `SUPPORT_QAT_MODULES` type, which is a tricky way to deal with it. + """ + self.swap_ff_with_fxff(model) + traced_graph = self.tracer.trace(model, concrete_args=concrete_args) + graph_module = build_graphmodule(model, traced_graph) + + # set the training modes of all modules to True to `_fuse_fx` correctly + # todo: check freezebn + self.sync_module_training_mode(graph_module, mode=True) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + backend_config=self.backend_config) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + backend_config=self.backend_config) + prepared = self.del_redundant_fakequant(prepared) + + return prepared + + def post_process_for_deploy(self, + observed_module: ObservedGraphModule, + device: str = 'cpu', + update_weight_with_fakequant: bool = False, + keep_w_fake_quant: bool = False): + """weight fake-quant for supported QAT modules. + + Args: + observed_module (ObservedGraphModule): Modules after fused and + observed. + keep_w_fake_quant (bool, optional): Bool to determine whether to + keep weight fake-quant op, depending on the backend. Defaults + to False. + + Note: + `post_process_weight_fakequant()` function is necessary that the + `SUPPORT_QAT_MODULES` will be convert to normal modules, and + BN will be really integrated into conv layers. + """ + + def traverse(module): + for name, child in module.named_children(): + # Trace `SUPPORT_QAT_MODULES` recursively. + if isinstance(child, SUPPORT_QAT_MODULES): + # We add w_fakequant once in case some ptq methods have + # specific operations such as Adaround. So we do Quantize + # to perform these operations and do dequantize to + # introduce quantization loss in advance. + weight_fakequant = child.weight_fake_quant + + # `to_float()` function fuse BN into conv or conv_relu, and + # also convert a qat module to a normal module. + # source url: https://github.com/pytorch/pytorch/blob/master/torch/nn/intrinsic/qat/modules/conv_fused.py # noqa: E501 + float_child = child.to_float() + + if update_weight_with_fakequant: + from torch.ao.nn.intrinsic import _FusedModule + if issubclass(type(float_child), _FusedModule): + float_child[0].weight.data = weight_fakequant( + float_child[0].weight.data) + else: + float_child.weight.data = weight_fakequant( + float_child.weight.data) + # This is decided by backend type, some backend need + # explicitly keep the fake quant structure, others don't. + # TODO add deploy doc link + if keep_w_fake_quant: + # make weight fakequant fixed as the consistent + # fakequant, it will help to deploy our model to + # various backends. + self.qconfig.fixed_w_fakequant() + for m in float_child.modules(): + setattr(m, 'qconfig', self.qconfig.convert()) + if type(child) in MERGE_BN_MAPPINGS: + cls = MERGE_BN_MAPPINGS[type(child)] + new_child = cls.from_float(float_child).to(device) + else: + new_child = type(child).from_float(float_child).to( + device) + + # because weight fakequants and observers are replaced + # with base fakequants and base observers, some + # initialized args need to be update by running + # weight_fake_quant. + enable_observer(new_child) + new_child.weight_fake_quant(new_child.weight) + disable_observer(new_child) + else: + new_child = float_child.to(device) + setattr(module, name, new_child) + else: + traverse(child) + + observed_module.apply(enable_fake_quant) + observed_module.apply(disable_observer) + traverse(observed_module) + + def del_redundant_fakequant(self, prepared: GraphModule): + """delete redundant fakequant op in prepared model. + + Returns: + prepared (GraphModule): prepared model after delete redundant + fakequant op. + + Notes: + We can configure different ways to delete redundant nodes: + @property + def module_prev_wo_fakequant(self): + return (torch.nn.ReLU6, torch.nn.Identity) + """ + extra_module_prev_wo_fakequant = self.extra_redundant_fakequants.get( + 'extra_module_prev_wo_fakequant', tuple()) + prepared = del_fakequant_before_module( + prepared, + self.module_prev_wo_fakequant + extra_module_prev_wo_fakequant, + inplace=True) + + extra_module_next_wo_fakequant = self.extra_redundant_fakequants.get( + 'extra_module_next_wo_fakequant', tuple()) + prepared = del_fakequant_after_module( + prepared, + self.module_next_wo_fakequant + extra_module_next_wo_fakequant, + inplace=True) + + extra_function_prev_wo_fakequant = self.extra_redundant_fakequants.get( + 'extra_function_prev_wo_fakequant', tuple()) + prepared = del_fakequant_before_function( + prepared, + self.function_prev_wo_fakequant + extra_function_prev_wo_fakequant, + inplace=True) + + extra_function_next_wo_fakequant = self.extra_redundant_fakequants.get( + 'extra_function_next_wo_fakequant', tuple()) + prepared = del_fakequant_after_function( + prepared, + self.function_next_wo_fakequant + extra_function_next_wo_fakequant, + inplace=True) + + extra_method_prev_wo_fakequant = self.extra_redundant_fakequants.get( + 'extra_method_prev_wo_fakequant', tuple()) + prepared = del_fakequant_before_method( + prepared, + self.method_prev_wo_fakequant + extra_method_prev_wo_fakequant, + inplace=True) + + extra_method_next_wo_fakequant = self.extra_redundant_fakequants.get( + 'extra_method_next_wo_fakequant', tuple()) + prepared = del_fakequant_after_method( + prepared, + self.method_next_wo_fakequant + extra_method_next_wo_fakequant, + inplace=True) + + extra_op_prev_wo_fakequant = self.extra_redundant_fakequants.get( + 'extra_op_prev_wo_fakequant', tuple()) + prepared = del_fakequant_before_op( + prepared, + self.op_prev_wo_fakequant + extra_op_prev_wo_fakequant, + inplace=True) + + extra_op_next_wo_fakequant = self.extra_redundant_fakequants.get( + 'extra_op_next_wo_fakequant', tuple()) + prepared = del_fakequant_after_op( + prepared, + self.op_next_wo_fakequant + extra_op_next_wo_fakequant, + inplace=True) + return prepared + + @property + def module_prev_wo_fakequant(self): + """Configurate the modules that their previous nodes are redundant + fakequants.""" + return tuple() + + @property + def module_next_wo_fakequant(self): + """Configurate the modules that their next nodes are redundant + fakequants.""" + return tuple() + + @property + def function_prev_wo_fakequant(self): + """Configurate the functions that their previous nodes are redundant + fakequants.""" + return tuple() + + @property + def function_next_wo_fakequant(self): + """Configurate the functions that their next nodes are redundant + fakequants.""" + return tuple() + + @property + def method_prev_wo_fakequant(self): + """Configurate the methods that their previous nodes are redundant + fakequants.""" + return tuple() + + @property + def method_next_wo_fakequant(self): + """Configurate the methods that their next nodes are redundant + fakequants.""" + return tuple() + + @property + def op_prev_wo_fakequant(self): + """Configurate the OPs that their previous nodes are redundant + fakequants.""" + return tuple() + + @property + def op_next_wo_fakequant(self): + """Configurate the OPs that their next nodes are redundant + fakequants.""" + return tuple() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/openvino_quantizer.py b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/openvino_quantizer.py new file mode 100755 index 000000000..8f5ef3873 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/openvino_quantizer.py @@ -0,0 +1,86 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Any, Optional, Tuple, Union + +import torch + +from mmrazor.registry import MODELS +from .native_quantizer import TorchNativeQuantizer + + +@MODELS.register_module() +class OpenVINOQuantizer(TorchNativeQuantizer): + """Quantizer for quantizing and deploying to Openvino backend. + + Each backend has its own features, for reducing the gap of quantized + performance between before and after deployment as possible, we should + match the backend's features in quantization. + + Openvino's some important features about quantization is as follows: + * support_w_mode = ('per_tensor', 'per_channel') + * support_a_mode = ('per_tensor') + * weight range should be symmetric, such as int 8 is [-127, 127] rather + than [-128, 127] + """ + + @property + def backend(self): + """The backend to deploy, also the key of the corresponding backend + config.""" + return 'openvino' + + @property + def support_w_modes(self): + """Supported quantization modes for weight about per_tensor or + per_channel.""" + return ('per_tensor', 'per_channel') + + @property + def support_a_modes(self): + """Supported quantization modes for activation about per_tensor or + per_channel.""" + return ('per_tensor') + + def export_onnx(self, + model: Union[torch.nn.Module, torch.jit.ScriptModule, + torch.jit.ScriptFunction], + args: Union[Tuple[Any, ...], torch.Tensor], + output_path: str, + opset_version: Optional[int] = 11, + **kwargs): + """Export the onnx model that can be deployed to OpenVino backend.""" + + symbolic_output_path = output_path.replace('.onnx', '_symbolic.onnx') + torch.onnx.export( + model, + args, + symbolic_output_path, + opset_version=opset_version, + **kwargs) + + from .exporters import OpenVinoQuantizeExportor + exporter = OpenVinoQuantizeExportor(symbolic_output_path, output_path) + exporter.export() + + @property + def module_prev_wo_fakequant(self): + """Configurate the modules that their previous nodes are redundant + fakequants.""" + return (torch.nn.ReLU6, torch.nn.Identity) + + @property + def module_next_wo_fakequant(self): + """Configurate the modules that their next nodes are redundant + fakequants.""" + return (torch.nn.MaxPool2d, ) + + @property + def method_next_wo_fakequant(self): + """Configurate the methods that their next nodes are redundant + fakequants.""" + return ('flatten', ) + + @property + def op_prev_wo_fakequant(self): + """Configurate the OPs that their previous nodes are redundant + fakequants.""" + return ('output', ) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/tensorrt_quantizer.py b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/tensorrt_quantizer.py new file mode 100755 index 000000000..be067fd4f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/tensorrt_quantizer.py @@ -0,0 +1,84 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Any, Optional, Tuple, Union + +import torch + +from mmrazor.registry import MODELS +from .native_quantizer import TorchNativeQuantizer + + +@MODELS.register_module() +class TensorRTQuantizer(TorchNativeQuantizer): + """Quantizer for quantizing and deploying to TensorRT backend. + + Each backend has its own features, for reducing the gap of quantized + performance between before and after deployment as possible, we should + match the backend's features in quantization. + + TensorRT's some important features about quantization is as follows: + * support_w_mode = ('per_tensor', 'per_channel') + * support_a_mode = ('per_tensor') + """ + + @property + def backend(self): + """The backend to deploy, also the key of the corresponding backend + config.""" + return 'tensorrt' + + @property + def support_w_modes(self): + """Supported quantization modes for weight about per_tensor or + per_channel.""" + return ('per_tensor', 'per_channel') + + @property + def support_a_modes(self): + """Supported quantization modes for activation about per_tensor or + per_channel.""" + return ('per_tensor') + + def export_onnx(self, + model: Union[torch.nn.Module, torch.jit.ScriptModule, + torch.jit.ScriptFunction], + args: Union[Tuple[Any, ...], torch.Tensor], + output_path: str, + opset_version: Optional[int] = 13, + **kwargs): + """Export the onnx model that can be deployed to OpenVino backend.""" + + symbolic_output_path = output_path.replace('.onnx', '_symbolic.onnx') + torch.onnx.export( + model, + args, + symbolic_output_path, + opset_version=opset_version, + **kwargs) + + from .exporters import TensorRTExplicitExporter + exporter = TensorRTExplicitExporter(symbolic_output_path, output_path) + exporter.export() + + @property + def module_prev_wo_fakequant(self): + """Configurate the modules that their previous nodes are redundant + fakequants.""" + return (torch.nn.ReLU6, torch.nn.Identity) + + @property + def module_next_wo_fakequant(self): + """Configurate the modules that their next nodes are redundant + fakequants.""" + return (torch.nn.MaxPool2d, ) + + @property + def method_next_wo_fakequant(self): + """Configurate the methods that their next nodes are redundant + fakequants.""" + return ('flatten', ) + + @property + def op_prev_wo_fakequant(self): + """Configurate the OPs that their previous nodes are redundant + fakequants.""" + return ('output', ) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/__init__.py new file mode 100755 index 000000000..931278b8a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/__init__.py @@ -0,0 +1,9 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .delivery import * # noqa: F401,F403 +from .demo_inputs import * # noqa: F401,F403 +from .estimators import ResourceEstimator +from .predictor import * # noqa: F401,F403 +from .recorder import * # noqa: F401,F403 +from .tracer import * # noqa: F401,F403 + +__all__ = ['ResourceEstimator'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/__init__.py new file mode 100755 index 000000000..814272932 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/__init__.py @@ -0,0 +1,9 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .delivery_manager import DistillDeliveryManager +from .function_outputs_delivery import FunctionOutputsDelivery +from .method_outputs_delivery import MethodOutputsDelivery + +__all__ = [ + 'FunctionOutputsDelivery', 'MethodOutputsDelivery', + 'DistillDeliveryManager' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/delivery_manager.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/delivery_manager.py new file mode 100755 index 000000000..592d8917d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/delivery_manager.py @@ -0,0 +1,113 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict, Optional + +from mmrazor.registry import TASK_UTILS +from .distill_delivery import DistillDelivery + +SUPPORT_DELIVERIES = ['FunctionOutputs', 'MethodOutputs'] + + +class DistillDeliveryManager: + """Various types deliveries' manager. The ``DistillDeliveryManager`` is + also a context manager, managing various types of deliveries. + + When entering the ``DistillDeliveryManager``, all deliveries managed by it + will be started. + + Notes: + DistillDelivery is a context manager used to override function(method) + outputs during teacher(student) forward. + + Args: + deliveries (dict): Configs of all deliveries. + + Examples: + >>> from mmcls.models.utils import Augments + + >>> augments_cfg = dict( + ... type='BatchMixup', alpha=1., num_classes=10, prob=1.0) + >>> augments = Augments(augments_cfg) + >>> imgs = torch.randn(2, 3, 32, 32) + >>> label = torch.randint(0, 10, (2,)) + + >>> # Without ``MethodOutputsDelivery``, outputs of the teacher and + >>> # the student are different. + >>> imgs_tea, label_tea = augments(imgs, label) + >>> imgs_stu, label_stu = augments(imgs, label) + >>> torch.equal(label_tea, label_stu) + False + >>> torch.equal(imgs_tea, imgs_stu) + False + + >>> distill_deliveries = ConfigDict( + ... aug=dict(type='MethodOutputs', max_keep_data=1, + ... method_path='mmcls.models.utils.Augments.__call__')) + >>> manager = DistillDeliveryManager(distill_deliveries) + + >>> manager.override_data = False + >>> with manager: + ... imgs_tea, label_tea = augments(imgs, label) + + >>> manager.override_data = True + >>> with manager: + ... imgs_stu, label_stu = augments(imgs, label) + + >>> torch.equal(label_tea, label_stu) + True + >>> torch.equal(imgs_tea, imgs_stu) + True + """ + + def __init__(self, deliveries: Optional[Dict[str, Dict]] = None) -> None: + + self._deliveries: Dict[str, DistillDelivery] = dict() + if deliveries: + for delivery_name, delivery_cfg in deliveries.items(): + delivery_cfg_ = copy.deepcopy(delivery_cfg) + delivery_type_ = delivery_cfg_.get('type', '') + assert isinstance(delivery_type_, str) + assert delivery_type_ in SUPPORT_DELIVERIES + + delivery_type_ = delivery_type_ + 'Delivery' + delivery_cfg_.update(dict(type=delivery_type_)) + + delivery = TASK_UTILS.build(delivery_cfg_) + self.deliveries[delivery_name] = delivery + + self._override_data = False + + @property + def deliveries(self) -> Dict[str, DistillDelivery]: + """dict: all deliveries.""" + return self._deliveries + + @property + def override_data(self) -> bool: + """bool: indicate whether to override the data with the recorded data. + """ + return self._override_data + + @override_data.setter + def override_data(self, override: bool) -> None: + """Set the override_data property to all the deliveries. + + If the `override_data` of a delivery is False, the delivery will + record the origin data. + + If the `override_data` of a delivery is True, the delivery will + override the origin data with the recorded data. + """ + self._override_data = override + for delivery in self.deliveries.values(): + delivery.override_data = override + + def __enter__(self) -> None: + """Enter the context manager.""" + for delivery in self.deliveries.values(): + delivery.__enter__() + + def __exit__(self, exc_type, exc_value, traceback) -> None: + """Exit the context manager.""" + for delivery in self.deliveries.values(): + delivery.__exit__(exc_type, exc_value, traceback) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/distill_delivery.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/distill_delivery.py new file mode 100755 index 000000000..d8c335f00 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/distill_delivery.py @@ -0,0 +1,66 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import ABCMeta, abstractmethod +from collections import deque +from typing import Callable + + +# TODO: Support overriding part of the outputs of a function or method +class DistillDelivery(metaclass=ABCMeta): + """Base class for deliveries for distillation. + + DistillDelivery is a context manager used to override function(method) + outputs during teacher(student) forward. + + A delivery can only handle one function or method. Some algorithms may use + multiple deliveries, which can be managed uniformly using + ``DistillDeliverManager``. + + Args: + max_keep_data (int): The length limitation of the queue, should be + larger than the execute times of the function or method. Defaults + to 1. + + Notes: + If a function (method) is executed more than once during the forward + of the source model, all the outputs of this function (method) will be + used to override function (method) outputs from the target model. + + If a function or method is executed more than once during the forward + of the target model, its' outputs from the source model are pushed + into the queue in order. + """ + + def __init__(self, max_keep_data: int = 1) -> None: + + self._override_data = False + self.data_queue: deque = deque([], maxlen=max_keep_data) + self.max_keep_data = max_keep_data + + @property + def override_data(self) -> bool: + """bool: indicate whether to override the data with the recorded data. + """ + return self._override_data + + @override_data.setter + def override_data(self, override: bool) -> None: + """Set the override_data property to this delivery. + + If the `override_data` of a deliver is False, the deliver will record + and keep the origin data. If the current_mode of a deliver is True, the + deliver will override the origin data with the recorded data. + """ + self._override_data = override + + @abstractmethod + def deliver_wrapper(self, origin: Callable) -> Callable: + """Wrap the specific object to make the intermediate results of the + model can be delivered.""" + + @abstractmethod + def __enter__(self) -> None: + """Enter the context manager.""" + + @abstractmethod + def __exit__(self, exc_type, exc_value, traceback) -> None: + """Exit the context manager.""" diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/function_outputs_delivery.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/function_outputs_delivery.py new file mode 100755 index 000000000..15c361e38 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/function_outputs_delivery.py @@ -0,0 +1,158 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import functools +from types import FunctionType +from typing import Callable + +from mmengine.utils import import_modules_from_strings + +from mmrazor.registry import TASK_UTILS +from .distill_delivery import DistillDelivery + + +@TASK_UTILS.register_module() +class FunctionOutputsDelivery(DistillDelivery): + """Delivery for intermediate results which are ``FunctionType``'s outputs. + + Args: + func_path (str): The name of the function whose output needs to be + delivered. + max_keep_data (int): The length limitation of the queue. Outputs from + the source model are pushed in the queue in order. + + Notes: + The form of `func_path` needs special attention. For example, + `anchor_inside_flags` is a function in mmdetection to check whether the + anchors are inside the border. This function is in + `mmdet/core/anchor/utils.py` and used in + `mmdet/models/dense_heads/anchor_head`. Then the `func_path` should be + `mmdet.models.dense_heads.anchor_head.anchor_inside_flags` but not + `mmdet.core.anchor.utils.anchor_inside_flags`. + + Examples: + >>> # Below code in toy_module.py + >>> import random + >>> def toy_func(): + >>> return random.randint(0, 1000) + + >>> # Below code in main.py + >>> # Teacher and student both will execute toy_func. + >>> # Now, we want to deliver outputs from the teacher to + >>> # the student + >>> import toy_module + >>> delivery = FunctionOutputsDeliver( + ... max_keep_data=1, func_path='toy_module.toy_func') + + >>> delivery.override_data = False + >>> with delivery: + ... output_teacher = toy_module.toy_func() + + >>> delivery.override_data = True + >>> with delivery: + ... output_student = toy_module.toy_func() + + >>> output_teacher == output_student + True + + >>> # If a function (method) is executed more than once during the + >>> # forward of the source model, all the outputs of this function + >>> # (method) will be used to override function (method) outputs from + >>> # the target model. + >>> delivery = FunctionOutputsDeliver( + ... max_keep_data=2, func_path='toy_module.toy_func') + + >>> delivery.override_data = False + >>> with delivery: + ... output1_tea = toy_module.toy_func() + ... output2_tea = toy_module.toy_func() + + >>> delivery.override_data = True + >>> with delivery: + ... output1_stu = toy_module.toy_func() + ... output2_stu = toy_module.toy_func() + + >>> output1_stu == output1_tea and output2_stu == output2_tea + True + """ + + def __init__(self, func_path: str, max_keep_data: int): + super().__init__(max_keep_data) + + self._check_valid_path(func_path) + self.func_path = func_path + + @staticmethod + def _check_valid_path(func_path: str) -> None: + """Check if the `func_path` is valid.""" + if not isinstance(func_path, str): + raise TypeError(f'func_path should be a FunctionType ' + f'instance, but got {type(func_path)}') + + assert len(func_path.split('.')) > 1, \ + 'func_path must have at least one `.`' + + @staticmethod + def _get_func_name(func_path: str) -> str: + """Get the function name according to `func_path`.""" + return func_path.split('.')[-1] + + @staticmethod + def _get_module_path(func_path: str) -> str: + """Get the module name according to `func_path`.""" + return '.'.join(func_path.split('.')[:-1]) + + def __enter__(self) -> None: + """Enter the context manager. + + Wrap the origin function. + """ + module_path = self._get_module_path(self.func_path) + try: + module = import_modules_from_strings(module_path) + except ImportError: + raise ImportError(f'{module_path} is not imported correctly.') + self.module = module + + func_name = self._get_func_name(self.func_path) + assert hasattr(module, func_name), \ + f'{func_name} is not in {module_path}.' + self.func_name = func_name + + origin_func = getattr(module, func_name) + if not isinstance(origin_func, FunctionType): + raise TypeError(f'{func_name} should be a FunctionType ' + f'instance, but got {type(origin_func)}') + self.origin_func = origin_func + + wrapped_func = self.deliver_wrapper(self.origin_func) + setattr(self.module, self.func_name, wrapped_func) + + def __exit__(self, exc_type, exc_value, traceback) -> None: + """Exit the context manager. + + Reset the origin function. + """ + setattr(self.module, self.func_name, self.origin_func) + + # self.module and self.origin_func can not be pickled. + # Delete these two attributes to avoid errors when ema model is used. + del self.module + del self.origin_func + + def deliver_wrapper(self, origin_func: Callable) -> Callable: + """Wrap the specific function to make the intermediate results of the + model can be delivered.""" + + @functools.wraps(origin_func) + def wrap_func(*args, **kwargs): + + if self.override_data: + assert len(self.data_queue) > 0, 'pop from an empty queue' + outputs = self.data_queue.popleft() + else: + assert len(self.data_queue) < self.data_queue.maxlen,\ + 'push into an full queue' + outputs = origin_func(*args, **kwargs) + self.data_queue.append(outputs) + return outputs + + return wrap_func diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/method_outputs_delivery.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/method_outputs_delivery.py new file mode 100755 index 000000000..fa9f6c4a4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/method_outputs_delivery.py @@ -0,0 +1,155 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import functools +from types import FunctionType, ModuleType +from typing import Callable + +from mmengine.utils import import_modules_from_strings + +from mmrazor.registry import TASK_UTILS +from .distill_delivery import DistillDelivery + + +@TASK_UTILS.register_module() +class MethodOutputsDelivery(DistillDelivery): + """Delivery for intermediate results which are ``MethodType``'s outputs. + + Note: + Different from ``FunctionType``, ``MethodType`` is the type of methods + of class instances. + + Args: + method_path (str): The name of the method whose output needs to be + delivered. + max_keep_data (int): The length limitation of the queue. Outputs from + the source model are pushed in the queue in order. + + Examples: + >>> from mmcls.models.utils import Augments + + >>> augments_cfg = dict( + ... type='BatchMixup', alpha=1., num_classes=10, prob=1.0) + >>> augments = Augments(augments_cfg) + >>> imgs = torch.randn(2, 3, 32, 32) + >>> label = torch.randint(0, 10, (2,)) + + >>> # Without ``MethodOutputsDeliver``, outputs of the teacher and the + >>> # student are very likely to be different. + >>> imgs_tea, label_tea = augments(imgs, label) + >>> imgs_stu, label_stu = augments(imgs, label) + >>> torch.equal(label_tea, label_stu) + False + >>> torch.equal(imgs_tea, imgs_stu) + False + + >>> # Suppose we want to deliver outputs from the teacher to + >>> # the student + >>> delivery = MethodOutputsDeliver( + ... max_keep_data=1, + ... method_path='mmcls.models.utils.Augments.__call__') + + >>> delivery.override_data = False + >>> with delivery: + ... imgs_tea, label_tea = augments(imgs, label) + + >>> delivery.override_data = True + >>> with delivery: + ... imgs_stu, label_stu = augments(imgs, label) + + >>> torch.equal(label_tea, label_stu) + True + >>> torch.equal(imgs_tea, imgs_stu) + True + """ + + def __init__(self, method_path: str, max_keep_data: int): + super().__init__(max_keep_data) + + self._check_valid_path(method_path) + module_path = self._get_module_path(method_path) + try: + module: ModuleType = import_modules_from_strings(module_path) + except ImportError: + raise ImportError(f'{module_path} is not imported correctly.') + + cls_name = self._get_cls_name(method_path) + assert hasattr(module, cls_name), \ + f'{cls_name} is not in {module_path}.' + + imported_cls: type = getattr(module, cls_name) + if not isinstance(imported_cls, type): + raise TypeError(f'{cls_name} should be a type ' + f'instance, but got {type(imported_cls)}') + self.imported_cls = imported_cls + + method_name = self._get_method_name(method_path) + assert hasattr(imported_cls, method_name), \ + f'{method_name} is not in {cls_name}.' + self.method_name = method_name + + origin_method = getattr(imported_cls, method_name) + # Before instantiation of a class, the type of a method of a class + # is FunctionType + if not isinstance(origin_method, FunctionType): + raise TypeError(f'{method_name} should be a FunctionType ' + f'instance, but got {type(origin_method)}') + self.origin_method = origin_method + + @staticmethod + def _check_valid_path(method_path: str) -> None: + """Check if the `method_path` is valid.""" + if not isinstance(method_path, str): + raise TypeError(f'method_path should be a str instance, ' + f'but got {type(method_path)}') + + assert len(method_path.split('.')) > 2, \ + 'method_path must have at least one `.`' + + @staticmethod + def _get_method_name(method_path: str) -> str: + """Get the method name according to `method_path`.""" + return method_path.split('.')[-1] + + @staticmethod + def _get_cls_name(method_path: str) -> str: + """Get the class name corresponding to this method according to + `method_path`.""" + return method_path.split('.')[-2] + + @staticmethod + def _get_module_path(method_path: str) -> str: + """Get the module name according to `method_path`.""" + return '.'.join(method_path.split('.')[:-2]) + + def __enter__(self) -> None: + """Enter the context manager. + + Wrap the origin method. + """ + wrapped_method = self.deliver_wrapper(self.origin_method) + setattr(self.imported_cls, self.method_name, wrapped_method) + + def __exit__(self, exc_type, exc_value, traceback) -> None: + """Exit the context manager. + + Reset the origin method. + """ + setattr(self.imported_cls, self.method_name, self.origin_method) + + def deliver_wrapper(self, origin_method: Callable) -> Callable: + """Wrap the specific method to make the intermediate results of the + model can be delivered.""" + + @functools.wraps(origin_method) + def wrap_method(*args, **kwargs): + + if self.override_data: + assert len(self.data_queue) > 0, 'pop from an empty queue' + outputs = self.data_queue.popleft() + else: + assert len(self.data_queue) < self.data_queue.maxlen,\ + 'push into an full queue' + outputs = origin_method(*args, **kwargs) + self.data_queue.append(outputs) + return outputs + + return wrap_method diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/__init__.py new file mode 100755 index 000000000..5d25e342e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/__init__.py @@ -0,0 +1,15 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .default_demo_inputs import DefaultDemoInput, defaul_demo_inputs +from .demo_inputs import (BaseDemoInput, DefaultMMClsDemoInput, + DefaultMMDemoInput, DefaultMMDetDemoInput, + DefaultMMSegDemoInput) + +__all__ = [ + 'defaul_demo_inputs', + 'DefaultMMClsDemoInput', + 'DefaultMMDetDemoInput', + 'DefaultMMDemoInput', + 'DefaultMMSegDemoInput', + 'BaseDemoInput', + 'DefaultDemoInput', +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/default_demo_inputs.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/default_demo_inputs.py new file mode 100755 index 000000000..60b69a738 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/default_demo_inputs.py @@ -0,0 +1,108 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from collections import OrderedDict + +import torch.nn as nn +from mmengine.model import BaseModel + +from mmrazor.registry import TASK_UTILS +from mmrazor.utils import get_placeholder +from ...algorithms.base import BaseAlgorithm +from .demo_inputs import (BaseDemoInput, DefaultMMClsDemoInput, + DefaultMMDemoInput, DefaultMMDetDemoInput, + DefaultMMPoseDemoInput, DefaultMMRotateDemoInput, + DefaultMMSegDemoInput, DefaultMMYoloDemoInput) + +try: + from mmdet.models import BaseDetector +except Exception: + BaseDetector = get_placeholder('mmdet') + +try: + from mmcls.models import ImageClassifier +except Exception: + ImageClassifier = get_placeholder('mmcls') + +try: + from mmseg.models import BaseSegmentor +except Exception: + BaseSegmentor = get_placeholder('mmseg') + +# New +try: + from mmpose.models import TopdownPoseEstimator +except Exception: + TopdownPoseEstimator = get_placeholder('mmpose') + +default_demo_input_class = OrderedDict([ + (BaseDetector, DefaultMMDetDemoInput), + (ImageClassifier, DefaultMMClsDemoInput), + (BaseSegmentor, DefaultMMSegDemoInput), + (TopdownPoseEstimator, DefaultMMPoseDemoInput), + (BaseModel, DefaultMMDemoInput), + (nn.Module, BaseDemoInput), +]) + +default_demo_input_class_for_scope = { + 'mmcls': DefaultMMClsDemoInput, + 'mmdet': DefaultMMDetDemoInput, + 'mmseg': DefaultMMSegDemoInput, + 'mmrotate': DefaultMMRotateDemoInput, + 'mmyolo': DefaultMMYoloDemoInput, + 'mmpose': DefaultMMPoseDemoInput, + 'torchvision': BaseDemoInput, +} + + +def get_default_demo_input_class(model, scope): + """Get demo input generator according to a model and scope.""" + if scope is not None: + for scope_name, demo_input in default_demo_input_class_for_scope.items( + ): + if scope == scope_name: + return demo_input + + for module_type, demo_input in default_demo_input_class.items( # noqa + ): # noqa + if isinstance(model, module_type): + return demo_input + # default + return BaseDemoInput + + +def defaul_demo_inputs(model, input_shape, training=False, scope=None): + """Get demo input according to a model and scope.""" + if isinstance(model, BaseAlgorithm): + return defaul_demo_inputs(model.architecture, input_shape, training, + scope) + else: + demo_input = get_default_demo_input_class(model, scope) + return demo_input().get_data(model, input_shape, training) + + +@TASK_UTILS.register_module() +class DefaultDemoInput(BaseDemoInput): + """Default demo input generator. + + Args: + input_shape: default input shape . Defaults to None. + training (bool, optional): Whether is training mode. Defaults to False. + scope (str, optional): mm scope name. Defaults to None. + """ + + def __init__( + self, + input_shape=None, + training=False, + scope: str = None, + kwargs={}, + ) -> None: + + default_demo_input_class = get_default_demo_input_class(None, scope) + if input_shape is None: + input_shape = default_demo_input_class.default_shape + super().__init__(input_shape, training, kwargs=kwargs) + self.scope = scope + + def _get_data(self, model, input_shape, training): + """Helper for get_data, including core logic to generate demo input.""" + return defaul_demo_inputs(model, input_shape, training, self.scope) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/demo_inputs.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/demo_inputs.py new file mode 100755 index 000000000..e1222f2b1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/demo_inputs.py @@ -0,0 +1,148 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +from mmrazor.registry import TASK_UTILS + + +@TASK_UTILS.register_module() +class BaseDemoInput(): + """Base demo input generator. + + Args: + input_shape: Default input shape. Defaults to default_shape. + training (bool, optional): Default training mode. Defaults to None. + kwargs (dict): Other keyword args to update the generated inputs. + """ + default_shape = (1, 3, 224, 224) + + def __init__(self, + input_shape=default_shape, + training=None, + kwargs={}) -> None: + + self.input_shape = input_shape + self.training = training + self.kwargs = kwargs + + def get_data(self, model, input_shape=None, training=None): + """Api to generate demo input.""" + if input_shape is None: + input_shape = self.input_shape + if training is None: + training = self.training + + data = self._get_data(model, input_shape, training) + if isinstance(data, dict): + data.update(self.kwargs) + return data + + def _get_data(self, model, input_shape, training): + """Helper for get_data, including core logic to generate demo input.""" + return torch.rand(input_shape) + + def __call__(self, + model=None, + input_shape=[1, 3, 224, 224], + training=False): + return self.get_data(model, input_shape, training) + + +@TASK_UTILS.register_module() +class DefaultMMDemoInput(BaseDemoInput): + """Default demo input generator for openmmable models.""" + + def _get_data(self, model, input_shape=None, training=None): + """Helper for get_data, including core logic to generate demo input.""" + + data = self._get_mm_data(model, input_shape, training) + data['mode'] = 'tensor' + return data + + def _get_mm_data(self, model, input_shape, training=False): + data = {'inputs': torch.rand(input_shape), 'data_samples': None} + data = model.data_preprocessor(data, training) + return data + + +@TASK_UTILS.register_module() +class DefaultMMClsDemoInput(DefaultMMDemoInput): + """Default demo input generator for mmcls models.""" + + def _get_mm_data(self, model, input_shape, training=False): + """Helper for get_data, including core logic to generate demo input.""" + from mmcls.structures import ClsDataSample + x = torch.rand(input_shape) + mm_inputs = { + 'inputs': + x, + 'data_samples': [ + ClsDataSample( + metainfo=dict(img_shape=input_shape[i], + num_classes=1000)).set_gt_label(1) + for i in range(input_shape[0]) + ], + } + mm_inputs = model.data_preprocessor(mm_inputs, training) + return mm_inputs + + +@TASK_UTILS.register_module() +class DefaultMMDetDemoInput(DefaultMMDemoInput): + """Default demo input generator for mmdet models.""" + + def _get_mm_data(self, model, input_shape, training=False): + """Helper for get_data, including core logic to generate demo input.""" + from mmdet.models import BaseDetector + from mmdet.testing._utils import demo_mm_inputs + assert isinstance(model, BaseDetector), f'{type(model)}' + + data = demo_mm_inputs(1, [input_shape[1:]], with_mask=True) + data = model.data_preprocessor(data, training) + return data + + +@TASK_UTILS.register_module() +class DefaultMMSegDemoInput(DefaultMMDemoInput): + """Default demo input generator for mmseg models.""" + + def _get_mm_data(self, model, input_shape, training=False): + """Helper for get_data, including core logic to generate demo input.""" + from mmseg.models import BaseSegmentor + assert isinstance(model, BaseSegmentor) + from .mmseg_demo_input import demo_mmseg_inputs + data = demo_mmseg_inputs(model, input_shape) + return data + + +@TASK_UTILS.register_module() +class DefaultMMRotateDemoInput(DefaultMMDemoInput): + """Default demo input generator for mmrotate models.""" + + def _get_mm_data(self, model, input_shape, training=False): + """Helper for get_data, including core logic to generate demo input.""" + from mmrotate.testing._utils import demo_mm_inputs + + data = demo_mm_inputs(1, [input_shape[1:]], use_box_type=True) + data = model.data_preprocessor(data, training) + return data + + +@TASK_UTILS.register_module() +class DefaultMMYoloDemoInput(DefaultMMDetDemoInput): + """Default demo input generator for mmyolo models.""" + + default_shape = (1, 3, 125, 320) + + +@TASK_UTILS.register_module() +class DefaultMMPoseDemoInput(DefaultMMDemoInput): + """Default demo input generator for mmpose models.""" + + def _get_mm_data(self, model, input_shape, training=False): + from mmpose.models import TopdownPoseEstimator + + from .mmpose_demo_input import demo_mmpose_inputs + assert isinstance(model, TopdownPoseEstimator), f'{type(model)}' + + data = demo_mmpose_inputs(model, input_shape) + return data diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmpose_demo_input.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmpose_demo_input.py new file mode 100755 index 000000000..dbf5f2772 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmpose_demo_input.py @@ -0,0 +1,119 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""Include functions to generate mmpose demo inputs. + +Modified from mmpose. +""" + +import torch +from mmpose.models.heads import (CPMHead, DSNTHead, HeatmapHead, + IntegralRegressionHead, MSPNHead, + RegressionHead, RLEHead, SimCCHead, + ViPNASHead) +from mmpose.testing._utils import get_packed_inputs + +from mmrazor.utils import get_placeholder + +try: + from mmpose.models import PoseDataPreProcessor + from mmpose.structures import PoseDataSample +except ImportError: + PoseDataPreProcessor = get_placeholder('mmpose') + PoseDataSample = get_placeholder('mmpose') + + +def demo_mmpose_inputs(model, for_training=False, batch_size=1): + input_shape = ( + 1, + 3, + ) + model.head.decoder.input_size + imgs = torch.randn(*input_shape) + + batch_data_samples = [] + from mmpose.models.heads import RTMHead + if isinstance(model.head, HeatmapHead): + batch_data_samples = get_packed_inputs( + batch_size, + num_keypoints=model.head.out_channels, + heatmap_size=model.head.decoder.heatmap_size[::-1])['data_samples'] + elif isinstance(model.head, MSPNHead): + batch_data_samples = get_packed_inputs( + batch_size=batch_size, + num_instances=1, + num_keypoints=model.head.out_channels, + heatmap_size=model.head.decoder.heatmap_size, + with_heatmap=True, + with_reg_label=False, + num_levels=model.head.num_stages * + model.head.num_units)['data_samples'] + elif isinstance(model.head, CPMHead): + batch_data_samples = get_packed_inputs( + batch_size=batch_size, + num_instances=1, + num_keypoints=model.head.out_channels, + heatmap_size=model.head.decoder.heatmap_size[::-1], + with_heatmap=True, + with_reg_label=False)['data_samples'] + + elif isinstance(model.head, SimCCHead): + # bug + batch_data_samples = get_packed_inputs( + batch_size, + num_keypoints=model.head.out_channels, + simcc_split_ratio=model.head.decoder.simcc_split_ratio, + input_size=model.head.decoder.input_size, + with_simcc_label=True)['data_samples'] + + elif isinstance(model.head, ViPNASHead): + batch_data_samples = get_packed_inputs( + batch_size, + num_keypoints=model.head.out_channels, + )['data_samples'] + + elif isinstance(model.head, DSNTHead): + batch_data_samples = get_packed_inputs( + batch_size, + num_keypoints=model.head.num_joints, + with_reg_label=True)['data_samples'] + + elif isinstance(model.head, IntegralRegressionHead): + batch_data_samples = get_packed_inputs( + batch_size, + num_keypoints=model.head.num_joints, + with_reg_label=True)['data_samples'] + + elif isinstance(model.head, RegressionHead): + batch_data_samples = get_packed_inputs( + batch_size, + num_keypoints=model.head.num_joints, + with_reg_label=True)['data_samples'] + + elif isinstance(model.head, RLEHead): + batch_data_samples = get_packed_inputs( + batch_size, + num_keypoints=model.head.num_joints, + with_reg_label=True)['data_samples'] + + elif isinstance(model.head, RTMHead): + batch_data_samples = get_packed_inputs( + batch_size, + num_keypoints=model.head.out_channels, + simcc_split_ratio=model.head.decoder.simcc_split_ratio, + input_size=model.head.decoder.input_size, + with_simcc_label=True)['data_samples'] + + else: + raise AssertionError(f'Head Type {type(model.head)} is Not Predefined') + + mm_inputs = { + 'inputs': torch.FloatTensor(imgs), + 'data_samples': batch_data_samples + } + + # check data preprocessor + if not hasattr(model, + 'data_preprocessor') or model.data_preprocessor is None: + model.data_preprocessor = PoseDataPreProcessor() + + mm_inputs = model.data_preprocessor(mm_inputs, for_training) + + return mm_inputs diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmseg_demo_input.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmseg_demo_input.py new file mode 100755 index 000000000..49dcdf6b5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmseg_demo_input.py @@ -0,0 +1,81 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""Include functions to generate mmsegementation demo inputs. + +Modified from mmseg. +""" +import torch +from mmengine.structures import PixelData +from torch import nn + +from mmrazor.utils import get_placeholder + +try: + from mmseg.models import SegDataPreProcessor + from mmseg.structures import SegDataSample +except ImportError: + SegDataPreProcessor = get_placeholder('mmseg') + SegDataSample = get_placeholder('mmseg') + + +def demo_mmseg_inputs(segmentor, input_shape, for_training=False): + + if isinstance(segmentor.decode_head, nn.ModuleList): + num_classes = segmentor.decode_head[-1].num_classes + else: + num_classes = segmentor.decode_head.num_classes + # batch_size=2 for BatchNorm + mm_inputs = _demo_mmseg_inputs( + num_classes=num_classes, input_shape=input_shape) + + # convert to cuda Tensor if applicabled + # if torch.cuda.is_available(): + # segmentor = segmentor.cuda() + + # check data preprocessor + if not hasattr(segmentor, + 'data_preprocessor') or segmentor.data_preprocessor is None: + segmentor.data_preprocessor = SegDataPreProcessor() + + mm_inputs = segmentor.data_preprocessor(mm_inputs, for_training) + + return mm_inputs + + +def _demo_mmseg_inputs(input_shape=(1, 3, 8, 16), num_classes=10): + """Create a superset of inputs needed to run test or train batches. + + Args: + input_shape (tuple): + input batch dimensions + + num_classes (int): + number of semantic classes + """ + (N, C, H, W) = input_shape + + imgs = torch.randn(*input_shape) + segs = torch.randint( + low=0, high=num_classes - 1, size=(N, H, W), dtype=torch.long) + + img_metas = [{ + 'img_shape': (H, W), + 'ori_shape': (H, W), + 'pad_shape': (H, W, C), + 'filename': '.png', + 'scale_factor': 1.0, + 'flip': False, + 'flip_direction': 'horizontal' + } for _ in range(N)] + + data_samples = [ + SegDataSample( + gt_sem_seg=PixelData(data=segs[i]), metainfo=img_metas[i]) + for i in range(N) + ] + + mm_inputs = { + 'inputs': torch.FloatTensor(imgs), + 'data_samples': data_samples + } + + return mm_inputs diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/__init__.py new file mode 100755 index 000000000..f1cd00f8e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .counters import * # noqa: F401,F403 +from .resource_estimator import ResourceEstimator + +__all__ = ['ResourceEstimator'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/base_estimator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/base_estimator.py new file mode 100755 index 000000000..1a6f69264 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/base_estimator.py @@ -0,0 +1,51 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import ABCMeta, abstractmethod +from typing import Dict, Tuple, Union + +import torch.nn + +from mmrazor.registry import TASK_UTILS + + +@TASK_UTILS.register_module() +class BaseEstimator(metaclass=ABCMeta): + """The base class of Estimator, used for estimating model infos. + + Args: + input_shape (tuple): Input data's default shape, for calculating + resources consume. Defaults to (1, 3, 224, 224). + units (dict): A dict including required units. Default to dict(). + as_strings (bool): Output FLOPs and params counts in a string + form. Default to False. + """ + + def __init__(self, + input_shape: Tuple = (1, 3, 224, 224), + units: Dict = dict(), + as_strings: bool = False): + assert len(input_shape) in [ + 3, 4, 5 + ], ('The length of input_shape must be in [3, 4, 5]. ' + f'Got `{len(input_shape)}`.') + self.input_shape = input_shape + self.units = units + self.as_strings = as_strings + + @abstractmethod + def estimate(self, + model: torch.nn.Module, + flops_params_cfg: dict = None, + latency_cfg: dict = None) -> Dict[str, Union[float, str]]: + """Estimate the resources(flops/params/latency) of the given model. + + Args: + model: The measured model. + flops_params_cfg (dict): Cfg for estimating FLOPs and parameters. + Default to None. + latency_cfg (dict): Cfg for estimating latency. Default to None. + + Returns: + Dict[str, Union[float, str]]): A dict that contains the resource + results(FLOPs, params and latency). + """ + pass diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/__init__.py new file mode 100755 index 000000000..721987ec1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .flops_params_counter import get_model_flops_params +from .latency_counter import get_model_latency +from .op_counters import * # noqa: F401,F403 + +__all__ = ['get_model_flops_params', 'get_model_latency'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/flops_params_counter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/flops_params_counter.py new file mode 100755 index 000000000..4a3e44df0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/flops_params_counter.py @@ -0,0 +1,604 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import sys +from functools import partial +from typing import Dict, List + +import mmcv +import torch +import torch.nn as nn + +from mmrazor.registry import TASK_UTILS + +no_positional_input_warned = False + + +def get_model_flops_params(model, + input_shape=(1, 3, 224, 224), + spec_modules=[], + disabled_counters=[], + print_per_layer_stat=False, + units=dict(flops='M', params='M'), + as_strings=False, + seperate_return: bool = False, + input_constructor=None, + flush=False, + ost=sys.stdout): + """Get FLOPs and parameters of a model. This method can calculate FLOPs and + parameter counts of a model with corresponding input shape. It can also + print FLOPs and params for each layer in a model. Supported layers are + listed as below: + + - Convolutions: ``nn.Conv1d``, ``nn.Conv2d``, ``nn.Conv3d``. + - Activations: ``nn.ReLU``, ``nn.PReLU``, ``nn.ELU``, ``nn.LeakyReLU``, + ``nn.ReLU6``. + - Poolings: ``nn.MaxPool1d``, ``nn.MaxPool2d``, ``nn.MaxPool3d``, + ``nn.AvgPool1d``, ``nn.AvgPool2d``, ``nn.AvgPool3d``, + ``nn.AdaptiveMaxPool1d``, ``nn.AdaptiveMaxPool2d``, + ``nn.AdaptiveMaxPool3d``, ``nn.AdaptiveAvgPool1d``, + ``nn.AdaptiveAvgPool2d``, ``nn.AdaptiveAvgPool3d``. + - BatchNorms: ``nn.BatchNorm1d``, ``nn.BatchNorm2d``, + ``nn.BatchNorm3d``. + - Linear: ``nn.Linear``. + - Deconvolution: ``nn.ConvTranspose2d``. + - Upsample: ``nn.Upsample``. + + Args: + model (nn.Module): The model for complexity calculation. + input_shape (tuple): Input shape (including batchsize) used for + calculation. Default to (1, 3, 224, 224). + spec_modules (list): A list that contains the names of several spec + modules, which users want to get resources infos of them. + e.g., ['backbone', 'head'], ['backbone.layer1']. Default to []. + disabled_counters (list): One can limit which ops' spec would be + calculated. Default to []. + print_per_layer_stat (bool): Whether to print FLOPs and params + for each layer in a model. Default to True. + units (dict): A dict including converted FLOPs and params units. + Default to dict(flops='M', params='M'). + as_strings (bool): Output FLOPs and params counts in a string form. + Default to True. + seperate_return (bool): Whether to return the resource information + separately. Default to False. + input_constructor (None | callable): If specified, it takes a callable + method that generates input. otherwise, it will generate a random + tensor with input shape to calculate FLOPs. Default to None. + flush (bool): same as that in :func:`print`. Default to False. + ost (stream): same as ``file`` param in :func:`print`. + Default to sys.stdout. + + Returns: + tuple[float | str] | dict[str, float]: If `as_strings` is set to True, + it will return FLOPs and parameter counts in a string format. + Otherwise, it will return those in a float number format. + NOTE: If seperate_return, it will return a resource info dict with + FLOPs & params counts of each spec module in float|string format. + """ + assert type(input_shape) is tuple + assert len(input_shape) >= 1 + assert isinstance(model, nn.Module) + if seperate_return and not len(spec_modules): + raise AssertionError('`seperate_return` can only be set to True when ' + '`spec_modules` are not empty.') + + flops_params_model = add_flops_params_counting_methods(model) + flops_params_model.eval() + flops_params_model.start_flops_params_count(disabled_counters) + if input_constructor: + input = input_constructor(input_shape) + _ = flops_params_model(**input) + else: + try: + batch = torch.ones(()).new_empty( + tuple(input_shape), + dtype=next(flops_params_model.parameters()).dtype, + device=next(flops_params_model.parameters()).device) + except StopIteration: + # Avoid StopIteration for models which have no parameters, + # like `nn.Relu()`, `nn.AvgPool2d`, etc. + batch = torch.ones(()).new_empty(tuple(input_shape)) + + _ = flops_params_model(batch) + + flops_count, params_count = \ + flops_params_model.compute_average_flops_params_cost() + + if print_per_layer_stat: + print_model_with_flops_params( + flops_params_model, + flops_count, + params_count, + ost=ost, + flush=flush) + + if units is not None: + flops_count = params_units_convert(flops_count, units['flops']) + params_count = params_units_convert(params_count, units['params']) + + if as_strings: + flops_suffix = ' ' + units['flops'] + 'FLOPs' if units else ' FLOPs' + params_suffix = ' ' + units['params'] if units else '' + + if len(spec_modules): + flops_count, params_count = 0.0, 0.0 + module_names = [name for name, _ in flops_params_model.named_modules()] + for module in spec_modules: + assert module in module_names, \ + f'All modules in spec_modules should be in the measured ' \ + f'flops_params_model. Got module `{module}` in spec_modules.' + spec_modules_resources: Dict[str, dict] = dict() + accumulate_sub_module_flops_params(flops_params_model, units=units) + for name, module in flops_params_model.named_modules(): + if name in spec_modules: + spec_modules_resources[name] = dict() + spec_modules_resources[name]['flops'] = module.__flops__ + spec_modules_resources[name]['params'] = module.__params__ + flops_count += module.__flops__ + params_count += module.__params__ + if as_strings: + spec_modules_resources[name]['flops'] = \ + str(module.__flops__) + flops_suffix + spec_modules_resources[name]['params'] = \ + str(module.__params__) + params_suffix + + flops_params_model.stop_flops_params_count() + + if seperate_return: + return spec_modules_resources + + if as_strings: + flops_string = str(flops_count) + flops_suffix + params_string = str(params_count) + params_suffix + return flops_string, params_string + + return flops_count, params_count + + +def params_units_convert(num_params, units='M', precision=3): + """Convert parameter number with units. + + Args: + num_params (float): Parameter number to be converted. + units (str | None): Converted FLOPs units. Options are None, 'M', + 'K' and ''. If set to None, it will automatically choose the most + suitable unit for Parameter number. Default to None. + precision (int): Digit number after the decimal point. Default to 2. + + Returns: + str: The converted parameter number. + + Examples: + >>> params_units_convert(1e9) + '1000.0' + >>> params_units_convert(2e5) + '200.0' + >>> params_units_convert(3e-9) + '3e-09' + """ + + if units == 'G': + return round(num_params / 10.**9, precision) + elif units == 'M': + return round(num_params / 10.**6, precision) + elif units == 'K': + return round(num_params / 10.**3, precision) + else: + raise ValueError(f'Unsupported units convert: {units}') + + +def print_model_with_flops_params(model, + total_flops, + total_params, + units=dict(flops='M', params='M'), + precision=3, + ost=sys.stdout, + flush=False): + """Print a model with FLOPs and Params for each layer. + + Args: + model (nn.Module): The model to be printed. + total_flops (float): Total FLOPs of the model. + total_params (float): Total parameter counts of the model. + units (tuple | none): A tuple pair including converted FLOPs & params + units. e.g., ('G', 'M') stands for FLOPs as 'G' & params as 'M'. + Default to ('M', 'M'). + precision (int): Digit number after the decimal point. Default to 3. + ost (stream): same as `file` param in :func:`print`. + Default to sys.stdout. + flush (bool): same as that in :func:`print`. Default to False. + + Example: + >>> class ExampleModel(nn.Module): + >>> def __init__(self): + >>> super().__init__() + >>> self.conv1 = nn.Conv2d(3, 8, 3) + >>> self.conv2 = nn.Conv2d(8, 256, 3) + >>> self.conv3 = nn.Conv2d(256, 8, 3) + >>> self.avg_pool = nn.AdaptiveAvgPool2d((1, 1)) + >>> self.flatten = nn.Flatten() + >>> self.fc = nn.Linear(8, 1) + >>> def forward(self, x): + >>> x = self.conv1(x) + >>> x = self.conv2(x) + >>> x = self.conv3(x) + >>> x = self.avg_pool(x) + >>> x = self.flatten(x) + >>> x = self.fc(x) + >>> return x + >>> model = ExampleModel() + >>> x = (3, 16, 16) + to print the FLOPs and params state for each layer, you can use + >>> get_model_flops_params(model, x) + or directly use + >>> print_model_with_flops_params(model, 4579784.0, 37361) + ExampleModel( + 0.037 M, 100.000% Params, 0.005 GFLOPs, 100.000% FLOPs, + (conv1): Conv2d(0.0 M, 0.600% Params, 0.0 GFLOPs, 0.959% FLOPs, 3, 8, kernel_size=(3, 3), stride=(1, 1)) # noqa: E501 + (conv2): Conv2d(0.019 M, 50.020% Params, 0.003 GFLOPs, 58.760% FLOPs, 8, 256, kernel_size=(3, 3), stride=(1, 1)) + (conv3): Conv2d(0.018 M, 49.356% Params, 0.002 GFLOPs, 40.264% FLOPs, 256, 8, kernel_size=(3, 3), stride=(1, 1)) + (avg_pool): AdaptiveAvgPool2d(0.0 M, 0.000% Params, 0.0 GFLOPs, 0.017% FLOPs, output_size=(1, 1)) + (flatten): Flatten(0.0 M, 0.000% Params, 0.0 GFLOPs, 0.000% FLOPs, ) + (fc): Linear(0.0 M, 0.024% Params, 0.0 GFLOPs, 0.000% FLOPs, in_features=8, out_features=1, bias=True) + ) + """ + + def accumulate_params(self): + """Accumulate params by recursion.""" + if is_supported_instance(self): + return self.__params__ + else: + sum = 0 + for m in self.children(): + sum += m.accumulate_params() + return sum + + def accumulate_flops(self): + """Accumulate flops by recursion.""" + if is_supported_instance(self): + return self.__flops__ / model.__batch_counter__ + else: + sum = 0 + for m in self.children(): + sum += m.accumulate_flops() + return sum + + def flops_repr(self): + """A new extra_repr method of the input module.""" + accumulated_num_params = self.accumulate_params() + accumulated_flops_cost = self.accumulate_flops() + flops_string = str( + params_units_convert( + accumulated_flops_cost, units['flops'], + precision=precision)) + ' ' + units['flops'] + 'FLOPs' + params_string = str( + params_units_convert(accumulated_num_params, units['params'], + precision)) + ' M' + return ', '.join([ + params_string, + '{:.3%} Params'.format(accumulated_num_params / total_params), + flops_string, + '{:.3%} FLOPs'.format(accumulated_flops_cost / total_flops), + self.original_extra_repr() + ]) + + def add_extra_repr(m): + """Reload extra_repr method.""" + m.accumulate_flops = accumulate_flops.__get__(m) + m.accumulate_params = accumulate_params.__get__(m) + flops_extra_repr = flops_repr.__get__(m) + if m.extra_repr != flops_extra_repr: + m.original_extra_repr = m.extra_repr + m.extra_repr = flops_extra_repr + assert m.extra_repr != m.original_extra_repr + + def del_extra_repr(m): + """Recover origin extra_repr method.""" + if hasattr(m, 'original_extra_repr'): + m.extra_repr = m.original_extra_repr + del m.original_extra_repr + if hasattr(m, 'accumulate_flops'): + del m.accumulate_flops + + model.apply(add_extra_repr) + print(model, file=ost, flush=flush) + model.apply(del_extra_repr) + + +def accumulate_sub_module_flops_params(model, units=None): + """Accumulate FLOPs and params for each module in the model. Each module in + the model will have the `__flops__` and `__params__` parameters. + + Args: + model (nn.Module): The model to be accumulated. + units (tuple | none): A tuple pair including converted FLOPs & params + units. e.g., ('G', 'M') stands for FLOPs as 'G' & params as 'M'. + Default to None. + """ + + def accumulate_params(module): + """Accumulate params by recursion.""" + if is_supported_instance(module): + return module.__params__ + else: + sum = 0 + for m in module.children(): + sum += accumulate_params(m) + return sum + + def accumulate_flops(module): + """Accumulate flops by recursion.""" + if is_supported_instance(module): + return module.__flops__ / model.__batch_counter__ + else: + sum = 0 + for m in module.children(): + sum += accumulate_flops(m) + return sum + + for module in model.modules(): + _flops = accumulate_flops(module) + _params = accumulate_params(module) + module.__flops__ = _flops + module.__params__ = _params + if units is not None: + module.__flops__ = params_units_convert(_flops, units['flops']) + module.__params__ = params_units_convert(_params, units['params']) + + +def get_model_parameters_number(model): + """Calculate parameter number of a model. + + Args: + model (nn.module): The model for parameter number calculation. + + Returns: + float: Parameter number of the model. + """ + num_params = sum(p.numel() for p in model.parameters() if p.requires_grad) + return num_params + + +def add_flops_params_counting_methods(net_main_module): + """Add additional methods to the existing module object. + + This is done this way so that each function has access to self object. + """ + net_main_module.start_flops_params_count = start_flops_params_count.__get__( # noqa: E501 + net_main_module) + net_main_module.stop_flops_params_count = stop_flops_params_count.__get__( + net_main_module) + net_main_module.reset_flops_params_count = reset_flops_params_count.__get__( # noqa: E501 + net_main_module) + net_main_module.compute_average_flops_params_cost = compute_average_flops_params_cost.__get__( # noqa: E501 + net_main_module) + + net_main_module.reset_flops_params_count() + + return net_main_module + + +def compute_average_flops_params_cost(self): + """Compute average FLOPs and Params cost. + + A method to compute average FLOPs cost, which will be available after + `add_flops_params_counting_methods()` is called on a desired net object. + + Returns: + float: Current mean flops consumption per image. + """ + batches_count = self.__batch_counter__ + flops_sum = 0 + params_sum = 0 + for module in self.modules(): + if is_supported_instance(module): + flops_sum += module.__flops__ + params_sum += module.__params__ + return flops_sum / batches_count, params_sum + + +def start_flops_params_count(self, disabled_counters): + """Activate the computation of mean flops and params consumption per image. + + A method to activate the computation of mean flops consumption per image. + which will be available after ``add_flops_params_counting_methods()`` is + called on a desired net object. It should be called before running the + network. + """ + add_batch_counter_hook_function(self) + + def add_flops_params_counter_hook_function(module): + if is_supported_instance(module): + if hasattr(module, '__flops_params_handle__'): + return + + else: + counter_type = get_counter_type(module) + if (disabled_counters is None + or counter_type not in disabled_counters): + counter = TASK_UTILS.build( + dict(type=counter_type, _scope_='mmrazor')) + handle = module.register_forward_hook( + counter.add_count_hook) + + module.__flops_params_handle__ = handle + else: + return + + self.apply(partial(add_flops_params_counter_hook_function)) + + +def stop_flops_params_count(self): + """Stop computing the mean flops and params consumption per image. + + A method to stop computing the mean flops consumption per image, which will + be available after ``add_flops_params_counting_methods()`` is called on a + desired net object. It can be called to pause the computation whenever. + """ + remove_batch_counter_hook_function(self) + self.apply(remove_flops_params_counter_hook_function) + + +def reset_flops_params_count(self): + """Reset statistics computed so far. + + A method to Reset computed statistics, which will be available after + `add_flops_params_counting_methods()` is called on a desired net object. + """ + add_batch_counter_variables_or_reset(self) + self.apply(add_flops_params_counter_variable_or_reset) + + +# ---- Internal functions +def empty_flops_params_counter_hook(module, input, output): + """Empty flops and params variables of the module.""" + module.__flops__ += 0 + module.__params__ += 0 + + +def add_batch_counter_variables_or_reset(module): + """Add or reset the batch counter variable.""" + module.__batch_counter__ = 0 + + +def add_batch_counter_hook_function(module): + """Register the batch counter hook for the module.""" + if hasattr(module, '__batch_counter_handle__'): + return + + handle = module.register_forward_hook(batch_counter_hook) + module.__batch_counter_handle__ = handle + + +def batch_counter_hook(module, input, output): + """Add batch counter variable based on the input size.""" + batch_size = 1 + if len(input) > 0: + # Can have multiple inputs, getting the first one + input = input[0] + batch_size = len(input) + else: + global no_positional_input_warned + if no_positional_input_warned: + pass + else: + print('Warning! No positional inputs found for a module, ' + 'assuming batch size is 1.') + no_positional_input_warned = True + module.__batch_counter__ += batch_size + + +def remove_batch_counter_hook_function(module): + """Remove batch counter handle variable.""" + if hasattr(module, '__batch_counter_handle__'): + module.__batch_counter_handle__.remove() + del module.__batch_counter_handle__ + + +def add_flops_params_counter_variable_or_reset(module): + """Add or reset flops and params variable of the module.""" + if is_supported_instance(module): + if hasattr(module, '__flops__') or hasattr(module, '__params__'): + print('Warning: variables __flops__ or __params__ are already ' + 'defined for the module' + type(module).__name__ + + ' ptflops can affect your code!') + module.__flops__ = 0 + module.__params__ = 0 + + +counter_warning_list = [] + + +def get_counter_type(module) -> str: + """Get counter type of the module based on the module class name. + + If the current module counter_type is not in TASK_UTILS._module_dict, + it will search the base classes of the module to see if it matches any + base class counter_type. + + Returns: + str: Counter type (or the base counter type) of the current module. + """ + counter_type = module.__class__.__name__ + 'Counter' + if counter_type not in TASK_UTILS._module_dict.keys(): + old_counter_type = counter_type + assert nn.Module in module.__class__.mro() + for base_cls in module.__class__.mro(): + if base_cls in get_modules_list(): + counter_type = base_cls.__name__ + 'Counter' + global counter_warning_list + if old_counter_type not in counter_warning_list: + from mmengine import MMLogger + logger = MMLogger.get_current_instance() + logger.warning(f'`{old_counter_type}` not in op_counters. ' + f'Using `{counter_type}` instead.') + counter_warning_list.append(old_counter_type) + break + return counter_type + + +def is_supported_instance(module): + """Judge whether the module is in TASK_UTILS registry or not.""" + if get_counter_type(module) in TASK_UTILS._module_dict.keys(): + return True + return False + + +def remove_flops_params_counter_hook_function(module): + """Remove counter related variables after resource estimation.""" + if hasattr(module, '__flops_params_handle__'): + module.__flops_params_handle__.remove() + del module.__flops_params_handle__ + if hasattr(module, '__flops__'): + del module.__flops__ + if hasattr(module, '__params__'): + del module.__params__ + + +def get_modules_list() -> List: + return [ + # convolutions + nn.Conv1d, + nn.Conv2d, + nn.Conv3d, + mmcv.cnn.bricks.Conv2d, + mmcv.cnn.bricks.Conv3d, + # activations + nn.ReLU, + nn.PReLU, + nn.ELU, + nn.LeakyReLU, + nn.ReLU6, + # poolings + nn.MaxPool1d, + nn.AvgPool1d, + nn.AvgPool2d, + nn.MaxPool2d, + nn.MaxPool3d, + nn.AvgPool3d, + mmcv.cnn.bricks.MaxPool2d, + mmcv.cnn.bricks.MaxPool3d, + nn.AdaptiveMaxPool1d, + nn.AdaptiveAvgPool1d, + nn.AdaptiveMaxPool2d, + nn.AdaptiveAvgPool2d, + nn.AdaptiveMaxPool3d, + nn.AdaptiveAvgPool3d, + # normalizations + nn.BatchNorm1d, + nn.BatchNorm2d, + nn.BatchNorm3d, + nn.GroupNorm, + nn.InstanceNorm1d, + nn.InstanceNorm2d, + nn.InstanceNorm3d, + nn.LayerNorm, + # FC + nn.Linear, + mmcv.cnn.bricks.Linear, + # Upscale + nn.Upsample, + nn.UpsamplingNearest2d, + nn.UpsamplingBilinear2d, + # Deconvolution + nn.ConvTranspose2d, + mmcv.cnn.bricks.ConvTranspose2d, + ] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/latency_counter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/latency_counter.py new file mode 100755 index 000000000..a4241e313 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/latency_counter.py @@ -0,0 +1,135 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import logging +import time +from typing import Tuple, Union + +import torch +from mmengine.logging import print_log + + +def get_model_latency(model: torch.nn.Module, + input_shape: Tuple = (1, 3, 224, 224), + unit: str = 'ms', + as_strings: bool = False, + max_iter: int = 100, + num_warmup: int = 5, + log_interval: int = 100, + repeat_num: int = 1) -> Union[float, str]: + """Repeat speed measure for multi-times to get more precise results. + + Args: + model (torch.nn.Module): The measured model. + input_shape (tuple): Input shape (including batchsize) used for + calculation. Default to (1, 3, 224, 224). + unit (str): Unit of latency in string format. Default to 'ms'. + as_strings (bool): Output latency counts in a string form. + Default to False. + max_iter (Optional[int]): Max iteration num for the measurement. + Default to 100. + num_warmup (Optional[int]): Iteration num for warm-up stage. + Default to 5. + log_interval (Optional[int]): Interval num for logging the results. + Default to 100. + repeat_num (Optional[int]): Num of times to repeat the measurement. + Default to 1. + + Returns: + latency (Union[float, str]): The measured inference speed of the model. + if ``as_strings=True``, it will return latency in string format. + """ + assert repeat_num >= 1 + + fps_list = [] + + for _ in range(repeat_num): + fps_list.append( + _get_model_latency(model, input_shape, max_iter, num_warmup, + log_interval)) + + latency = round(1000 / fps_list[0], 1) + + if repeat_num > 1: + _fps_list = [round(fps, 1) for fps in fps_list] + times_per_img_list = [round(1000 / fps, 1) for fps in fps_list] + _mean_fps = sum(_fps_list) / len(_fps_list) + mean_times_per_img = sum(times_per_img_list) / len(times_per_img_list) + print_log( + f'Overall fps: {_fps_list}[{_mean_fps:.1f}] img / s, ' + f'times per image: ' + f'{times_per_img_list}[{mean_times_per_img:.1f}] ms/img', + logger='current', + level=logging.DEBUG) + latency = mean_times_per_img + + if as_strings: + latency = str(latency) + ' ' + unit # type: ignore + + return latency + + +def _get_model_latency(model: torch.nn.Module, + input_shape: Tuple = (1, 3, 224, 224), + max_iter: int = 100, + num_warmup: int = 5, + log_interval: int = 100) -> float: + """Measure inference speed on GPU devices. + + Args: + model (torch.nn.Module): The measured model. + input_shape (tuple): Input shape (including batchsize) used for + calculation. Default to (1, 3, 224, 224). + max_iter (Optional[int]): Max iteration num for the measurement. + Default to 100. + num_warmup (Optional[int]): Iteration num for warm-up stage. + Default to 5. + log_interval (Optional[int]): Interval num for logging the results. + Default to 100. + + Returns: + fps (float): The measured inference speed of the model. + """ + # the first several iterations may be very slow so skip them + pure_inf_time = 0.0 + fps = 0.0 + data = dict() + if next(model.parameters()).is_cuda: + device = 'cuda' + else: + raise NotImplementedError('To use cpu to test latency not supported.') + + # benchmark with {max_iter} image and take the average + for i in range(1, max_iter): + if device == 'cuda': + data = torch.rand(input_shape).cuda() + torch.cuda.synchronize() + start_time = time.perf_counter() + + with torch.no_grad(): + model(data) + + torch.cuda.synchronize() + elapsed = time.perf_counter() - start_time + + if i >= num_warmup: + pure_inf_time += elapsed + if (i + 1) % log_interval == 0: + fps = (i + 1 - num_warmup) / pure_inf_time + print_log( + f'Done image [{i + 1:<3}/ {max_iter}], ' + f'fps: {fps:.1f} img / s, ' + f'times per image: {1000 / fps:.1f} ms / img', + logger='current', + level=logging.DEBUG) + + if (i + 1) == max_iter: + fps = (i + 1 - num_warmup) / pure_inf_time + print_log( + f'Overall fps: {fps:.1f} img / s, ' + f'times per image: {1000 / fps:.1f} ms / img', + logger='current', + level=logging.DEBUG) + break + + torch.cuda.empty_cache() + + return fps diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/__init__.py new file mode 100755 index 000000000..5226a7047 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/__init__.py @@ -0,0 +1,25 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .activation_layer_counter import (ELUCounter, LeakyReLUCounter, + PReLUCounter, ReLU6Counter, ReLUCounter) +from .base_counter import BaseCounter +from .conv_layer_counter import (Conv1dCounter, Conv2dCounter, Conv3dCounter, + DynamicConv2dCounter) +from .deconv_layer_counter import ConvTranspose2dCounter +from .linear_layer_counter import DynamicLinearCounter, LinearCounter +from .norm_layer_counter import (BatchNorm1dCounter, BatchNorm2dCounter, + BatchNorm3dCounter, DMCPBatchNorm2dCounter, + GroupNormCounter, InstanceNorm1dCounter, + InstanceNorm2dCounter, InstanceNorm3dCounter, + LayerNormCounter) +from .pooling_layer_counter import * # noqa: F403, F405, F401 +from .upsample_layer_counter import UpsampleCounter + +__all__ = [ + 'ReLUCounter', 'PReLUCounter', 'ELUCounter', 'LeakyReLUCounter', + 'ReLU6Counter', 'BatchNorm1dCounter', 'BatchNorm2dCounter', + 'BatchNorm3dCounter', 'Conv1dCounter', 'Conv2dCounter', 'Conv3dCounter', + 'ConvTranspose2dCounter', 'UpsampleCounter', 'LinearCounter', + 'GroupNormCounter', 'InstanceNorm1dCounter', 'InstanceNorm2dCounter', + 'InstanceNorm3dCounter', 'LayerNormCounter', 'BaseCounter', + 'DMCPBatchNorm2dCounter', 'DynamicConv2dCounter', 'DynamicLinearCounter' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/activation_layer_counter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/activation_layer_counter.py new file mode 100755 index 000000000..e32aa5526 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/activation_layer_counter.py @@ -0,0 +1,40 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmrazor.registry import TASK_UTILS +from ..flops_params_counter import get_model_parameters_number +from .base_counter import BaseCounter + + +@TASK_UTILS.register_module() +class ReLUCounter(BaseCounter): + """FLOPs/params counter for ReLU series activate function.""" + + @staticmethod + def add_count_hook(module, input, output): + """Calculate FLOPs and params based on the size of input & output.""" + active_elements_count = output.numel() + module.__flops__ += int(active_elements_count) + module.__params__ += get_model_parameters_number(module) + + +@TASK_UTILS.register_module() +class PReLUCounter(ReLUCounter): + """FLOPs/params counter for PReLU function.""" + pass + + +@TASK_UTILS.register_module() +class ELUCounter(ReLUCounter): + """FLOPs/params counter for ELU function.""" + pass + + +@TASK_UTILS.register_module() +class LeakyReLUCounter(ReLUCounter): + """FLOPs/params counter for LeakyReLU function.""" + pass + + +@TASK_UTILS.register_module() +class ReLU6Counter(ReLUCounter): + """FLOPs/params counter for ReLU6 function.""" + pass diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/base_counter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/base_counter.py new file mode 100755 index 000000000..46baee933 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/base_counter.py @@ -0,0 +1,28 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import ABCMeta, abstractclassmethod + + +class BaseCounter(object, metaclass=ABCMeta): + """Base class of all op module counters in `TASK_UTILS`. + + In ResourceEstimator, `XXModuleCounter` is responsible for `XXModule`, + which refers to estimator/flops_params_counter.py::get_counter_type(). + Users can customize a `ModuleACounter` and overwrite the `add_count_hook` + method with a self-defined module `ModuleA`. + """ + + def __init__(self) -> None: + pass + + @staticmethod + @abstractclassmethod + def add_count_hook(module, input, output): + """The main method of a `BaseCounter` which defines the way to + calculate resources(flops/params) of the current module. + + Args: + module (nn.Module): the module to be tested. + input (_type_): input_tensor. Plz refer to `torch forward_hook` + output (_type_): output_tensor. Plz refer to `torch forward_hook` + """ + pass diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/conv_layer_counter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/conv_layer_counter.py new file mode 100755 index 000000000..d410e398e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/conv_layer_counter.py @@ -0,0 +1,115 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np + +from mmrazor.models.architectures.dynamic_ops import DynamicConv2d +from mmrazor.registry import TASK_UTILS +from .base_counter import BaseCounter + + +class ConvCounter(BaseCounter): + """FLOPs/params counter for Conv module series.""" + + @staticmethod + def add_count_hook(module, input, output): + """Calculate FLOPs and params based on the size of input & output.""" + # Can have multiple inputs, getting the first one + input = input[0] + + batch_size = input.shape[0] + output_dims = list(output.shape[2:]) + + kernel_dims = list(module.kernel_size) + in_channels = module.in_channels + out_channels = module.out_channels + groups = module.groups + + filters_per_channel = out_channels / groups + conv_per_position_flops = int( + np.prod(kernel_dims)) * in_channels * filters_per_channel + + active_elements_count = batch_size * int(np.prod(output_dims)) + + overall_conv_flops = conv_per_position_flops * active_elements_count + overall_params = conv_per_position_flops + + bias_flops = 0 + overall_params = conv_per_position_flops + if module.bias is not None: + bias_flops = out_channels * active_elements_count + overall_params += out_channels + + overall_flops = overall_conv_flops + bias_flops + + module.__flops__ += overall_flops + module.__params__ += int(overall_params) + + +@TASK_UTILS.register_module() +class Conv1dCounter(ConvCounter): + """FLOPs/params counter for Conv1d module.""" + pass + + +@TASK_UTILS.register_module() +class Conv2dCounter(ConvCounter): + """FLOPs/params counter for Conv2d module.""" + pass + + +@TASK_UTILS.register_module() +class Conv3dCounter(ConvCounter): + """FLOPs/params counter for Conv3d module.""" + pass + + +@TASK_UTILS.register_module() +class DynamicConv2dCounter(ConvCounter): + + @staticmethod + def add_count_hook(module: DynamicConv2d, input, output): + """Calculate FLOPs and params based on the dynamic channels of conv + layers.""" + input = input[0] + + batch_size = input.shape[0] + output_dims = list(output.shape[2:]) + + kernel_dims = list(module.kernel_size) + + if 'out_channels' in module.mutable_attrs: + out_channels = module.mutable_attrs[ + 'out_channels'].activated_channels + mutable_channel = list( + module.mutable_attrs['out_channels'].mutable_channels.values()) + if len(mutable_channel) > 0 and hasattr( + mutable_channel[0], 'activated_tensor_channels'): + out_channels = mutable_channel[0].activated_tensor_channels + else: + out_channels = module.out_channels + if 'in_channels' in module.mutable_attrs: + in_channels = module.mutable_attrs[ + 'in_channels'].activated_channels + else: + in_channels = module.in_channels + + groups = module.groups + + filters_per_channel = out_channels / groups + conv_per_position_flops = \ + np.prod(kernel_dims) * in_channels * filters_per_channel + + active_elements_count = batch_size * int(np.prod(output_dims)) + + overall_conv_flops = conv_per_position_flops * active_elements_count + overall_params = conv_per_position_flops + + bias_flops = 0 + overall_params = conv_per_position_flops + if module.bias is not None: + bias_flops = out_channels * active_elements_count + overall_params += out_channels + + overall_flops = overall_conv_flops + bias_flops + + module.__flops__ += overall_flops + module.__params__ += int(overall_params) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/deconv_layer_counter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/deconv_layer_counter.py new file mode 100755 index 000000000..0426fbb4b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/deconv_layer_counter.py @@ -0,0 +1,39 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmrazor.registry import TASK_UTILS +from ..flops_params_counter import get_model_parameters_number +from .base_counter import BaseCounter + + +@TASK_UTILS.register_module() +class ConvTranspose2dCounter(BaseCounter): + """FLOPs/params counter for Deconv module series.""" + + @staticmethod + def add_count_hook(module, input, output): + """Compute FLOPs and params based on the size of input & output.""" + # Can have multiple inputs, getting the first one + input = input[0] + + batch_size = input.shape[0] + input_height, input_width = input.shape[2:] + + # TODO: use more common representation + kernel_height, kernel_width = module.kernel_size + in_channels = module.in_channels + out_channels = module.out_channels + groups = module.groups + + filters_per_channel = out_channels // groups + conv_per_position_flops = ( + kernel_height * kernel_width * in_channels * filters_per_channel) + + active_elements_count = batch_size * input_height * input_width + overall_conv_flops = conv_per_position_flops * active_elements_count + bias_flops = 0 + if module.bias is not None: + output_height, output_width = output.shape[2:] + bias_flops = out_channels * batch_size * output_height * output_height # noqa: E501 + overall_flops = overall_conv_flops + bias_flops + + module.__flops__ += int(overall_flops) + module.__params__ += get_model_parameters_number(module) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/group_fisher_counters.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/group_fisher_counters.py new file mode 100755 index 000000000..7e85c33ae --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/group_fisher_counters.py @@ -0,0 +1,7 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This file includes the modules in the impl folder. + +As it only records impl modules, it is not initialized automatically. +""" +from mmrazor.implementations.pruning.group_fisher import ( # noqa + GroupFisherConv2dCounter, GroupFisherLinearCounter) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/linear_layer_counter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/linear_layer_counter.py new file mode 100755 index 000000000..80c024c09 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/linear_layer_counter.py @@ -0,0 +1,25 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np + +from mmrazor.registry import TASK_UTILS +from ..flops_params_counter import get_model_parameters_number +from .base_counter import BaseCounter + + +@TASK_UTILS.register_module() +class LinearCounter(BaseCounter): + """FLOPs/params counter for Linear operation series.""" + + @staticmethod + def add_count_hook(module, input, output): + """Calculate FLOPs and params based on the size of input & output.""" + input = input[0] + output_last_dim = output.shape[ + -1] # pytorch checks dimensions, so here we don't care much + module.__flops__ += int(np.prod(input.shape) * output_last_dim) + module.__params__ += get_model_parameters_number(module) + + +@TASK_UTILS.register_module() +class DynamicLinearCounter(LinearCounter): + pass diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/norm_layer_counter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/norm_layer_counter.py new file mode 100755 index 000000000..54f3f26d2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/norm_layer_counter.py @@ -0,0 +1,91 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np + +from mmrazor.registry import TASK_UTILS +from ..flops_params_counter import get_model_parameters_number +from .base_counter import BaseCounter + + +class BNCounter(BaseCounter): + """FLOPs/params counter for BatchNormalization series.""" + + @staticmethod + def add_count_hook(module, input, output): + """Calculate FLOPs and params based on the size of input & output.""" + input = input[0] + batch_flops = np.prod(input.shape) + if getattr(module, 'affine', False): + batch_flops *= 2 + module.__flops__ += int(batch_flops) + module.__params__ += get_model_parameters_number(module) + + +@TASK_UTILS.register_module() +class BatchNorm1dCounter(BNCounter): + """FLOPs/params counter for BatchNorm1d module.""" + pass + + +@TASK_UTILS.register_module() +class BatchNorm2dCounter(BNCounter): + """FLOPs/params counter for BatchNorm2d module.""" + pass + + +@TASK_UTILS.register_module() +class BatchNorm3dCounter(BNCounter): + """FLOPs/params counter for BatchNorm3d module.""" + pass + + +@TASK_UTILS.register_module() +class InstanceNorm1dCounter(BNCounter): + """FLOPs/params counter for InstanceNorm1d module.""" + pass + + +@TASK_UTILS.register_module() +class InstanceNorm2dCounter(BNCounter): + """FLOPs/params counter for InstanceNorm2d module.""" + pass + + +@TASK_UTILS.register_module() +class InstanceNorm3dCounter(BNCounter): + """FLOPs/params counter for InstanceNorm3d module.""" + pass + + +@TASK_UTILS.register_module() +class LayerNormCounter(BNCounter): + """FLOPs/params counter for LayerNorm module.""" + pass + + +@TASK_UTILS.register_module() +class GroupNormCounter(BNCounter): + """FLOPs/params counter for GroupNorm module.""" + pass + + +@TASK_UTILS.register_module() +class DMCPBatchNorm2dCounter(BNCounter): + """FLOPs/params counter for DynamicBatchNorm2d module.""" + + @staticmethod + def add_count_hook(module, input, output): + """Calculate FLOPs and params based on the size of input & output.""" + input = input[0] + B, C, H, W = input.shape + + mutable_channel = list( + module.mutable_attrs['num_features'].mutable_channels.values()) + if hasattr(mutable_channel[0], 'activated_tensor_channels'): + C = mutable_channel[0].activated_tensor_channels + + batch_flops = B * C * H * W + if getattr(module, 'affine', False): + batch_flops *= 2 + num_features = module.mutable_attrs['num_features'].activated_channels + module.__flops__ += batch_flops + module.__params__ += num_features * 2 diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/pooling_layer_counter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/pooling_layer_counter.py new file mode 100755 index 000000000..27d9b605f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/pooling_layer_counter.py @@ -0,0 +1,89 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np + +from mmrazor.registry import TASK_UTILS +from ..flops_params_counter import get_model_parameters_number +from .base_counter import BaseCounter + + +class PoolCounter(BaseCounter): + """FLOPs/params counter for Pooling series.""" + + @staticmethod + def add_count_hook(module, input, output): + """Calculate FLOPs and params based on the size of input & output.""" + input = input[0] + module.__flops__ += int(np.prod(input.shape)) + module.__params__ += get_model_parameters_number(module) + + +@TASK_UTILS.register_module() +class MaxPool1dCounter(PoolCounter): + """FLOPs/params counter for MaxPool1d module.""" + pass + + +@TASK_UTILS.register_module() +class MaxPool2dCounter(PoolCounter): + """FLOPs/params counter for MaxPool2d module.""" + pass + + +@TASK_UTILS.register_module() +class MaxPool3dCounter(PoolCounter): + """FLOPs/params counter for MaxPool3d module.""" + pass + + +@TASK_UTILS.register_module() +class AvgPool1dCounter(PoolCounter): + """FLOPs/params counter for AvgPool1d module.""" + pass + + +@TASK_UTILS.register_module() +class AvgPool2dCounter(PoolCounter): + """FLOPs/params counter for AvgPool2d module.""" + pass + + +@TASK_UTILS.register_module() +class AvgPool3dCounter(PoolCounter): + """FLOPs/params counter for AvgPool3d module.""" + pass + + +@TASK_UTILS.register_module() +class AdaptiveMaxPool1dCounter(PoolCounter): + """FLOPs/params counter for AdaptiveMaxPool1d module.""" + pass + + +@TASK_UTILS.register_module() +class AdaptiveMaxPool2dCounter(PoolCounter): + """FLOPs/params counter for AdaptiveMaxPool2d module.""" + pass + + +@TASK_UTILS.register_module() +class AdaptiveMaxPool3dCounter(PoolCounter): + """FLOPs/params counter for AdaptiveMaxPool3d module.""" + pass + + +@TASK_UTILS.register_module() +class AdaptiveAvgPool1dCounter(PoolCounter): + """FLOPs/params counter for AdaptiveAvgPool1d module.""" + pass + + +@TASK_UTILS.register_module() +class AdaptiveAvgPool2dCounter(PoolCounter): + """FLOPs/params counter for AdaptiveAvgPool2d module.""" + pass + + +@TASK_UTILS.register_module() +class AdaptiveAvgPool3dCounter(PoolCounter): + """FLOPs/params counter for AdaptiveAvgPool3d module.""" + pass diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/upsample_layer_counter.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/upsample_layer_counter.py new file mode 100755 index 000000000..12958b6d5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/upsample_layer_counter.py @@ -0,0 +1,20 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmrazor.registry import TASK_UTILS +from ..flops_params_counter import get_model_parameters_number +from .base_counter import BaseCounter + + +@TASK_UTILS.register_module() +class UpsampleCounter(BaseCounter): + """FLOPs/params counter for Upsample function.""" + + @staticmethod + def add_count_hook(module, input, output): + """Calculate FLOPs and params based on the size of input & output.""" + output_size = output[0] + batch_size = output_size.shape[0] + output_elements_count = batch_size + for val in output_size.shape[1:]: + output_elements_count *= val + module.__flops__ += int(output_elements_count) + module.__params__ += get_model_parameters_number(module) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/resource_estimator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/resource_estimator.py new file mode 100755 index 000000000..ac5292d0c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/resource_estimator.py @@ -0,0 +1,215 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional, Tuple, Union + +import torch.nn + +from mmrazor.registry import TASK_UTILS +from .base_estimator import BaseEstimator +from .counters import get_model_flops_params, get_model_latency + + +@TASK_UTILS.register_module() +class ResourceEstimator(BaseEstimator): + """Estimator for calculating the resources consume. + + Args: + input_shape (tuple): Input data's default shape, for calculating + resources consume. Defaults to (1, 3, 224, 224). + units (dict): Dict that contains converted FLOPs/params/latency units. + Default to dict(flops='M', params='M', latency='ms'). + as_strings (bool): Output FLOPs/params/latency counts in a string + form. Default to False. + flops_params_cfg (dict): Cfg for estimating FLOPs and parameters. + Default to None. + latency_cfg (dict): Cfg for estimating latency. Default to None. + + Examples: + >>> # direct calculate resource consume of nn.Conv2d + >>> conv2d = nn.Conv2d(3, 32, 3) + >>> estimator = ResourceEstimator(input_shape=(1, 3, 64, 64)) + >>> estimator.estimate(model=conv2d) + {'flops': 3.444, 'params': 0.001, 'latency': 0.0} + + >>> # direct calculate resource consume of nn.Conv2d + >>> conv2d = nn.Conv2d(3, 32, 3) + >>> estimator = ResourceEstimator() + >>> flops_params_cfg = dict(input_shape=(1, 3, 32, 32)) + >>> estimator.estimate(model=conv2d, flops_params_cfg) + {'flops': 0.806, 'params': 0.001, 'latency': 0.0} + + >>> # calculate resources of custom modules + >>> class CustomModule(nn.Module): + ... + ... def __init__(self) -> None: + ... super().__init__() + ... + ... def forward(self, x): + ... return x + ... + >>> @TASK_UTILS.register_module() + ... class CustomModuleCounter(BaseCounter): + ... + ... @staticmethod + ... def add_count_hook(module, input, output): + ... module.__flops__ += 1000000 + ... module.__params__ += 700000 + ... + >>> model = CustomModule() + >>> flops_params_cfg = dict(input_shape=(1, 3, 64, 64)) + >>> estimator.estimate(model=model, flops_params_cfg) + {'flops': 1.0, 'params': 0.7, 'latency': 0.0} + ... + >>> # calculate resources of custom modules with disable_counters + >>> flops_params_cfg = dict(input_shape=(1, 3, 64, 64), + ... disabled_counters=['CustomModuleCounter']) + >>> estimator.estimate(model=model, flops_params_cfg) + {'flops': 0.0, 'params': 0.0, 'latency': 0.0} + + >>> # calculate resources of mmrazor.models + NOTE: check 'EstimateResourcesHook' in + mmrazor.engine.hooks.estimate_resources_hook for details. + """ + + def __init__( + self, + input_shape: Tuple = (1, 3, 224, 224), + units: Dict = dict(flops='M', params='M', latency='ms'), + as_strings: bool = False, + flops_params_cfg: Optional[dict] = None, + latency_cfg: Optional[dict] = None, + ): + super().__init__(input_shape, units, as_strings) + if not isinstance(units, dict): + raise TypeError('units for estimator should be a dict', + f'but got `{type(units)}`') + for unit_key in units: + if unit_key not in ['flops', 'params', 'latency']: + raise KeyError(f'Got invalid key `{unit_key}` in units. ', + 'Should be `flops`, `params` or `latency`.') + if flops_params_cfg: + self.flops_params_cfg = flops_params_cfg + else: + self.flops_params_cfg = dict() + self.latency_cfg = latency_cfg if latency_cfg else dict() + + def estimate(self, + model: torch.nn.Module, + flops_params_cfg: dict = None, + latency_cfg: dict = None) -> Dict[str, Union[float, str]]: + """Estimate the resources(flops/params/latency) of the given model. + + This method will first parse the merged :attr:`self.flops_params_cfg` + and the :attr:`self.latency_cfg` to check whether the keys are valid. + + Args: + model: The measured model. + flops_params_cfg (dict): Cfg for estimating FLOPs and parameters. + Default to None. + latency_cfg (dict): Cfg for estimating latency. Default to None. + + NOTE: If the `flops_params_cfg` and `latency_cfg` are both None, + this method will only estimate FLOPs/params with default settings. + + Returns: + Dict[str, Union[float, str]]): A dict that contains the resource + results(FLOPs, params and latency). + """ + resource_metrics = dict() + measure_latency = True if latency_cfg else False + + if flops_params_cfg: + flops_params_cfg = {**self.flops_params_cfg, **flops_params_cfg} + self._check_flops_params_cfg(flops_params_cfg) + flops_params_cfg = self._set_default_resource_params( + flops_params_cfg) + else: + flops_params_cfg = self.flops_params_cfg + + if latency_cfg: + latency_cfg = {**self.latency_cfg, **latency_cfg} + self._check_latency_cfg(latency_cfg) + latency_cfg = self._set_default_resource_params(latency_cfg) + else: + latency_cfg = self.latency_cfg + + model.eval() + flops, params = get_model_flops_params(model, **flops_params_cfg) + if measure_latency: + latency = get_model_latency(model, **latency_cfg) + else: + latency = '0.0 ms' if self.as_strings else 0.0 # type: ignore + + resource_metrics.update({ + 'flops': flops, + 'params': params, + 'latency': latency + }) + return resource_metrics + + def estimate_separation_modules( + self, + model: torch.nn.Module, + flops_params_cfg: dict = None) -> Dict[str, Union[float, str]]: + """Estimate FLOPs and params of the spec modules with separate return. + + Args: + model: The measured model. + flops_params_cfg (dict): Cfg for estimating FLOPs and parameters. + Default to None. + + Returns: + Dict[str, Union[float, str]]): A dict that contains the FLOPs and + params results (string | float format) of each modules in the + ``flops_params_cfg['spec_modules']``. + """ + if flops_params_cfg: + flops_params_cfg = {**self.flops_params_cfg, **flops_params_cfg} + self._check_flops_params_cfg(flops_params_cfg) + flops_params_cfg = self._set_default_resource_params( + flops_params_cfg) + else: + flops_params_cfg = self.flops_params_cfg + flops_params_cfg['seperate_return'] = True + + assert len(flops_params_cfg['spec_modules']), ( + 'spec_modules can not be empty when calling ' + f'`estimate_separation_modules` of {self.__class__.__name__} ') + + model.eval() + spec_modules_resources = get_model_flops_params( + model, **flops_params_cfg) + return spec_modules_resources + + def _check_flops_params_cfg(self, flops_params_cfg: dict) -> None: + """Check the legality of ``flops_params_cfg``. + + Args: + flops_params_cfg (dict): Cfg for estimating FLOPs and parameters. + """ + for key in flops_params_cfg: + if key not in get_model_flops_params.__code__.co_varnames[ + 1:]: # type: ignore + raise KeyError(f'Got invalid key `{key}` in flops_params_cfg.') + + def _check_latency_cfg(self, latency_cfg: dict) -> None: + """Check the legality of ``latency_cfg``. + + Args: + latency_cfg (dict): Cfg for estimating latency. + """ + for key in latency_cfg: + if key not in get_model_latency.__code__.co_varnames[ + 1:]: # type: ignore + raise KeyError(f'Got invalid key `{key}` in latency_cfg.') + + def _set_default_resource_params(self, cfg: dict) -> dict: + """Set default attributes for the input cfgs. + + Args: + cfg (dict): flops_params_cfg or latency_cfg. + """ + default_common_settings = ['input_shape', 'units', 'as_strings'] + for key in default_common_settings: + if key not in cfg: + cfg[key] = getattr(self, key) + return cfg diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/__init__.py new file mode 100755 index 000000000..6caa0dbf8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .metric_predictor import MetricPredictor + +__all__ = ['MetricPredictor'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/__init__.py new file mode 100755 index 000000000..96337921d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/__init__.py @@ -0,0 +1,7 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .carts_handler import CartsHandler +from .gp_handler import GaussProcessHandler +from .mlp_handler import MLPHandler +from .rbf_handler import RBFHandler + +__all__ = ['CartsHandler', 'GaussProcessHandler', 'MLPHandler', 'RBFHandler'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/base_handler.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/base_handler.py new file mode 100755 index 000000000..40246ac3d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/base_handler.py @@ -0,0 +1,32 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from joblib import dump, load + + +class BaseHandler: + """Base class for a handler. + + Note: + The handler works through a specific machine leanring algorithm, + and is designed for predicting the evaluation metric of a model. + """ + + def __init__(self) -> None: + pass + + def fit(self, train_data, train_label): + """Training the model of handler.""" + pass + + def predict(self, test_data): + """Predicting the metric using the model of handler.""" + pass + + def load(self, path): + """Load pretrained weights for the handler.""" + self.model = load(path) + + def save(self, path): + """Save the handler and return saved path for diff suffix.""" + path += f'_{self.__class__.__name__}.joblib'.lower() + dump(self.model, path) + return path diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/carts_handler.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/carts_handler.py new file mode 100755 index 000000000..0c310c97f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/carts_handler.py @@ -0,0 +1,97 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List + +import numpy as np + +try: + from sklearn.tree import DecisionTreeRegressor +except ImportError: + from mmrazor.utils import get_placeholder + DecisionTreeRegressor = get_placeholder('sklearn') + +from mmrazor.registry import TASK_UTILS +from .base_handler import BaseHandler + + +@TASK_UTILS.register_module() +class CartsHandler(BaseHandler): + """Classification and Regression Tree. + + Args: + num_trees (int): number of regression trees. + """ + + def __init__(self, num_trees=1000): + self.num_trees = num_trees + + def fit(self, train_data: np.array, train_label: np.array) -> None: + """Define the model of handler. + + Args: + train_data (numpy.array): input data for training. + train_label (numpy.array): input label for training. + """ + self.model = self._make_decision_trees(train_data, train_label, + self.num_trees) + + def predict(self, test_data: np.array) -> np.array: + """Predict the evaluation metric of the model. + + Args: + test_data (numpy.array): input data for testing. + + Returns: + numpy.array: predicted metric. + """ + trees, features = self.model[0], self.model[1] + test_num, num_trees = len(test_data), len(trees) + + predict_labels = np.zeros((test_num, 1)) + for i in range(test_num): + this_test_data = test_data[i, :] + predict_this_list = np.zeros(num_trees) + + for j, (tree, feature) in enumerate(zip(trees, features)): + predict_this_list[j] = tree.predict([this_test_data[feature] + ])[0] + + predict_this_list = np.sort(predict_this_list) + predict_this_list = predict_this_list[::-1] + this_predict = np.mean(predict_this_list) + predict_labels[i, 0] = this_predict + + return predict_labels + + @staticmethod + def _make_decision_trees(train_data: np.array, train_label: np.array, + num_trees: int) -> List[list]: + """Construct the decision trees. + + Args: + train_data (numpy.array): input data for training. + train_label (numpy.array): input label for training. + num_trees (int): num of decision trees. + + Returns: + List[list]: List of built models. + """ + feature_record = [] + tree_record = [] + + for _ in range(num_trees): + sample_idx = np.arange(train_data.shape[0]) + np.random.shuffle(sample_idx) + train_data = train_data[sample_idx, :] + train_label = train_label[sample_idx] + + feature_idx = np.arange(train_data.shape[1]) + np.random.shuffle(feature_idx) + n_feature = np.random.randint(1, train_data.shape[1] + 1) + selected_feature_ids = feature_idx[0:n_feature] + feature_record.append(selected_feature_ids) + + dt = DecisionTreeRegressor() + dt.fit(train_data[:, selected_feature_ids], train_label) + tree_record.append(dt) + + return [tree_record, feature_record] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/gp_handler.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/gp_handler.py new file mode 100755 index 000000000..76f8aab67 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/gp_handler.py @@ -0,0 +1,129 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np + +try: + from pydacefit.dace import DACE + from pydacefit.fit import fit +except ImportError: + from mmrazor.utils import get_placeholder + DACE = get_placeholder('pydacefit') + fit = get_placeholder('pydacefit') + +from mmrazor.registry import TASK_UTILS +from .base_handler import BaseHandler + + +def get_pydacefit_func(): + """Build a function map from pydacefit.""" + from pydacefit.corr import (corr_cubic, corr_exp, corr_expg, corr_gauss, + corr_spherical, corr_spline) + from pydacefit.dace import regr_linear, regr_quadratic + from pydacefit.regr import regr_constant + + REGR = { + 'linear': regr_linear, + 'constant': regr_constant, + 'quadratic': regr_quadratic + } + + CORR = { + 'gauss': corr_gauss, + 'cubic': corr_cubic, + 'exp': corr_exp, + 'expg': corr_expg, + 'spline': corr_spline, + 'spherical': corr_spherical + } + + return REGR, CORR + + +class DACE_with_smooth(DACE): + """GP model.""" + + def __init__(self, + regr, + corr, + theta: float = 1.0, + thetaL: float = 0.0, + thetaU: float = 100.0): + super(DACE_with_smooth, self).__init__(regr, corr, theta, thetaL, + thetaU) + + def fit(self, X, Y): + """Build the model.""" + if len(Y.shape) == 1: + Y = Y[:, None] + + if X.shape[0] != Y.shape[0]: + raise Exception('X and Y must have the same number of rows.') + + mX, sX = np.mean(X, axis=0), np.std(X, axis=0, ddof=1) + 1e-6 + mY, sY = np.mean(Y, axis=0), np.std(Y, axis=0, ddof=1) + 1e-6 + + nX = (X - mX) / sX + nY = (Y - mY) / sY + + if self.tl is not None and self.tu is not None: + self.model = {'nX': nX, 'nY': nY} + self.boxmin() + self.model = self.itpar['best'] + else: + self.model = fit(nX, nY, self.regr, self.kernel, self.theta) + + self.model = { + **self.model, 'mX': mX, + 'sX': sX, + 'mY': mY, + 'sY': sY, + 'nX': nX, + 'nY': nY + } + self.model['sigma2'] = np.square(sY) @ self.model['_sigma2'] + + +@TASK_UTILS.register_module() +class GaussProcessHandler(BaseHandler): + """GaussProcess handler of the metric predictor. It uses Gaussian Process + (Kriging) to predict the metric of a trained model. + + Args: + regr (str): regression kernel for GP model. Defaults to 'linear'. + corr (str): correlation kernel for GP model. Defaults to 'gauss'. + """ + + def __init__(self, regr: str = 'linear', corr: str = 'gauss'): + REGR, CORR = get_pydacefit_func() + assert regr in REGR, \ + ValueError(f'`regr` should be in `REGR`. Got `{regr}`.') + assert corr in CORR, \ + ValueError(f'`corr` should be in `CORR`. Got `{corr}`.') + self.regr = REGR[regr] + self.corr = CORR[corr] + + self.model = DACE_with_smooth( + regr=self.regr, + corr=self.corr, + theta=1.0, + thetaL=0.00001, + thetaU=100) + + def fit(self, train_data: np.array, train_label: np.array) -> None: + """Training the model of handler. + + Args: + train_data (numpy.array): input data for training. + train_label (numpy.array): input label for training. + """ + self.model.fit(train_data, train_label) + + def predict(self, test_data: np.array) -> np.array: + """Predict the evaluation metric of the model. + + Args: + test_data (numpy.array): input data for testing. + + Returns: + numpy.array: predicted metric. + """ + return self.model.predict(test_data) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/mlp_handler.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/mlp_handler.py new file mode 100755 index 000000000..e1bd7975a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/mlp_handler.py @@ -0,0 +1,197 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict + +import numpy as np +import torch +import torch.nn as nn +import torch.optim as optim +from mmcv.cnn.bricks import build_activation_layer + +try: + from mmdet.models.losses import SmoothL1Loss +except ImportError: + from mmrazor.utils import get_placeholder + SmoothL1Loss = get_placeholder('mmdet') +from mmengine.model import BaseModule +from mmengine.optim.scheduler import CosineAnnealingLR + +from mmrazor.registry import TASK_UTILS +from .base_handler import BaseHandler + + +class MLP(BaseModule): + """MLP implemented with nn.Linear. + + Input: Tensor with shape [B, C, H, W]. + Output: Tensor with shape [B, C, H, W]. + + Args: + in_features (int): Dimension of input features. + hidden_features (int): Dimension of hidden features. + out_features (int): Dimension of output features. + act_cfg (dict): The config dict for activation between pointwise + convolution. Defaults to ``dict(type='ReLU')``. + drop (float): Dropout rate. Defaults to 0.0. + """ + + def __init__(self, + in_features: int = 78, + hidden_features: int = 300, + out_features: int = 1, + num_hidden_layers: int = 2, + act_cfg: Dict = dict(type='ReLU'), + drop: float = 0.): + super().__init__() + out_features = out_features or in_features + hidden_features = hidden_features or in_features + + self.fc1 = nn.Linear(in_features, hidden_features) + self.act = build_activation_layer(act_cfg) + + hidden_layers = [] + for _ in range(num_hidden_layers): + hidden_layers.append(nn.Linear(hidden_features, hidden_features)) + hidden_layers.append(build_activation_layer(act_cfg)) + self.hidden_layers = nn.Sequential(*hidden_layers) + + self.fc2 = nn.Linear(hidden_features, out_features) + self.drop = nn.Dropout(drop) + self.init_weights() + + def forward(self, x): + x = self.fc1(x) + x = self.act(x) + x = self.hidden_layers(x) + x = self.drop(x) + x = self.fc2(x) + return x + + +@TASK_UTILS.register_module() +class MLPHandler(BaseHandler): + """MLP handler of the metric predictor. It uses MLP network to predict the + metric of a trained model. + + Args: + epochs (int, optional): num of epochs for MLP network training. + Defaults to 100. + data_split_ratio (float, optional): split ratio of train/valid of + input data. Defaults to 0.8. + model_cfg (dict, optional): configs for MLP network. Defaults to None. + device (str, optional): device for MLP Handler. Defaults to 'cuda'. + """ + + def __init__(self, + epochs: int = 100, + data_split_ratio: float = 0.8, + model_cfg: Dict = None, + device: str = 'cpu'): + self.epochs = epochs + self.data_split_ratio = data_split_ratio + + self.model_cfg = model_cfg if model_cfg is not None else dict() + self.model = MLP(**self.model_cfg) + + self.device = device + + def fit(self, train_data: np.array, train_label: np.array) -> None: + """Training the model of handler. + + Args: + train_data (numpy.array): input data for training. + train_label (numpy.array): input label for training. + """ + if train_data.shape[1] != self.model.fc1.in_features: + self.model.fc1 = nn.Linear(train_data.shape[1], + self.model.fc1.out_features) + self.model = self.train_mlp(train_data, train_label) + + def predict(self, test_data: np.array) -> np.array: + """Predict the evaluation metric of the model. + + Args: + test_data (numpy.array): input data for testing. + + Returns: + numpy.array: predicted metric. + """ + if test_data.ndim < 2: + data = torch.zeros(1, test_data.shape[0]) + data[0, :] = torch.from_numpy(test_data).float() + else: + data = torch.from_numpy(test_data).float() + + self.model = self.model.to(device=self.device) + self.model.eval() + with torch.no_grad(): + data = data.to(device=self.device) + pred = self.model(data) + + return pred.cpu().detach().numpy() + + def load(self, path: str) -> None: + """Load predictor's pretrained weights.""" + self.model.load_state_dict( + torch.load(path, map_location='cpu')['state_dict']) + + def save(self, path: str) -> str: + """Save predictor and return saved path for diff suffix.""" + path = path + '_mlp.pth' + torch.save({'state_dict': self.model.state_dict(), 'meta': {}}, path) + return path + + def train_mlp(self, train_data: np.array, + train_label: np.array) -> nn.Module: + """Train MLP network. + + Args: + train_data (numpy.array): input data for training. + train_label (numpy.array): input label for training. + + Returns: + nn.Module: the well-trained MLP network. + """ + num_samples = train_data.shape[0] + target = torch.zeros(num_samples, 1) + perm = torch.randperm(target.size(0)) + train_index = perm[:int(num_samples * self.data_split_ratio)] + valid_index = perm[int(num_samples * self.data_split_ratio):] + + inputs = torch.from_numpy(train_data).float() + target[:, 0] = torch.from_numpy(train_label).float() + + self.model = self.model.to(device=self.device) + self.optimizer = optim.Adam(self.model.parameters(), lr=8e-4) + self.criterion = SmoothL1Loss() + + self.scheduler = CosineAnnealingLR( + self.optimizer, T_max=self.epochs, eta_min=0, by_epoch=True) + + best_loss = 1e33 + for _ in range(self.epochs): + train_inputs = inputs[train_index].to(self.device) + train_labels = target[train_index].to(self.device) + + self.model.train() + self.optimizer.zero_grad() + pred = self.model(train_inputs) + loss = self.criterion(pred, train_labels) + loss.backward() + self.optimizer.step() + + self.model.eval() + with torch.no_grad(): + valid_inputs = inputs[valid_index].to(self.device) + valid_labels = target[valid_index].to(self.device) + + pred = self.model(valid_inputs) + valid_loss = self.criterion(pred, valid_labels).item() + + self.scheduler.step() + + if valid_loss < best_loss: + best_loss = valid_loss + best_net = copy.deepcopy(self.model) + + return best_net.to(device='cpu') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/rbf_handler.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/rbf_handler.py new file mode 100755 index 000000000..39bec949d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/rbf_handler.py @@ -0,0 +1,68 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np + +try: + from pySOT.surrogate import RBFInterpolant +except ImportError: + from mmrazor.utils import get_placeholder + RBFInterpolant = get_placeholder('pySOT') + +from mmrazor.registry import TASK_UTILS +from .base_handler import BaseHandler + + +@TASK_UTILS.register_module() +class RBFHandler(BaseHandler): + """RBF handler of the metric predictor. It uses `Radial Basis Function` to + predict the metric of a trained model. + + Args: + kernel (str): RBF kernel object. Defaults to 'tps'. + tail (str): RBF polynomial tail object. Defaults to 'linear'. + """ + + def __init__(self, kernel: str = 'tps', tail: str = 'linear'): + from pySOT.surrogate import (ConstantTail, CubicKernel, Kernel, + LinearTail, Tail, TPSKernel) + + self.kernel_mapping = {'cubic': CubicKernel, 'tps': TPSKernel} + self.tail_mapping = {'linear': LinearTail, 'constant': ConstantTail} + + assert kernel in self.kernel_mapping.keys(), ( + f'Got unknown RBF kernel `{kernel}`.') + self.kernel: Kernel = self.kernel_mapping[kernel] + + assert tail in self.tail_mapping.keys(), ( + f'Got unknown RBF tail `{tail}`.') + self.tail: Tail = self.tail_mapping[tail] + + def fit(self, train_data: np.array, train_label: np.array) -> None: + """Training the model of handler. + + Args: + train_data (numpy.array): input data for training. + train_label (numpy.array): input label for training. + """ + if train_data.shape[0] <= train_data.shape[1]: + raise ValueError('In RBF, dim 0 of data (got ' + f'{train_data.shape[0]}) should be larger than ' + f'dim 1 of data (got {train_data.shape[1]}).') + + self.model = RBFInterpolant( + dim=train_data.shape[1], + kernel=self.kernel(), + tail=self.tail(train_data.shape[1])) + + for i in range(len(train_data)): + self.model.add_points(train_data[i, :], train_label[i]) + + def predict(self, test_data: np.array) -> np.array: + """Predict the evaluation metric of the model. + + Args: + test_data (numpy.array): input data for testing. + + Returns: + numpy.array: predicted metric. + """ + return self.model.predict(test_data) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/metric_predictor.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/metric_predictor.py new file mode 100755 index 000000000..796c3ac5b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/metric_predictor.py @@ -0,0 +1,223 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Union + +import numpy as np + +try: + import scipy.stats as stats +except ImportError: + from mmrazor.utils import get_placeholder + stats = get_placeholder('scipy') + +from mmrazor.registry import TASK_UTILS +from mmrazor.structures import export_fix_subnet +from mmrazor.utils.typing import DumpChosen +from .handler import RBFHandler + + +@TASK_UTILS.register_module() +class MetricPredictor: + """A predictor for predicting evaluation metrics in different tasks. + + Args: + handler_cfg (dict): Config to build a predict handler. + search_groups (dict) : The search_groups of the specified supernet. + train_samples (int): Num of training samples for the handler. + Defaults to 2. + handler_ckpt (str, optional): Path to handler's checkpoint. If given, + predictor will load weights directly instead of handler training. + encoding_type (str, optional): Type of how to encode the search space + to integer bit-string. Defaults to `onehot`. + score_key (str): Specify one metric in evaluation results to score + models. Defaults to 'accuracy_top-1'. + """ + + def __init__(self, + handler_cfg: Dict, + search_groups: Dict, + train_samples: int = 2, + handler_ckpt: str = None, + encoding_type: str = 'onehot', + score_key: str = 'accuracy_top-1', + **kwargs): + self.handler_cfg = handler_cfg + self.handler = TASK_UTILS.build(handler_cfg) + + assert encoding_type in [ + 'normal', 'onehot' + ], ('encoding_type must be `normal` or `onehot`.' + f'Got `{encoding_type}`.') + if isinstance(self.handler, RBFHandler): + encoding_type = 'normal' + self.encoding_type = encoding_type + + self.search_groups = search_groups + self.train_samples = train_samples + self.handler_ckpt = handler_ckpt + + self.score_key_list = [score_key] + ['anticipate'] + self.initialize = False + + def predict(self, model) -> Dict[str, float]: + """Predict the evaluation metric of input model using the handler. + + Args: + model: input model. + + Returns: + Dict[str, float]: evaluation metric of the model. + """ + metric: Dict[str, float] = {} + assert self.initialize is True, ( + 'Before predicting, evaluator is required to be executed first, ' + 'cause the model of handler in predictor needs to be initialized.') + + if self.initialize: + model, _ = export_fix_subnet(model) + data = self.preprocess(np.array([self.model2vector(model)])) + score = float(np.squeeze(self.handler.predict(data))) + if metric.get(self.score_key_list[0], None): + metric.update({self.score_key_list[1]: score}) + else: + metric.update({self.score_key_list[0]: score}) + return metric + + def model2vector( + self, model: Dict[str, Union[str, DumpChosen]]) -> Dict[str, list]: + """Convert the input model to N-dims vector. + + Args: + model (Dict[str, Union[str, DumpChosen]]): input model. + + Returns: + Dict[str, list]: converted vector. + """ + index = 0 + vector_dict: Dict[str, list] = \ + dict(normal_vector=[], onehot_vector=[]) + + assert len(model.keys()) == len(self.search_groups.keys()), ( + f'Length mismatch for model({len(model.keys())}) and search_groups' + f'({len(self.search_groups.keys())}).') + + for key, choice in model.items(): + if isinstance(choice, DumpChosen): + assert choice.meta is not None, ( + f'`DumpChosen.meta` of current {key} should not be None ' + 'when converting the search space.') + onehot = np.zeros( + len(choice.meta['all_choices']), dtype=np.int) + _chosen_index = choice.meta['all_choices'].index(choice.chosen) + else: + if key is not None: + from mmrazor.models.mutables import MutableChannelUnit + if isinstance(self.search_groups[key][0], + MutableChannelUnit): + choices = self.search_groups[key][0].candidate_choices + else: + choices = self.search_groups[key][0].choices + else: + assert len(self.search_groups[index]) == 1 + choices = self.search_groups[index][0].choices + onehot = np.zeros(len(choices), dtype=np.int) + _chosen_index = choices.index(choice) + onehot[_chosen_index] = 1 + + vector_dict['normal_vector'].extend([_chosen_index]) + vector_dict['onehot_vector'].extend(onehot) + index += 1 + + return vector_dict + + def vector2model(self, vector: np.array) -> Dict[str, str]: + """Convert the N-dims vector to original model. + + Args: + vector (numpy.array): input vector which represents the model. + + Returns: + Dict[str, str]: converted model. + """ + from mmrazor.models.mutables import OneShotMutableChannelUnit + + start = 0 + model = {} + vector = np.squeeze(vector) + for name, mutables in self.search_groups.items(): + if isinstance(mutables[0], OneShotMutableChannelUnit): + choices = mutables[0].candidate_choices + else: + choices = mutables[0].choices + + if self.encoding_type == 'onehot': + index = np.where(vector[start:start + len(choices)] == 1)[0][0] + start += len(choices) + else: + index = vector[start] + start += 1 + + chosen = choices[int(index)] if len(choices) > 1 else choices[0] + model[name] = chosen + + return model + + @staticmethod + def get_correlation(prediction: np.array, + label: np.array) -> List[np.array]: + """Compute the correlations between prediction and ground-truth label. + + Args: + prediction (numpy.array): predict vector. + label (numpy.array): ground-truth label. + + Returns: + List[numpy.array]: coefficients of correlations between predicton + and ground-truth label. + """ + rmse = np.sqrt(((prediction - label)**2).mean()) + rho, _ = stats.spearmanr(prediction, label) + tau, _ = stats.kendalltau(prediction, label) + return [rmse, rho, tau] + + def preprocess(self, data: List[Dict[str, list]]) -> np.array: + """Preprocess the data, convert it into np.array format. + + Args: + data (List[Dict[str, list]]): input data for training. + + Returns: + numpy.array: input data in numpy.array format. + """ + if self.encoding_type == 'normal': + data = np.array([x['normal_vector'] for x in data]) + else: + data = np.array([x['onehot_vector'] for x in data]) + return data + + def fit(self, data: List[Dict[str, list]], label: np.array) -> None: + """Training the handler using the structure information of a model. The + weights of handler will be fixed after that. + + Args: + data (List[Dict[str, list]]): input data for training. + label (numpy.array): input label for training. + """ + data = self.preprocess(data) + self.handler.fit(data, label) + self.initialize = True + + def load_checkpoint(self) -> None: + """Load checkpoint for handler.""" + self.handler.load(self.handler_ckpt) + self.initialize = True + + def save_checkpoint(self, path: str) -> str: + """Save checkpoint of handler and return saved path for diff suffix. + + Args: + path (str): save path for the handler. + + Returns: + (str): specific checkpoint path of the current handler. + """ + return self.handler.save(path) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/__init__.py new file mode 100755 index 000000000..8af399126 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/__init__.py @@ -0,0 +1,15 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .function_inputs_recorder import FunctionInputsRecorder +from .function_outputs_recorder import FunctionOutputsRecorder +from .method_inputs_recorder import MethodInputsRecorder +from .method_outputs_recorder import MethodOutputsRecorder +from .module_inputs_recorder import ModuleInputsRecorder +from .module_outputs_recorder import ModuleOutputsRecorder +from .param_recorder import ParameterRecorder +from .recorder_manager import RecorderManager + +__all__ = [ + 'FunctionOutputsRecorder', 'MethodOutputsRecorder', + 'ModuleOutputsRecorder', 'ParameterRecorder', 'RecorderManager', + 'ModuleInputsRecorder', 'MethodInputsRecorder', 'FunctionInputsRecorder' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/base_recorder.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/base_recorder.py new file mode 100755 index 000000000..b34c69180 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/base_recorder.py @@ -0,0 +1,116 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from abc import ABCMeta, abstractmethod +from typing import Any, List, Optional + +from torch import nn + + +class BaseRecorder(metaclass=ABCMeta): + """Base class for recorders. + + Recorder is a context manager used to record various intermediate results + during the model forward. It can be used in distillation algorithm and + can also be used to obtain some specific data for visual analysis. + + In MMRazor, there will be different types of recorders to obtain different + types of intermediate results. They can be used in combination with the + ``RecorderManager``. + + Note: + The recorder will be lazily initialized in the ``RecorderManager`` by + default. If you want to use the recorder without the + ``RecorderManager``, you need to initialize it first. + """ + + def __init__(self, source: str) -> None: + + self._source = source + # Intermediate results are recorded in dictionary format according + # to the data source. + # One data source may generate multiple records, which need to be + # recorded through list. + self._data_buffer: List = list() + # Before using the recorder for the first time, it needs to be + # initialized. + self._initialized = False + + @property + def source(self) -> str: + """str: source of recorded data.""" + return self._source + + @property + def data_buffer(self) -> List: + """list: data buffer.""" + return self._data_buffer + + @abstractmethod + def prepare_from_model(self, model: Optional[nn.Module] = None) -> None: + """Make the intermediate results of the model can be record.""" + + def initialize(self, model: Optional[nn.Module] = None) -> None: + """Init the recorder. + + Args: + model (nn.Module): The model which need to record intermediate + results. + """ + self.prepare_from_model(model) + self._initialized = True + + def get_record_data(self, + record_idx: int = 0, + data_idx: Optional[int] = None) -> Any: + """Get data from ``data_buffer``. + + Args: + record_idx (int): The index of the record saved in + ``data_buffer``. If a source is executed N times during + forward, there will be N records in ``data_buffer``. + data_index (int, optional): The index of target data in + a record. A record may be a tuple or a list, if data_idx is + None, the whole list or tuple is returned. Defaults to None. + + Returns: + Any: The type of the return value is undefined, and different + source data may have different types. + """ + assert record_idx < len(self._data_buffer), \ + 'record_idx is illegal. The length of data_buffer is ' \ + f'{len(self._data_buffer)}, but record_idx is ' \ + f'{record_idx}.' + + record = self._data_buffer[record_idx] + + if data_idx is None: + target_data = record + else: + if isinstance(record, (list, tuple)): + assert data_idx < len(record), \ + 'data_idx is illegal. The length of record is ' \ + f'{len(record)}, but data_idx is {data_idx}.' + target_data = record[data_idx] + else: + raise TypeError('When data_idx is not None, record should be ' + 'a list or tuple instance, but got ' + f'{type(record)}.') + + return target_data + + def reset_data_buffer(self) -> None: + """Clear data in data_buffer.""" + + self._data_buffer = list() + + def __enter__(self): + """Enter the context manager.""" + + assert self._initialized, \ + 'The recorder will be initialized in the RecorderManager by '\ + 'default. If you want to use the recorder without the '\ + 'RecorderManager, you need to initialize it first.' + + self.reset_data_buffer() + + def __exit__(self, exc_type, exc_value, traceback): + """Exit the context manager.""" diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_inputs_recorder.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_inputs_recorder.py new file mode 100755 index 000000000..e7bbdd896 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_inputs_recorder.py @@ -0,0 +1,71 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import functools +from inspect import signature +from typing import Callable, List + +from mmrazor.registry import TASK_UTILS +from .function_outputs_recorder import FunctionOutputsRecorder + + +@TASK_UTILS.register_module() +class FunctionInputsRecorder(FunctionOutputsRecorder): + """Recorder for intermediate results which are ``FunctionType``'s inputs. + + Notes: + The form of `source` needs special attention. For example, + `anchor_inside_flags` is a function in mmdetection to check whether the + anchors are inside the border. This function is in + `mmdet/core/anchor/utils.py` and used in + `mmdet/models/dense_heads/anchor_head.py`. Then the source should be + `mmdet.models.dense_heads.anchor_head.anchor_inside_flags` but not + `mmdet.core.anchor.utils.anchor_inside_flags`. + + + Examples: + >>> # Below code in toy_module.py + >>> import random + >>> def toy_func(a, b): + ... return a, b + >>> def execute_toy_func(a, b): + ... toy_func(a, b) + + >>> # Below code in main.py + >>> # Now, we want to get teacher's inputs by recorder. + + >>> from toy_module import execute_toy_func + >>> r1 = FunctionInputsRecorder('toy_module.toy_func') + >>> r1.initialize() + >>> with r1: + ... execute_toy_func(1, 2) + ... execute_toy_func(1, b=2) + ... execute_toy_func(b=2, a=1) + + >>> r1.data_buffer + [[1, 2], [1, 2], [1, 2]] + """ + + def func_record_wrapper(self, origin_func: Callable, + data_buffer: List) -> Callable: + """Save the function's inputs. + + Args: + origin_func (FunctionType): The method whose inputs need to be + recorded. + data_buffer (list): A list of data. + """ + + func_input_params = signature(origin_func).parameters.keys() + + @functools.wraps(origin_func) + def wrap_func(*args, **kwargs): + outputs = origin_func(*args, **kwargs) + inputs = list(args) + for keyword in func_input_params: + if keyword in kwargs: + inputs.append(kwargs[keyword]) + # assume a func execute N times, there will be N inputs need to + # save. + data_buffer.append(inputs) + return outputs + + return wrap_func diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_outputs_recorder.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_outputs_recorder.py new file mode 100755 index 000000000..706c1a8f7 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_outputs_recorder.py @@ -0,0 +1,162 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import functools +from types import FunctionType, ModuleType +from typing import Callable, List, Optional + +from mmengine.utils import import_modules_from_strings +from torch import nn + +from mmrazor.registry import TASK_UTILS +from .base_recorder import BaseRecorder + + +@TASK_UTILS.register_module() +class FunctionOutputsRecorder(BaseRecorder): + """Recorder for intermediate results which are ``FunctionType``'s outputs. + + Notes: + The form of `source` needs special attention. For example, + `anchor_inside_flags` is a function in mmdetection to check whether the + anchors are inside the border. This function is in + `mmdet/core/anchor/utils.py` and used in + `mmdet/models/dense_heads/anchor_head.py`. Then the source should be + `mmdet.models.dense_heads.anchor_head.anchor_inside_flags` but not + `mmdet.core.anchor.utils.anchor_inside_flags`. + + + Examples: + >>> # Below code in toy_module.py + >>> import random + >>> def toy_func(): + ... return random.randint(0, 1000) + >>> def toy_list_func(): + ... return [random.randint(0,1000) for _ in range(3)] + + >>> # Below code in main.py + >>> # Now, we want to get teacher's outputs by recorder. + + >>> import toy_module + >>> r1 = FunctionOutputsRecorder('toy_module.toy_func') + >>> r1.initialize() + >>> with r1: + ... output_teacher1 = toy_module.toy_func() + ... output_teacher2 = toy_module.toy_func() + ... output_teacher3 = toy_module.toy_func() + + >>> r1.data_buffer + [33, 41, 12] + >>> recorder.get_record_data(record_idx=2) + 12 + >>> output_teacher1==33 and output_teacher2==41 and output_teacher3==41 + True + + >>> r2 = FunctionOutputsRecorder('toy_module.toy_list_func') + >>> r2.initialize() + >>> with r2: + ... output_teacher1 = toy_module.toy_list_func() + ... output_teacher2 = toy_module.toy_list_func() + ... output_teacher3 = toy_module.toy_list_func() + + >>> r2.data_buffer + [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + >>> r2.get_record_data(record_idx=2, data_idx=2) + 9 + """ + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self._check_valid_source(self.source) + + @staticmethod + def _check_valid_source(source): + """Check if the source's format is valid.""" + if not isinstance(source, str): + raise TypeError(f'source should be a str ' + f'instance, but got {type(source)}') + + assert len(source.split('.')) > 1, \ + 'source must have at least one `.`' + + @property + def func_name(self): + """Get the function name according to `func_path`.""" + return self.source.split('.')[-1] + + @property + def module_string(self): + """Get the module name according to `func_path`.""" + return '.'.join(self.source.split('.')[:-1]) + + def prepare_from_model(self, model: Optional[nn.Module] = None) -> None: + """The `model` is useless in `FunctionOutputsRecorder`.""" + pass + + def func_record_wrapper(self, origin_func: Callable, + data_buffer: List) -> Callable: + """Save the function's outputs. + + Args: + origin_func (FunctionType): The method whose outputs need to be + recorded. + data_buffer (list): A list of data. + """ + + @functools.wraps(origin_func) + def wrap_func(*args, **kwargs): + outputs = origin_func(*args, **kwargs) + # assume a func execute N times, there will be N outputs need to + # save. + data_buffer.append(outputs) + return outputs + + return wrap_func + + def __enter__(self): + """Enter the context manager.""" + super().__enter__() + + # import the function corrosponding module + try: + mod = import_modules_from_strings(self.module_string) + except ImportError: + raise ImportError( + f'{self.module_string} is not imported correctly.') + + self.imported_module: ModuleType = mod + + assert hasattr(mod, self.func_name), \ + f'{self.func_name} is not in {self.module_string}.' + + origin_func = getattr(mod, self.func_name) + if not isinstance(origin_func, FunctionType): + raise TypeError(f'{self.func_name} should be a FunctionType ' + f'instance, but got {type(origin_func)}') + + self.origin_func: Callable = origin_func + + # add record wrapper to origin function. + record_func = self.func_record_wrapper(origin_func, self.data_buffer) + + assert hasattr(mod, self.func_name), \ + f'{self.func_name} is not in {self.module_string}.' + + # rewrite the origin function + setattr(mod, self.func_name, record_func) + + def __exit__(self, exc_type, exc_value, traceback): + """Exit the context manager.""" + super().__exit__(exc_type, exc_value, traceback) + + mod = self.imported_module + origin_func = self.origin_func + + assert hasattr(mod, self.func_name), \ + f'{self.func_name} is not in {self.module_string}.' + + # restore the origin function + setattr(mod, self.func_name, origin_func) + + # self.imported_module and self.origin_func can not be pickled. + # Delete these two attributes to avoid errors when ema model is used. + del self.imported_module + del self.origin_func diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_inputs_recorder.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_inputs_recorder.py new file mode 100755 index 000000000..44cb41843 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_inputs_recorder.py @@ -0,0 +1,83 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import functools +from inspect import signature +from typing import Callable, List + +from mmrazor.registry import TASK_UTILS +from .method_outputs_recorder import MethodOutputsRecorder + + +@TASK_UTILS.register_module() +class MethodInputsRecorder(MethodOutputsRecorder): + """Recorder for intermediate results which are ``MethodType``'s inputs. + + Note: + Different from ``FunctionType``, ``MethodType`` is the type of methods + of class instances. + + Examples: + >>> # Below code in toy_module.py + >>> import random + >>> class Toy(): + ... def toy_func(self, x, y=0): + ... return x + y + + >>> # Below code in main.py + >>> # Now, we want to get teacher's inputs by recorder. + + >>> from toy_module import Toy + >>> toy = Toy() + >>> r1 = MethodInputsRecorder('toy_module.Toy.toy_func') + >>> r1.initialize() + >>> with r1: + ... _ = toy.toy_func(1, 2) + + >>> r1.data_buffer + [[1, 2]] + >>> r1.get_record_data(record_idx=0, data_idx=0) + 1 + >>> r1.get_record_data(record_idx=0, data_idx=1) + 2 + + >>> from toy_module import Toy + >>> toy = Toy() + >>> r1 = MethodInputsRecorder('toy_module.Toy.toy_func') + >>> r1.initialize() + >>> with r1: + ... _ = toy.toy_func(1, 2) + ... _ = toy.toy_func(y=2, x=1) + + >>> r1.data_buffer + [[1, 2], [1, 2]] + >>> r1.get_record_data(record_idx=1, data_idx=0) + 1 + >>> r1.get_record_data(record_idx=1, data_idx=1) + 2 + """ + + def method_record_wrapper(self, orgin_method: Callable, + data_buffer: List) -> Callable: + """Save the method's inputs. + + Args: + origin_method (MethodType): The method whose inputs need to be + recorded. + data_buffer (list): A list of data. + """ + + method_input_params = signature(orgin_method).parameters.keys() + + @functools.wraps(orgin_method) + def wrap_method(*args, **kwargs): + outputs = orgin_method(*args, **kwargs) + # the first element of a class method is the class itself + inputs = list(args[1:]) + for keyword in method_input_params: + if keyword in kwargs: + inputs.append(kwargs[keyword]) + # Assume a func execute N times, there will be N inputs need to + # save. + data_buffer.append(inputs) + return outputs + + return wrap_method diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_outputs_recorder.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_outputs_recorder.py new file mode 100755 index 000000000..6d3fb6593 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_outputs_recorder.py @@ -0,0 +1,167 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import functools +from types import FunctionType, ModuleType +from typing import Callable, List, Optional + +from mmengine.utils import import_modules_from_strings +from torch import nn + +from mmrazor.registry import TASK_UTILS +from .base_recorder import BaseRecorder + + +@TASK_UTILS.register_module() +class MethodOutputsRecorder(BaseRecorder): + """Recorder for intermediate results which are ``MethodType``'s outputs. + + Note: + Different from ``FunctionType``, ``MethodType`` is the type of methods + of class instances. + + Examples: + >>> # Below code in toy_module.py + >>> import random + >>> class Toy(): + ... def toy_func(self): + ... return random.randint(0, 1000) + ... def toy_list_func(self): + ... return [random.randint(0, 1000) for _ in range(3)] + + >>> # Below code in main.py + >>> # Now, we want to get teacher's outputs by recorder. + + >>> from toy_module import Toy + >>> toy = Toy() + >>> r1 = MethodOutputsRecorder('toy_module.Toy.toy_func') + >>> r1.initialize() + >>> with r1: + ... output_teacher1 = toy.toy_func() + ... output_teacher2 = toy.toy_func() + ... output_teacher3 = toy.toy_func() + + >>> r1.data_buffer + [33, 41, 12] + >>> r1.get_record_data(record_idx=2) + 12 + >>> output_teacher1==33 and output_teacher2==41 and output_teacher3==41 + True + + >>> r2 = MethodOutputsRecorder('toy_module.Toy.toy_list_func' + >>> r2.initialize() + >>> with r2: + ... output_teacher1 = toy.toy_list_func() + ... output_teacher2 = toy.toy_list_func() + ... output_teacher3 = toy.toy_list_func() + + >>> r2.data_buffer + [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + >>> r2.get_record_data(record_idx=2, data_idx=2) + 9 + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self._check_valid_source(self.source) + + # import the function corrosponding module + try: + mod: ModuleType = import_modules_from_strings(self.module_string) + except ImportError: + raise ImportError( + f'{self.module_string} is not imported correctly.') + + assert hasattr(mod, self.cls_name), \ + f'{self.cls_name} is not in {self.module_string}.' + + imported_cls: type = getattr(mod, self.cls_name) + if not isinstance(imported_cls, type): + raise TypeError(f'{self.cls_name} should be a type ' + f'instance, but got {type(imported_cls)}') + self.imported_class = imported_cls + + assert hasattr(imported_cls, self.method_name), \ + f'{self.method_name} is not in {self.cls_name}.' + + origin_method = getattr(imported_cls, self.method_name) + if not isinstance(origin_method, FunctionType): + raise TypeError(f'{self.method_name} should be a FunctionType ' + f'instance, but got {type(origin_method)}') + self.origin_method = origin_method + + @staticmethod + def _check_valid_source(source: str) -> None: + """Check if the `source` is valid.""" + if not isinstance(source, str): + raise TypeError(f'source should be a str ' + f'instance, but got {type(source)}') + + assert len(source.split('.')) > 2, \ + 'source must have at least two `.`' + + @property + def method_name(self): + """Get the method name according to `method_path`.""" + return self.source.split('.')[-1] + + @property + def cls_name(self): + """Get the class name corresponding to this method according to + `method_path`.""" + return self.source.split('.')[-2] + + @property + def module_string(self): + """Get the module name according to `method_path`.""" + return '.'.join(self.source.split('.')[:-2]) + + def prepare_from_model(self, model: Optional[nn.Module] = None) -> None: + """Wrapper the origin source methods. + + The ``model`` is useless in this recorder, just to be consistent with + other recorders. + """ + pass + + def method_record_wrapper(self, orgin_method: Callable, + data_buffer: List) -> Callable: + """Save the method's outputs. + + Args: + origin_method (MethodType): The method whose outputs need to be + recorded. + data_buffer (list): A list of data. + """ + + @functools.wraps(orgin_method) + def wrap_method(*args, **kwargs): + outputs = orgin_method(*args, **kwargs) + # assume a func execute N times, there will be N outputs need to + # save. + data_buffer.append(outputs) + return outputs + + return wrap_method + + def __enter__(self): + """Enter the context manager.""" + super().__enter__() + + imported_cls = self.imported_class + origin_method = self.origin_method + # add record wrapper to origin method. + record_method = self.method_record_wrapper(origin_method, + self.data_buffer) + + # rewrite the origin method. + setattr(imported_cls, self.method_name, record_method) + + def __exit__(self, exc_type, exc_value, traceback): + """Exit the context manager.""" + super().__exit__(exc_type, exc_value, traceback) + + imported_cls = self.imported_class + origin_method = self.origin_method + + # restore the origin method + setattr(imported_cls, self.method_name, origin_method) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_inputs_recorder.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_inputs_recorder.py new file mode 100755 index 000000000..53ea90940 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_inputs_recorder.py @@ -0,0 +1,27 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Any, Tuple + +from torch import nn + +from mmrazor.registry import TASK_UTILS +from .module_outputs_recorder import ModuleOutputsRecorder + + +@TASK_UTILS.register_module() +class ModuleInputsRecorder(ModuleOutputsRecorder): + """Recorder for intermediate results which are Pytorch moudle's inputs.""" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def forward_hook(self, module: nn.Module, inputs: Tuple, + outputs: Any) -> None: + """Save the module's forward input. + + Args: + module (:obj:`torch.nn.Module`): The module to register hook. + inputs (tuple): The input of the module. + outputs : The output of the module. + """ + if self.recording: + self.data_buffer.append(inputs) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_outputs_recorder.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_outputs_recorder.py new file mode 100755 index 000000000..277d73935 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_outputs_recorder.py @@ -0,0 +1,96 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Any, Optional, Tuple + +from torch import nn + +from mmrazor.registry import TASK_UTILS +from .base_recorder import BaseRecorder + + +@TASK_UTILS.register_module() +class ModuleOutputsRecorder(BaseRecorder): + """Recorder for intermediate results which are Pytorch moudle's outputs. + + Examples: + >>> from torch import nn + >>> class ToyModel(nn.Module): + ... def __init__(self): + ... super().__init__() + ... self.conv1 = nn.Conv2d(8,8,1) + ... self.conv2 = nn.Conv2d(1,1,1) + ... def forward(self, x): + ... x1 = self.conv1(x) + ... x2 = self.conv1(x+1) + ... return self.conv2(x1 + x2) + + >>> model = ToyModel() + >>> [ name for name,_ in model.named_modules() ] + ['conv1', 'conv2'] + + >>> r1 = ModuleOutputsRecorder('conv1') + >>> r1.initialize(model) + + >>> with r1: + >>> res = model(torch.randn(1,1,1,1)) + + >>> r1.data_buffer + [tensor([[[[0.6734]]]]), tensor([[[[1.2514]]]]) ] + >>> r1.get_record_data(record_idx=1) + tensor([[[[1.2514]]]]) + + >>> r2 = ModuleOutputsRecorder('conv2') + >>> r2.initialize(model) + + >>> with r2: + >>> res = model(torch.randn(1,1,1,1)) + + >>> r2.data_buffer + [tensor([[[[0.9534]]]])] + >>> r2.get_record_data() + tensor([[[[0.9534]]]]) + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._recording = False + + @property + def recording(self) -> bool: + """bool: whether to record data in forward hook.""" + return self._recording + + def prepare_from_model(self, model: Optional[nn.Module] = None) -> None: + """Register Pytorch forward hook to corresponding module.""" + + assert model is not None, 'model can not be None.' + + founded = False + for name, module in model.named_modules(): + if name == self.source: + module.register_forward_hook(self.forward_hook) + founded = True + break + + assert founded, f'"{self.source}" is not in the model.' + + def forward_hook(self, module: nn.Module, inputs: Tuple, + outputs: Any) -> None: + """Save the module's forward output. + + Args: + module (:obj:`torch.nn.Module`): The module to register hook. + inputs (tuple): The input of the module. + outputs : The output of the module. + """ + if self._recording: + self.data_buffer.append(outputs) + + def __enter__(self): + """Enter the context manager.""" + super().__enter__() + self._recording = True + + def __exit__(self, exc_type, exc_value, traceback): + """Exit the context manager.""" + super().__exit__(exc_type, exc_value, traceback) + self._recording = False diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/param_recorder.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/param_recorder.py new file mode 100755 index 000000000..afd0d1c0f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/param_recorder.py @@ -0,0 +1,57 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Optional + +from torch import nn + +from mmrazor.registry import TASK_UTILS +from .base_recorder import BaseRecorder + + +@TASK_UTILS.register_module() +class ParameterRecorder(BaseRecorder): + """Recorder for Pytorch model's parameters. + + Examples: + >>> from torch import nn + >>> class ToyModel(nn.Module): + ... def __init__(self): + ... super().__init__() + ... self.toy_conv = nn.Conv2d(1,1,1) + ... def forward(self, x): + ... return self.toy_conv(x) + + >>> model = ToyModel() + >>> [ name for name,_ in model.named_parameters() ] + ['toy_conv.weight', 'toy_conv.bias'] + + >>> recorder = ParameterRecorder('toy_conv.weight') + >>> recorder.initialize(model) + + >>> recorder.data_buffer + [Parameter containing: tensor([[[[0.3244]]]], requires_grad=True)] + >>> recorder.get_record_data() + Parameter containing: tensor([[[[0.3244]]]], requires_grad=True) + """ + + def prepare_from_model(self, model: Optional[nn.Module] = None) -> None: + """Record the Pytorch model's parameters.""" + assert model is not None, \ + 'model can not be None when use ParameterRecorder.' + + founded = False + for param_name, param in model.named_parameters(): + if param_name == self.source: + self.data_buffer.append(param) + founded = True + break + + assert founded, f'"{self.source}" is not in the model.' + + def reset_data_buffer(self): + """Clear data in data_buffer. + + Note: + The data_buffer stores the address of the parameter in memory and + does not need to be reset. + """ + pass diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/recorder_manager.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/recorder_manager.py new file mode 100755 index 000000000..30fbbb39f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/recorder_manager.py @@ -0,0 +1,116 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict, Optional + +from torch import nn + +from mmrazor.registry import TASK_UTILS +from .base_recorder import BaseRecorder + + +class RecorderManager: + """Various types recorders' manager. The ``RecorderManager`` also is a + context manager, managing various types of Recorder. When entering the + ``RecorderManager``, all recorders managed by it will be started. + + Note: + The recorders will be initialized in the ``RecorderManager`` by + default. If you want to just use a recorder without the + ``RecorderManager``, you need to initialize it first. + + Args: + recorders (dict, optional): All recorders' config. + + + Examples: + >>> # Below code in toy_module.py + >>> import random + >>> class Toy(): + ... def toy_func(self): + ... return random.randint(0, 1000) + + >>> # Below code in main.py + >>> from torch import nn + >>> from toy_module import Toy + + >>> class ToyModel(nn.Module): + ... def __init__(self): + ... super().__init__() + ... self.conv1 = nn.Conv2d(1,1,1) + ... self.conv2 = nn.Conv2d(1,1,1) + ... self.toy = Toy() + ... def forward(self, x): + ... return self.conv2(self.conv1(x)) + self.toy.toy_func() + + >>> model = ToyModel() + >>> [ name for name,_ in model.named_modules() ] + ['conv1', 'conv2'] + + >>> conv1_rec = ModuleOutputsRecorder('conv1') + >>> conv2_rec = ModuleOutputsRecorder('conv2') + >>> func_rec = MethodOutputsRecorder('toy_module.Toy.toy_func') + >>> manager = RecorderManager( + ... {'conv1_rec': conv1_rec , + ... 'conv2_rec': conv2_rec, + ... 'func_rec': func_rec}) + >>> manager.initialize(model) + + >>> with manager: + ... res = model(torch.ones(1,1,1,1)) + >>> res + tensor([[[[22.9534]]]]) + + >>> conv2_data = manager.get_recorder('conv2_rec').get_record_data() + >>> conv2_data + tensor([[[[0.9534]]]]) + + >>> func_data = manager.get_recorder('func_rec').get_record_data() + >>> func_data + 22 + + >>> res.sum() == (conv2_data + func_data).sum() + True + """ + + def __init__(self, recorders: Optional[Dict] = None) -> None: + + self._recorders: Dict[str, BaseRecorder] = dict() + if recorders: + for name, cfg in recorders.items(): + recorder_cfg = copy.deepcopy(cfg) + recorder_type = cfg['type'] + recorder_type_ = recorder_type + 'Recorder' + + recorder_cfg['type'] = recorder_type_ + recorder = TASK_UTILS.build(recorder_cfg) + + self._recorders[name] = recorder + + @property + def recorders(self) -> Dict[str, BaseRecorder]: + """dict: all recorders.""" + return self._recorders + + def get_recorder(self, recorder: str) -> BaseRecorder: + """Get the corresponding recorder according to the name.""" + return self.recorders[recorder] + + def initialize(self, model: nn.Module): + """Init all recorders. + + Args: + model (nn.Module): The model which need to record intermediate + results. + """ + for recorder in self.recorders.values(): + recorder.initialize(model) + + def __enter__(self): + """Enter the context manager.""" + for recorder in self.recorders.values(): + recorder.__enter__() + + def __exit__(self, exc_type, exc_value, traceback): + """Exit the context manager.""" + for recorder in self.recorders.values(): + recorder.__exit__(exc_type, exc_value, traceback) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/__init__.py new file mode 100755 index 000000000..987030d81 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/__init__.py @@ -0,0 +1,17 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .backward_tracer import BackwardTracer +from .channel_analyzer import ChannelAnalyzer +# from .razor_tracer import RazorFxTracer +from .fx import (CustomTracer, UntracedMethodRegistry, build_graphmodule, + custom_symbolic_trace) +from .loss_calculator import * # noqa: F401,F403 +from .parsers import * # noqa: F401,F403 +from .path import (Path, PathConcatNode, PathConvNode, PathDepthWiseConvNode, + PathLinearNode, PathList, PathNode, PathNormNode) + +__all__ = [ + 'BackwardTracer', 'PathConvNode', 'PathLinearNode', 'PathNormNode', + 'PathConcatNode', 'Path', 'PathList', 'PathNode', 'PathDepthWiseConvNode', + 'ChannelAnalyzer', 'CustomTracer', 'UntracedMethodRegistry', + 'custom_symbolic_trace', 'build_graphmodule' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/backward_tracer.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/backward_tracer.py new file mode 100755 index 000000000..f87c760d1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/backward_tracer.py @@ -0,0 +1,201 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import re +from collections import OrderedDict + +from mmengine import ConfigDict +from torch.nn import Conv2d, Linear +from torch.nn.modules import GroupNorm +from torch.nn.modules.batchnorm import _NormBase + +from mmrazor.registry import TASK_UTILS +from .parsers import DEFAULT_BACKWARD_TRACER +from .path import Path, PathList + +SUPPORT_MODULES = (Conv2d, Linear, _NormBase, GroupNorm) + + +@TASK_UTILS.register_module() +class BackwardTracer: + """A topology tracer via backward. + + Args: + loss_calculator (dict or Callable): Calculate the pseudo loss to trace + the topology of a model. + """ + + def __init__(self, loss_calculator): + if isinstance(loss_calculator, (dict, ConfigDict)): + loss_calculator = TASK_UTILS.build(loss_calculator) + + assert callable( + loss_calculator + ), 'loss_calculator should be a dict, ConfigDict or ' \ + 'callable object' + self.loss_calculator = loss_calculator + + @property + def backward_parser(self): + """The mapping from the type of a backward op to the corresponding + parser.""" + return DEFAULT_BACKWARD_TRACER + + def backward_trace(self, grad_fn, module2name, param2module, cur_path, + result_paths, visited, shared_module): + """Trace the topology of all the ``NON_PASS_MODULE``.""" + grad_fn = grad_fn[0] if isinstance(grad_fn, (list, tuple)) else grad_fn + + if grad_fn is not None: + name = type(grad_fn).__name__ + # In pytorch graph, there may be an additional '0' or '1' + # (e.g. ThnnConv2DBackward0) after a backward op. Delete the + # digit numbers to build the corresponding parser. + name = re.sub(r'[0-1]+', '', name) + parse_module = self.backward_parser.get(name) + + if parse_module is not None: + parse_module(self, grad_fn, module2name, param2module, + cur_path, result_paths, visited, shared_module) + else: + # If the op is AccumulateGrad, parents is (), + parents = grad_fn.next_functions + if parents is not None: + for parent in parents: + self.backward_trace(parent, module2name, param2module, + cur_path, result_paths, visited, + shared_module) + else: + result_paths.append(copy.deepcopy(cur_path)) + + def _trace_shared_module_hook(self, module, inputs, outputs): + """Trace shared modules. Modules such as the detection head in + RetinaNet which are visited more than once during :func:`forward` are + shared modules. + + Args: + module (:obj:`torch.nn.Module`): The module to register hook. + inputs (tuple): The input of the module. + outputs (tuple): The output of the module. + """ + module._cnt += 1 + + def _build_mappings(self, model): + """Build the mappings which are used during tracing.""" + + module2name = OrderedDict() + # build a mapping from the identity of a module's params + # to this module + param2module = OrderedDict() + # record the visited module name during trace path + visited = dict() + + def traverse(module, prefix=''): + for name, child in module.named_children(): + full_name = f'{prefix}.{name}' if prefix else name + + if isinstance(child, SUPPORT_MODULES): + module2name[child] = full_name + for param in child.parameters(): + param2module[id(param)] = child + visited[full_name] = False + else: + traverse(child, full_name) + + traverse(model) + + return module2name, param2module, visited + + def _register_share_module_hook(self, model): + """Record shared modules which will be visited more than once during + forward such as shared detection head in RetinaNet. + + If a module is not a shared module and it has been visited during + forward, its parent modules must have been traced already. However, a + shared module will be visited more than once during forward, so it is + still need to be traced even if it has been visited. + """ + self._shared_module_hook_handles = list() + for module in model.modules(): + if hasattr(module, 'weight'): + # trace shared modules + module._cnt = 0 + # the handle is only to remove the corresponding hook later + handle = module.register_forward_hook( + self._trace_shared_module_hook) + self._shared_module_hook_handles.append(handle) + + def _remove_share_module_hook(self, model): + """`_trace_shared_module_hook` and `_cnt` are only used to trace the + shared modules in a model and need to be remove later.""" + for module in model.modules(): + if hasattr(module, 'weight'): + del module._cnt + + for handle in self._shared_module_hook_handles: + handle.remove() + + del self._shared_module_hook_handles + + def _set_all_requires_grad(self, model): + """Set `requires_grad` of a parameter to True to trace the whole + architecture topology.""" + self._param_requires_grad = dict() + for param in model.parameters(): + self._param_requires_grad[id(param)] = param.requires_grad + param.requires_grad = True + + def _restore_requires_grad(self, model): + """We set requires_grad to True to trace the whole architecture + topology. + + So it should be reset after that. + """ + for param in model.parameters(): + param.requires_grad = self._param_requires_grad[id(param)] + del self._param_requires_grad + + @staticmethod + def _find_share_modules(model): + """Find shared modules which will be visited more than once during + forward such as shared detection head in RetinaNet.""" + share_modules = list() + for name, module in model.named_modules(): + if hasattr(module, 'weight'): + if module._cnt > 1: + share_modules.append(name) + + return share_modules + + @staticmethod + def _reset_norm_running_stats(model): + """As we calculate the pseudo loss during tracing, we need to reset + states of parameters.""" + for module in model.modules(): + if isinstance(module, _NormBase): + module.reset_parameters() + + def trace(self, model): + """Trace trace the architecture topology of the input model.""" + module2name, param2module, visited = self._build_mappings(model) + + # Set requires_grad to True. If the `requires_grad` of a module's + # weight is False, we can not trace this module by parsing backward. + self._set_all_requires_grad(model) + + self._register_share_module_hook(model) + + pseudo_loss = self.loss_calculator(model) + + share_modules = self._find_share_modules(model) + + self._remove_share_module_hook(model) + self._restore_requires_grad(model) + + module_path_list = PathList() + + self.backward_trace(pseudo_loss.grad_fn, module2name, param2module, + Path(), module_path_list, visited, share_modules) + + self._reset_norm_running_stats(model) + + return module_path_list diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/channel_analyzer.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/channel_analyzer.py new file mode 100755 index 000000000..9f754e97e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/channel_analyzer.py @@ -0,0 +1,178 @@ +# Copyright (c) OpenMMLab. All rights reserved. +""" +- How to config ChannelAnalyzer by hard code + - fxtracer + - demo_inputs + ./mmrazor/models/task_modules/demo_inputs/default_demo_inputs.py + - leaf module + - ChannelAnalyzer.default_leaf_modules + - method + - ./mmrazor/models/task_modules/tracer/fx_tracer.py + - ChannelNode + - ./mmrazor/structures/graph/channel_nodes.py + - DynamicOp + ./mmrazor/models/architectures/dynamic_ops/bricks/dynamic_conv.py +""" +import copy +from typing import Dict, List, Tuple, Union + +import torch +import torch.nn as nn +from mmcv.cnn.bricks import Scale +from mmengine.model.utils import revert_sync_batchnorm + +from mmrazor.models.architectures.dynamic_ops import DynamicChannelMixin +from mmrazor.models.mutables.mutable_channel import ( + MutableChannelUnit, SequentialMutableChannelUnit) +from mmrazor.models.mutables.mutable_channel.units.utils import find_mutable +from mmrazor.registry import TASK_UTILS +from mmrazor.structures.graph import ModuleGraph +from mmrazor.structures.graph.channel_graph import ( + ChannelGraph, default_channel_node_converter) +from mmrazor.structures.graph.module_graph import (FxTracerToGraphConverter, + PathToGraphConverter) +from mmrazor.structures.graph.pseudo_fx_graph import parse_torch_graph +from mmrazor.utils import print_log +from ..demo_inputs import BaseDemoInput, DefaultDemoInput +from .backward_tracer import BackwardTracer +from .fx_tracer import MMFxTracer +from .loss_calculator.sum_loss_calculator import SumPseudoLoss + + +@TASK_UTILS.register_module() +class ChannelAnalyzer: + """The tracer for pruning. It return the configs of MutableChannelUnits as + result. + + Args: + demo_input (Union[List, Dict, Tuple, BaseDemoInput], optional): + The demo input for the model. demo_input can be one of + input_shape(list), config of a demo input generator, a demoinput + generator. Defaults to (1, 3, 224, 224). + tracer_type (str, optional): str indicates which basic tracer to use. + Defaults to 'BackwardTracer'. + """ + default_leaf_modules = ( + # dynamic op + DynamicChannelMixin, + # torch + nn.Conv2d, + nn.Linear, + nn.modules.batchnorm._BatchNorm, + # mmcv + Scale, + ) + + def __init__(self, + demo_input: Union[List, Dict, Tuple, + BaseDemoInput] = (1, 3, 224, 224), + tracer_type='BackwardTracer') -> None: + + if isinstance(demo_input, dict): + self.demo_input = TASK_UTILS.build(demo_input) + elif isinstance(demo_input, list) or isinstance(demo_input, tuple): + self.demo_input = DefaultDemoInput(demo_input, False) + elif isinstance(demo_input, BaseDemoInput): + self.demo_input = demo_input + else: + raise NotImplementedError(f'{type(demo_input)},{demo_input}') + + self.input_shape = demo_input + + assert tracer_type in ['BackwardTracer', 'FxTracer'] + self.tracer_type = tracer_type + if tracer_type == 'BackwardTracer': + self.tracer = BackwardTracer( + loss_calculator=SumPseudoLoss( + input_shape=self.demo_input.input_shape)) + elif tracer_type == 'FxTracer': + from mmrazor import digit_version + assert digit_version(torch.__version__) >= digit_version( + '1.12.0' + ), 'Please install torch>=1.12.0, if you want to use fx tracer.' + self.tracer = MMFxTracer(leaf_module=self.default_leaf_modules) + else: + raise NotImplementedError() + + def analyze(self, model): + """Tracer the model, and return configs of channel dependency.""" + model = copy.deepcopy(model) + model = revert_sync_batchnorm(model) + model.eval() + if self.tracer_type == 'BackwardTracer': + path_list = self.tracer.trace(model) + module_graph: ModuleGraph = PathToGraphConverter(path_list, + model).graph + elif self.tracer_type == 'FxTracer': + fx_graph = self._fx_trace(model) + fx_graph.owning_module = model + base_graph = parse_torch_graph(fx_graph) + + module_graph = FxTracerToGraphConverter(base_graph, model).graph + module_graph._model = model + else: + raise NotImplementedError() + + module_graph.refresh_module_name() + module_graph.check(fix=True) + module_graph.check() + + channel_graph = ChannelGraph.copy_from(module_graph, + default_channel_node_converter) + channel_graph.check(fix=True) + channel_graph.check() + + channel_graph.forward(self.demo_input.input_shape[1]) + unit_configs = channel_graph.generate_units_config() + + return self._find_mutable_units(model, unit_configs) + + def _fx_trace(self, model): + """Tracer the model using fx tracer.""" + args = self.demo_input.get_data(model) + if isinstance(args, dict): + args.pop('inputs') + args['mode'] = 'tensor' + return self.tracer.trace(model, concrete_args=args) + else: + return self.tracer.trace(model) + + def _find_mutable_units(self, model: nn.Module, units_config: Dict): + """Test the tracer result and filter unforwardable units.""" + model = copy.deepcopy(model).cpu() + units: List[SequentialMutableChannelUnit] = [ + SequentialMutableChannelUnit.init_from_cfg(model, cfg) + for cfg in units_config.values() + ] + for unit in units: + unit.prepare_for_pruning(model) + mutable_units = [unit for unit in units if unit.is_mutable] + inputs = self.demo_input.get_data(model) + model.eval() + + template_output = None + if isinstance(inputs, dict): + for mode in ['loss', 'tensor', 'predict']: + try: + inputs['mode'] = mode + template_output = model(**inputs) + break + except Exception as e: + print_log(f'Forward failed in {mode} mode as {e}') + else: + try: + template_output = model(inputs) + except Exception as e: + print_log(f'Forward failed in as {e}') + if template_output is None: + raise Exception( + 'Forward failed, there may be an error in demo input.', + f'{inputs}') + mutable_units = find_mutable(model, mutable_units, units, inputs, + template_output) + mutable_unit_config = {} + for unit in mutable_units: + mutable_unit_config[ + unit.name] = MutableChannelUnit.config_template( + unit, with_channels=True, with_init_args=True) + return mutable_unit_config diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/__init__.py new file mode 100755 index 000000000..82f723f10 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/__init__.py @@ -0,0 +1,18 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .custom_tracer import (CustomTracer, UntracedMethodRegistry, + build_graphmodule, custom_symbolic_trace) +from .graph_utils import (del_fakequant_after_function, + del_fakequant_after_method, + del_fakequant_after_module, del_fakequant_after_op, + del_fakequant_before_function, + del_fakequant_before_method, + del_fakequant_before_module, del_fakequant_before_op) + +__all__ = [ + 'CustomTracer', 'UntracedMethodRegistry', 'custom_symbolic_trace', + 'build_graphmodule', 'del_fakequant_before_module', + 'del_fakequant_after_module', 'del_fakequant_after_function', + 'del_fakequant_before_function', 'del_fakequant_after_op', + 'del_fakequant_before_op', 'del_fakequant_before_method', + 'del_fakequant_after_method' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/custom_tracer.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/custom_tracer.py new file mode 100755 index 000000000..68d5f0809 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/custom_tracer.py @@ -0,0 +1,477 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import functools +from copy import deepcopy +from types import FunctionType +from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union + +import torch +import torch.nn as nn + +try: + from torch._C import ScriptObject # type: ignore[attr-defined] + from torch.ao.quantization.quantize_fx import QuantizationTracer + from torch.fx import Graph, GraphModule, Tracer + from torch.fx._symbolic_trace import (_autowrap_check, + _patch_wrapped_functions, _Patcher) + from torch.fx.proxy import Proxy +except ImportError: + from mmrazor.utils import get_placeholder + ScriptObject = get_placeholder('torch>=1.13') + QuantizationTracer = get_placeholder('torch>=1.13') + GraphModule = get_placeholder('torch>=1.13') + Tracer = get_placeholder('torch>=1.13') + Graph = get_placeholder('torch>=1.13') + _autowrap_check = get_placeholder('torch>=1.13') + _patch_wrapped_functions = get_placeholder('torch>=1.13') + _Patcher = get_placeholder('torch>=1.13') + Proxy = get_placeholder('torch>=1.13') + +from mmengine.utils import import_modules_from_strings + +from mmrazor.registry import TASK_UTILS + +_orig_module_call: Callable = nn.Module.__call__ +_orig_module_getattr: Callable = nn.Module.__getattr__ + + +class UntracedMethodRegistry: + """A `Descriptor` class which records untraced methods. Thus, when the + class is traced with CustomTracer, the decorated method will be as a leaf + node, not be nested traced. + + Example: + >>> # `imported_cls` is the owner of the untraced method; + >>> # `method_str` is the name of the untraced method. + >>> method_registry = UntracedMethodRegistry(method) + >>> method_registry.__set_name__(imported_cls, method_str) + + Args: + method (FunctionType): Function to be registered. + """ + method_dict: Dict = dict() + tracer = None + + def __init__(self, method: FunctionType): + self.method = method + self.owner = None + + def __set_name__(self, owner, name): + self.owner = owner + self.name = name + wrapped = self.method_wrapper() + self.method_dict[name] = dict(mod=self.owner, wrapped=wrapped) + + def method_wrapper(self): + + @functools.wraps(self.method) + def wrapped_method(mod, *args, **kwargs): + + def method(*args, **kwargs): + return self.method(mod, *args, **kwargs) + + return self.tracer.call_method(mod, self.name, method, args, + kwargs) + + return wrapped_method + + +def _prepare_module_dict(model: torch.nn.Module, fx_graph): + """If there is a class method that can not be traced by the symbolic + tracer, a ``call_method`` ``Node`` will be inserted into the ``Graph`` in + ``CustomTracer``. + + Example: + >>> class Model: + ... def __init__(self): + ... self.head = ClsHead() + ... + >>> class ClsHead(nn.Module): + ... def forward(self, feats: Tuple[torch.Tensor]) -> torch.Tensor: + ... return feats[-1] + ... + ... def loss(self, feats: Tuple[torch.Tensor], + ... data_samples: List[ClsDataSample], **kwargs) -> dict: + ... cls_score = self(feats) + ... # The part can not be traced by torch.fx + ... losses = self._get_loss(cls_score, data_samples, **kwargs) + ... return losses + ... + ... def _get_loss(self, cls_score: torch.Tensor, + ... data_samples: List[ClsDataSample], **kwargs): + ... if 'score' in data_samples[0].gt_label: + ... xxx + ... else: + ... xxx + ... losses = xxx + ... return losses + + As the ``_get_loss`` can not be traced by torch.fx, ``Toy._get_loss`` need + to be added to ``skipped_methods`` in ``CustomTracer``. Hence the code + above will product the following Graph:: + + .. code-block:: text + ... ... + %head : [#users=1] = get_attr[target=head] + %_get_loss : [#users=1] = call_method[target=_get_loss](args = (%head, %head_fc, %data_samples), kwargs = {}) # noqa: E501 + return _get_loss + + Hence, the head module in the ``GraphModule`` and that in the original + model are the same one (refer to https://github.com/pytorch/pytorch/blob/master/torch/fx/graph_module.py#L346). # noqa: E501 + So changes made to the graph module (in ``prepare()``) will also modify + the original model. + + Args: + model (torch.nn.Module): Module or function to be + traced and converted into a Graph representation. + fx_graph (torch.fx.Graph): The fx Graph traced by fx tracer. It + contains the nodes this GraphModule should use for code generation. + """ + + def _get_attrs(target, attrs): + attrs = attrs.split('.') + for att in attrs: + target = getattr(target, att) + return target + + module_dict = dict() + special_nodes = [] + + for node in fx_graph.nodes: + if node.op == 'get_attr': + attr = _get_attrs(model, node.target) + if isinstance(attr, nn.Module): + module_dict[node.target] = nn.Module() + special_nodes.append(node) + elif node.op == 'call_method': + for special_node in special_nodes: + if special_node in node.args or \ + special_node in node.kwargs.values(): + origin_module = getattr(model, special_node.target) + setattr(module_dict[special_node.target], node.target, + getattr(origin_module, node.target)) + + return module_dict + + +def duplicate_reused_nodes(graph: Graph, modules: Dict[str, Any] = {}): + """Deepcopy the shared modules (e.g. shared detection head in RetinaNet) to + make sure modules can be fused correctly. + + Modified from https://github.com/ModelTC/MQBench/blob/main/mqbench/prepare_by_platform.py # noqa: E501 + """ + _dup_prefix = '_dup' + target_dict = dict() + dup_modules = dict() + for node in graph.nodes: + if node.op == 'call_module': + if node.target not in target_dict: + target_dict[node.target] = [node] + else: + target_dict[node.target].append(node) + for key in target_dict: + if len(target_dict[key]) > 1: + for idx, node in enumerate(target_dict[key]): + if idx == 0: + continue + module = deepcopy(modules[node.target]) + node.target += _dup_prefix + str(idx) + dup_modules[node.target] = module + graph.lint() + return graph, dup_modules + + +def build_graphmodule(model: torch.nn.Module, + fx_graph, + name: str = 'GraphModule'): + """To build GraphModule with the generated graph by CustomTracer. The + implement of skipping methods in CustomTracer will cause the confliction of + that a node is both a leaf node and non-leaf node, which will lead that the + modification to the ``graph`` also change the original ``forward``. + + Args: + model (torch.nn.Module): Module or function to be + traced and converted into a Graph representation. + fx_graph (torch.fx.Graph): The fx Graph traced by fx tracer. It + contains the nodes this GraphModule should use for code generation. + name (str): The name of generated GraphModule. + + Returns: + GraphModule: GraphModule is an nn.Module generated from an fx.Graph. + Graphmodule has a ``graph`` attribute, as well as ``code`` and + ``forward`` attributes generated from that ``graph``. + + .. warning:: + When ``graph`` is reassigned, ``code`` and ``forward`` will be + automatically regenerated. However, if you edit the contents of the + ``graph`` without reassigning the ``graph`` attribute itself, you must + call ``recompile()`` to update the generated code. + """ + modules = dict(model.named_modules()) + module_dict = _prepare_module_dict(model, fx_graph) + fx_graph, duplicated_modules = duplicate_reused_nodes(fx_graph, modules) + modules.update(module_dict) + modules.update(duplicated_modules) + return GraphModule(modules, fx_graph, name) + + +@TASK_UTILS.register_module() +class CustomTracer(QuantizationTracer): + """Custom tracer based on QuantizationTracer of pytorch. It can not only + skip some modules and classes while tracing, but also skip some methods + untraced by torch.fx.Tracer. + + Args: + skipped_methods (List[str], optional): Methods to be skipped while + tracing. Defaults to None. + skipped_module_names (List[str], optional): Modules to be skipped + while tracing. Defaults to None. + skipped_module_classes (List[Callable], optional): Class to be skipped + while tracing. Defaults to None. + """ + + def __init__(self, + skipped_methods: List[str] = [], + skipped_module_names: List[str] = [], + skipped_module_classes: List[Callable] = [], + *args, + **kwargs): + super(CustomTracer, self).__init__(skipped_module_names, + skipped_module_classes) + UntracedMethodRegistry.tracer = self # type: ignore + self.skipped_methods = skipped_methods + if self.skipped_methods: + self.register_skipped_methods() + + @staticmethod + def _check_valid_source(source): + """Check if the source's format is valid.""" + if not isinstance(source, str): + raise TypeError(f'source should be a str ' + f'instance, but got {type(source)}') + + assert len(source.split('.')) > 1, \ + 'source must have at least one `.`' + + def register_skipped_methods(self): + """Register skipped methods to UntracedMethodRegistry.method_dict.""" + if not isinstance(self.skipped_methods, list): + self.skipped_methods = [self.skipped_methods] + for s_method in self.skipped_methods: + self._check_valid_source(s_method) + mod_str = '.'.join(s_method.split('.')[:-2]) + cls_str = s_method.split('.')[-2] + method_str = s_method.split('.')[-1] + + try: + mod = import_modules_from_strings(mod_str) + except ImportError: + raise ImportError(f'{mod_str} is not imported correctly.') + + imported_cls: type = getattr(mod, cls_str) + if not isinstance(imported_cls, type): + raise TypeError(f'{cls_str} should be a type ' + f'instance, but got {type(imported_cls)}') + assert hasattr(imported_cls, method_str), \ + f'{method_str} is not in {mod_str}.' + + method = getattr(imported_cls, method_str) + + method_registry = UntracedMethodRegistry(method) + method_registry.__set_name__(imported_cls, method_str) + + def call_method(self, m: torch.nn.Module, name: str, method: Callable, + args: Tuple, kwargs: Dict): + """Method that specifies the behavior of this ``Tracer`` when it + encounters a call to an ``nn.Module`` instance. + + By default, the behavior is to check if the called module is a leaf + module via ``is_leaf_module``. If it is, emit a ``call_module`` + node referring to ``m`` in the ``Graph``. Otherwise, call the + ``Module`` normally, tracing through the operations in its ``forward`` + function. + + This method can be overridden to--for example--create nested traced + GraphModules, or any other behavior you would want while tracing across + ``Module`` boundaries. + + Args: + m (torch.nn.Module): The module for which a call is being emitted + name (str): The name of proxy to be created. + method (Callable): The method of the ``Module`` to be invoked + args (Tuple): args of the module callsite + kwargs (Dict): kwargs of the module callsite + + Return: + + The return value from the Module call. In the case that a + ``call_module`` node was emitted, this is a ``Proxy`` value. + Otherwise, it is whatever value was returned from the ``Module`` + invocation. + """ + # module_qualified_name = self.path_of_module(m) + if not self.is_skipped_method(m): + return method(*args, **kwargs) + args_l = list(args) + args_l.insert(0, m) + args = tuple(args_l) + return self.create_proxy('call_method', name, args, kwargs) + + def trace(self, + root: Union[torch.nn.Module, Callable[..., Any]], + concrete_args: Optional[Dict[str, Any]] = None) -> Graph: + """Trace ``root`` and return the corresponding FX ``Graph`` + representation. ``root`` can either be an ``nn.Module`` instance or a + Python callable. Note that after this call, ``self.root`` may be + different from the ``root`` passed in here. For example, when a free + function is passed to ``trace()``, we will create an ``nn.Module`` + instance to use as the root and add embedded constants to. + + Args: + root (Union[Module, Callable]): Either a ``Module`` or a function + to be traced through. Backwards-compatibility for this + parameter is guaranteed. + concrete_args (Optional[Dict[str, any]]): Concrete arguments that + should not be treated as Proxies. This parameter is + experimental and its backwards-compatibility is *NOT* + guaranteed. + + Returns: + A ``Graph`` representing the semantics of the passed-in ``root``. + """ + if isinstance(root, torch.nn.Module): + self.root = root + fn = type(root).forward + self.submodule_paths: Optional[Dict[torch.nn.Module, str]] = { + mod: name + for name, mod in root.named_modules() + } + else: + self.root = nn.Module() + fn = root + + tracer_cls: Optional[Type['Tracer']] = getattr(self, '__class__', None) + self.graph = Graph(tracer_cls=tracer_cls) + + # When we encounter a Tensor value that's not a parameter, we look if + # it is some other attribute on the model. Construct a dict mapping + # Tensor values to the qualified name here for efficiency. This is + # used downstream in create_arg + self.tensor_attrs: Dict[Union[torch.Tensor, ScriptObject], str] = {} + + def collect_tensor_attrs(m: nn.Module, prefix_atoms: List[str]): + for k, v in m.__dict__.items(): + if isinstance(v, (torch.Tensor, ScriptObject)): + self.tensor_attrs[v] = '.'.join(prefix_atoms + [k]) + for k, v in m.named_children(): + collect_tensor_attrs(v, prefix_atoms + [k]) + + collect_tensor_attrs(self.root, []) + + assert isinstance(fn, FunctionType) + + fn_globals = fn.__globals__ # run before it gets patched + fn, args = self.create_args_for_root(fn, isinstance(root, nn.Module), + concrete_args) + + # Reduce number of get_attr calls + parameter_proxy_cache: Dict[str, Proxy] = {} + + # Method dispatch on parameters is not recorded unless it's directly + # used. Thus, we need to insert a proxy when __getattr__ requests a + # parameter. + @functools.wraps(_orig_module_getattr) + def module_getattr_wrapper(mod, attr): + attr_val = _orig_module_getattr(mod, attr) + return self.getattr(attr, attr_val, parameter_proxy_cache) + + @functools.wraps(_orig_module_call) + def module_call_wrapper(mod, *args, **kwargs): + + def forward(*args, **kwargs): + return _orig_module_call(mod, *args, **kwargs) + + _autowrap_check( + patcher, + getattr(getattr(mod, 'forward', mod), '__globals__', {}), + self._autowrap_function_ids) + return self.call_module(mod, forward, args, kwargs) + + with _Patcher() as patcher: + # allow duplicate patches to support the case of nested calls + patcher.patch_method( + nn.Module, + '__getattr__', + module_getattr_wrapper, + deduplicate=False) + patcher.patch_method( + nn.Module, '__call__', module_call_wrapper, deduplicate=False) + + for name, value in UntracedMethodRegistry.method_dict.items(): + wrapped = value['wrapped'] + patcher.patch_method( + value['mod'], name, wrapped, deduplicate=False) + + _patch_wrapped_functions(patcher) + _autowrap_check(patcher, fn_globals, self._autowrap_function_ids) + for module in self._autowrap_search: + _autowrap_check(patcher, module.__dict__, + self._autowrap_function_ids) + self.create_node( + 'output', + 'output', (self.create_arg(fn(*args)), ), {}, + type_expr=fn.__annotations__.get('return', None)) + + self.submodule_paths = None + + return self.graph + + def is_skipped_method(self, m: torch.nn.Module): + """Judge if ``m`` is registered skipped method.""" + mods = tuple(value['mod'] + for value in UntracedMethodRegistry.method_dict.values()) + custom = isinstance(m, mods) + return custom + + def is_leaf_module(self, m: torch.nn.Module, + module_qualified_name: str) -> bool: + """A method to specify whether a given ``nn.Module`` is a "leaf" + module. Leaf modules are the atomic units that appear in the IR, + referenced by ``call_module`` calls. By default, Modules in the PyTorch + standard library namespace (torch.nn) are leaf modules. All other + modules are traced through and their constituent ops are recorded, + unless specified otherwise via this parameter. + + Args: + m (Module): The module being queried about + module_qualified_name (str): The path to root of this module. + For example, if you have a module hierarchy where submodule + ``foo`` contains submodule ``bar``, which contains submodule + ``baz``, that module will appear with the qualified name + ``foo.bar.baz`` here. + """ + leaf = super().is_leaf_module(m, module_qualified_name) + return leaf + + +def custom_symbolic_trace( + root: Union[torch.nn.Module, Callable[..., Any]], + concrete_args: Optional[Dict[str, Any]] = None) -> GraphModule: + """Modified `symbolic_trace` function in pytorch. Given an ``nn.Module`` or + function instance ``root``, this function will return a ``GraphModule`` + constructed by recording operations seen while tracing through ``root``. + + Args: + root (torch.nn.Module): Module or function to be + traced and converted into a Graph representation. + concrete_args (Optional[Dict[str, any]]): Inputs to be partially + specialized. + + Returns: + GraphModule: a Module created from the recorded operations from + ``root``. + """ + tracer = CustomTracer() + graph = tracer.trace(root, concrete_args) + name = root.__class__.__name__ if isinstance( + root, torch.nn.Module) else root.__name__ + return GraphModule(tracer.root, graph, name) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/graph_utils.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/graph_utils.py new file mode 100755 index 000000000..ca1291711 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/graph_utils.py @@ -0,0 +1,387 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Any, List, Tuple + +import torch + +try: + from torch.ao.quantization.fake_quantize import FakeQuantizeBase + from torch.fx import Node +except ImportError: + from mmrazor.utils import get_placeholder + FakeQuantizeBase = get_placeholder('torch>=1.13') + Node = get_placeholder('torch>=1.13') + + +def _get_attrs(target: torch.nn.Module, attr: str) -> Any: + """Get the attribute from target. + + Args: + target (torch.nn.Module): Get the attribute from target module. + attr (str): The target attribute. + + Returns: + Any: The target attribute. + """ + + attrs: List[str] = attr.split('.') + + for att in attrs: + target = getattr(target, att, None) + return target + + +def recursive_find_erased_nodes(node, prepared_model): + """Find FakeQuant before target node recursively. + + Examples: + head_fc = self.head.fc(activation_post_process_87); \ + activation_post_process_87 = None + activation_post_process_88 = \ + self.activation_post_process_88(head_fc); head_fc = None + head = self.head + _get_loss = head._get_loss(activation_post_process_88, + data_samples); \ + head = activation_post_process_88 = data_samples = None + return _get_loss + + node | node.args + -------------------- + output | (_get_loss, ) + _get_loss | (head, activation_post_process_88, + data_samples) + head | () + activation_post_process_88 | (head_fc, ) + data_samples | (None, ) + """ + if node is None: + return [] + + if node.op == 'call_module' and isinstance( + _get_attrs(prepared_model, node.target), FakeQuantizeBase): + return [node] + + nodes_to_erase = [] + for prev_node in node.args: + if isinstance(prev_node, Node): + nodes_to_erase.extend( + recursive_find_erased_nodes(prev_node, prepared_model)) + for prev_node in node.kwargs.values(): + if isinstance(prev_node, Node): + nodes_to_erase.extend( + recursive_find_erased_nodes(prev_node, prepared_model)) + + return nodes_to_erase + + +def del_fakequant_before_op(prepared_model, + target_ops: Tuple, + inplace: bool = True): + """Delete useless fakequant before nodes whose ``op`` attribute (node.op) + is in `target_ops`. + + Args: + prepared_model (GraphModule): Prepared standalone module. + target_ops (tuple): Fakequants before nodes whose op attribute + (node.op) is in `target_ops` will be deleted. + inplace (bool): Can optionally do the operation in-place. Defaults to + True. + + Returns: + GraphModule: Prepared standalone module after deletion. + """ + + if not inplace: + prepared_model = copy.deepcopy(prepared_model) + new_graph = copy.deepcopy(prepared_model.graph) + for node in new_graph.nodes: + if node.op in target_ops: + nodes_to_erase: List[Node] = recursive_find_erased_nodes( + node, prepared_model) + for to_erase in nodes_to_erase: + assert to_erase.op == 'call_module' and isinstance( + _get_attrs(prepared_model, to_erase.target), + FakeQuantizeBase) and len(to_erase.args) == 1 + to_erase.replace_all_uses_with(to_erase.args[0]) + new_graph.erase_node(to_erase) + delattr(prepared_model, to_erase.target) + + new_graph.lint() + prepared_model.graph = new_graph + return prepared_model + + +def del_fakequant_after_op(prepared_model, + target_ops: Tuple, + inplace: bool = True): + """Delete useless fakequant after nodes whose ``op`` attribute (node.op) is + in `target_ops`. + + Args: + prepared_model (GraphModule): Prepared standalone module. + target_ops (tuple): Fakequants after nodes whose op attribute + (node.op) is in `target_ops` will be deleted. + inplace (bool): Can optionally do the operation in-place. Defaults to + True. + + Returns: + GraphModule: Prepared standalone module after deletion. + """ + if not inplace: + prepared_model = copy.deepcopy(prepared_model) + new_graph = copy.deepcopy(prepared_model.graph) + + target_nodes = [] + for node in new_graph.nodes: + if node.op in target_ops: + target_nodes.append(node) + + for node in new_graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared_model, node.target), FakeQuantizeBase): + assert len(node.args) == 1 + prev_node = node.args[0] + if prev_node not in target_nodes: + continue + node.replace_all_uses_with(prev_node) + new_graph.erase_node(node) + delattr(prepared_model, node.target) + + new_graph.lint() + prepared_model.graph = new_graph + return prepared_model + + +def del_fakequant_before_method(prepared_model, + method_patterns: Tuple, + inplace: bool = True): + """Delete useless fakequant before nodes whose op attribute (node.op) is + `call_method` and target attribute (node.target) is in `target_patterns`. + + Args: + prepared_model (GraphModule): Prepared standalone module. + target_patterns (tuple): Fakequants before nodes whose op attribute + (node.op) is `call_method` and target attribute (node.target) is + in `target_patterns` will be deleted. + inplace (bool): Can optionally do the operation in-place. Defaults to + True. + + Returns: + GraphModule: Prepared standalone module after deletion. + """ + if not inplace: + prepared_model = copy.deepcopy(prepared_model) + new_graph = copy.deepcopy(prepared_model.graph) + for node in new_graph.nodes: + if node.op == 'call_method' and node.target in method_patterns: + nodes_to_erase: List[Node] = recursive_find_erased_nodes( + node, prepared_model) + for to_erase in nodes_to_erase: + assert to_erase.op == 'call_module' and isinstance( + _get_attrs(prepared_model, to_erase.target), + FakeQuantizeBase) and len(to_erase.args) == 1 + to_erase.replace_all_uses_with(to_erase.args[0]) + new_graph.erase_node(to_erase) + delattr(prepared_model, to_erase.target) + + new_graph.lint() + prepared_model.graph = new_graph + return prepared_model + + +def del_fakequant_after_method(prepared_model, + method_patterns: Tuple, + inplace: bool = True): + """Delete useless fakequant after nodes whose op attribute (node.op) is + `call_method` and target attribute (node.target) is in `target_patterns`. + + Args: + prepared_model (GraphModule): Prepared standalone module. + target_patterns (tuple): Fakequants after nodes whose op attribute + (node.op) is `call_method` and target attribute (node.target) + is in `target_patterns` will be deleted. + inplace (bool): Can optionally do the operation in-place. Defaults to + True. + + Returns: + GraphModule: Prepared standalone module after deletion. + """ + if not inplace: + prepared_model = copy.deepcopy(prepared_model) + new_graph = copy.deepcopy(prepared_model.graph) + + target_nodes = [] + for node in new_graph.nodes: + if node.op == 'call_method' and node.target in method_patterns: + target_nodes.append(node) + + for node in new_graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared_model, node.target), FakeQuantizeBase): + assert len(node.args) == 1 + prev_node = node.args[0] + if prev_node not in target_nodes: + continue + node.replace_all_uses_with(prev_node) + new_graph.erase_node(node) + delattr(prepared_model, node.target) + + new_graph.lint() + prepared_model.graph = new_graph + return prepared_model + + +def del_fakequant_before_function(prepared_model, + function_patterns: Tuple, + inplace: bool = True): + """Delete useless fakequant before nodes whose op attribute (node.op) is + `call_function` and target attribute (node.target) is in `target_patterns`. + + Args: + prepared_model (GraphModule): Prepared standalone module. + target_patterns (tuple): Fakequants before nodes whose op attribute + (node.op) is `call_function` and target attribute (node.target) is + in `target_patterns` will be deleted. + inplace (bool): Can optionally do the operation in-place. Defaults to + True. + + Returns: + GraphModule: Prepared standalone module after deletion. + """ + if not inplace: + prepared_model = copy.deepcopy(prepared_model) + new_graph = copy.deepcopy(prepared_model.graph) + for node in new_graph.nodes: + if node.op == 'call_function' and node.target in function_patterns: + nodes_to_erase: List[Node] = recursive_find_erased_nodes( + node, prepared_model) + for to_erase in nodes_to_erase: + assert to_erase.op == 'call_module' and isinstance( + _get_attrs(prepared_model, to_erase.target), + FakeQuantizeBase) and len(to_erase.args) == 1 + to_erase.replace_all_uses_with(to_erase.args[0]) + new_graph.erase_node(to_erase) + delattr(prepared_model, to_erase.target) + + new_graph.lint() + prepared_model.graph = new_graph + return prepared_model + + +def del_fakequant_after_function(prepared_model, + function_patterns: Tuple, + inplace: bool = True): + """Delete useless fakequant after nodes whose op attribute (node.op) is + `call_function` and target attribute (node.target) is in `target_patterns`. + + Args: + prepared_model (GraphModule): Prepared standalone module. + function_patterns (tuple): Fakequants after nodes whose op attribute + (node.op) is `call_function` and target attribute (node.target) is + in `target_patterns` will be deleted. + inplace (bool): Can optionally do the operation in-place. Defaults to + True. + + Returns: + GraphModule: Prepared standalone module after deletion. + """ + if not inplace: + prepared_model = copy.deepcopy(prepared_model) + new_graph = copy.deepcopy(prepared_model.graph) + + target_nodes = [] + for node in new_graph.nodes: + if node.op == 'call_function' and node.target in function_patterns: + target_nodes.append(node) + + for node in new_graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared_model, node.target), FakeQuantizeBase): + assert len(node.args) == 1 + prev_node = node.args[0] + if prev_node not in target_nodes: + continue + node.replace_all_uses_with(prev_node) + new_graph.erase_node(node) + delattr(prepared_model, node.target) + + new_graph.lint() + prepared_model.graph = new_graph + return prepared_model + + +def del_fakequant_before_module(prepared_model, + module_patterns: Tuple, + inplace: bool = True): + """Delete useless fakequant before modules whose type are in + `module_patterns`. + + Args: + prepared_model (GraphModule): Prepared standalone module. + target_patterns (tuple): Fakequants before modules whose type is in + `module_patterns` will be deleted. + inplace (bool): Can optionally do the operation in-place. + Defaults to True. + + Returns: + GraphModule: Prepared standalone module after deletion. + """ + if not inplace: + prepared_model = copy.deepcopy(prepared_model) + new_graph = copy.deepcopy(prepared_model.graph) + for node in new_graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared_model, node.target), module_patterns): + to_erase = node.args[0] + if not (to_erase.op == 'call_module' and isinstance( + _get_attrs(prepared_model, to_erase.target), + FakeQuantizeBase)): + continue + to_erase.replace_all_uses_with(to_erase.args[0]) + new_graph.erase_node(to_erase) + delattr(prepared_model, to_erase.target) + + new_graph.lint() + prepared_model.graph = new_graph + return prepared_model + + +def del_fakequant_after_module(prepared_model, + module_patterns: Tuple, + inplace: bool = True): + """Delete useless fakequant after modules whose type are in + `module_patterns`. + + Args: + prepared_model (GraphModule): Prepared standalone module. + target_patterns (tuple): Fakequants after modules whose type is in + `module_patterns` will be deleted. + inplace (bool): Can optionally do the operation in-place. + Defaults to True. + + Returns: + GraphModule: Prepared standalone module after deletion. + """ + if not inplace: + prepared_model = copy.deepcopy(prepared_model) + new_graph = copy.deepcopy(prepared_model.graph) + target_nodes = [] + for node in new_graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared_model, node.target), module_patterns): + target_nodes.append(node) + + for node in new_graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared_model, node.target), FakeQuantizeBase): + assert len(node.args) == 1 + prev_node = node.args[0] + if prev_node not in target_nodes: + continue + node.replace_all_uses_with(prev_node) + new_graph.erase_node(node) + delattr(prepared_model, node.target) + + new_graph.lint() + prepared_model.graph = new_graph + return prepared_model diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx_tracer.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx_tracer.py new file mode 100755 index 000000000..23b4c3325 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx_tracer.py @@ -0,0 +1,359 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This module define FxTracer and related classes.""" +# flake8: noqa +import functools +import inspect +import sys +import types +from types import FunctionType, ModuleType +from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, Union + +import torch +import torch.nn as nn +from mmengine import MMLogger +from torch._C import ScriptObject # type: ignore[attr-defined] + +from mmrazor.utils import get_placeholder + +try: + from torch.fx._symbolic_trace import (Tracer, _find_proxy, + _orig_module_call, + _orig_module_getattr, + _patch_wrapped_functions, _Patcher) + from torch.fx.graph import Graph + from torch.fx.node import Argument + from torch.fx.proxy import Proxy +except ImportError: + Tracer = get_placeholder('torch>=1.12') + _find_proxy = get_placeholder('torch>=1.12') + _orig_module_call = get_placeholder('torch>=1.12') + _orig_module_getattr = get_placeholder('torch>=1.12') + _patch_wrapped_functions = get_placeholder('torch>=1.12') + _Patcher = get_placeholder('torch>=1.12') + Graph = get_placeholder('torch>=1.12') + Argument = get_placeholder('torch>=1.12') + Proxy = get_placeholder('torch>=1.12') + +from mmrazor import digit_version + +sys.setrecursionlimit(int(pow(2, 20))) + +logger = MMLogger.get_current_instance() + + +def _autowrap_check(patcher: _Patcher, frame_dict: Dict[str, Any], + function_ids: Set[int]): + auto_wrapper = AutoWrapper(patcher) + auto_wrapper.wrap(None, '', frame_dict) + + +def auto_wrap(patcher, owner): + auto_wrapper = AutoWrapper(patcher) + auto_wrapper.wrap(None, '', owner) + + +class AutoWrapper: + + def __init__(self, patcher) -> None: + self.patcher: _Patcher = patcher + + # wrap + + def wrap(self, owner, name, val): + + def is_method(val): + return (inspect.ismethod(val) or inspect.isfunction(val) + or isinstance(val, types.BuiltinFunctionType) + or isinstance(val, staticmethod) + or isinstance(val, classmethod)) + + if owner is None and isinstance(val, dict): + self.wrap_frame(owner, name, val) + else: + # class + if inspect.isclass(val): + self.wrap_class(owner, name, val) + # method + elif inspect.isclass(owner) and is_method(val): + self.wrap_method(owner, name, val) + # function + elif inspect.isfunction(val) or isinstance( + val, types.BuiltinFunctionType): + self.wrap_function(owner, name, val) + # package + elif isinstance(val, ModuleType): + self.wrap_module(owner, name, val) + # instance + elif isinstance(val, object): + self.wrap_class(None, '', type(val)) + # else + else: + logger.debug(f'unsupported type to wrap: {name}/{type(val)}') + + def wrap_frame(self, owner, name: str, val: dict): + assert isinstance(val, dict) + + if self.patcher.visit_once(val): + frame_name = val['__name__'] if '__name__' in val else '' + logger.debug(f'wrap a frame {frame_name}') + for key in val: + self.wrap(val, key, val[key]) + + def wrap_module(self, owner, name, val): + if self.visit_once(val): + if val in [torch]: + logger.debug(f'wrap a module {owner[name]}') + self.wrap(None, '', val.__dict__) + + def wrap_class(self, owner, name, val): + assert inspect.isclass(val) + if issubclass(val, nn.Module): + if self.visit_once(val): + logger.debug(f'wrap a class {val}') + for key in val.__dict__: + key: str + if not (key.startswith('__')): + self.wrap(val, key, val.__dict__[key]) + + def wrap_function(self, owner, name, val): + if self.visit_once(val): + self.patcher.patch(owner, name, self.func_wapper(val)) + logger.debug(f'wrap a function {name}') + + def wrap_method(self, owner, name, val): + assert inspect.isclass(owner) + if self.visit_once(val): + try: + if isinstance(val, staticmethod): + pass + logger.debug(f'wrap a staticmethod {name} (unimplement)') + elif isinstance(val, classmethod): + pass + logger.debug(f'wrap a classmethod {name} (unimplement)') + else: + self.patcher.patch_method(owner, name, + self.method_wrapper(val)) + logger.debug(f'wrap an instance method {name}') + except Exception: + self.patcher.patches_made.pop() + + # wrapper + def func_wapper(self, orig_fn): + + @functools.wraps(orig_fn) + def wrapped(*args, **kwargs): + """Given an closed-over ``orig_function`` to invoke, search the + args and kwargs for a Proxy object. + + If there is one, emit a ``call_function`` node to preserve the call + to this leaf function directly. Otherwise, just return the results + of this function call, as this function is not being traced. + """ + _autowrap_check(self.patcher, getattr(orig_fn, '__globals__', {}), + set()) + try: + end = orig_fn(*args, **kwargs) + return end + except Exception: + logger.debug(f'auto wrap {orig_fn}') + proxy = _find_proxy(args, kwargs) + if proxy is not None: + return_proxy = proxy.tracer.create_proxy( + 'call_function', orig_fn, args, kwargs) + return_proxy.node.meta['is_wrapped'] = True + return return_proxy + else: + return orig_fn(*args, **kwargs) + + return wrapped + + def method_wrapper(self, orig_fn): + + @functools.wraps(orig_fn) + def wrapped(*args, **kwargs): + """Given an closed-over ``orig_function`` to invoke, search the + args and kwargs for a Proxy object. + + If there is one, emit a ``call_function`` node to preserve the call + to this leaf function directly. Otherwise, just return the results + of this function call, as this function is not being traced. + """ + _autowrap_check(self.patcher, getattr(orig_fn, '__globals__', {}), + set()) + # logger.debug(f'call method {orig_fn}') + try: + end = orig_fn(*args, **kwargs) + return end + except Exception: + logger.debug(f'auto wrap {orig_fn}') + proxy: Proxy = _find_proxy(args, kwargs) + if proxy is not None: + return_proxy = proxy.tracer.create_proxy( + 'call_method', orig_fn.__name__, args, kwargs) + return_proxy.node.meta['is_wrapped'] = True + return return_proxy + else: + return orig_fn(*args, **kwargs) + + return wrapped + + # others + def visit_once(self, obj): + return self.patcher.visit_once(obj) + + def is_visited(self, obj): + id_ = id(obj) + return id_ in self.patcher.visited + + +class FxTracer(Tracer): + + def trace(self, + root: Union[torch.nn.Module, Callable[..., Any]], + concrete_args: Optional[Dict[str, Any]] = None) -> Graph: + """Please refer to torch.fx._symbolic_trace.Tracer.""" + if isinstance(root, torch.nn.Module): + self.root = root + + assert hasattr(type(root), self.traced_func_name), ( + f"traced_func_name={self.traced_func_name} doesn't exist in {type(root).__name__}" # noqa + ) # noqa + + fn = getattr(type(root), self.traced_func_name) + self.submodule_paths = { + mod: name + for name, mod in root.named_modules() + } + else: + self.root = torch.nn.Module() + fn = root + + tracer_cls: Optional[Type['Tracer']] = getattr(self, '__class__', None) + self.graph = Graph(tracer_cls=tracer_cls) + + # When we encounter a Tensor value that's not a parameter, we look if it + # is some other attribute on the model. Construct a dict mapping Tensor + # values to the qualified name here for efficiency. This is used downstream + # in create_arg + self.tensor_attrs: Dict[Union[torch.Tensor, ScriptObject], str] = {} + + def collect_tensor_attrs(m: torch.nn.Module, prefix_atoms: List[str]): + for k, v in m.__dict__.items(): + if isinstance(v, (torch.Tensor, ScriptObject)): + self.tensor_attrs[v] = '.'.join(prefix_atoms + [k]) + for k, v in m.named_children(): + collect_tensor_attrs(v, prefix_atoms + [k]) + + collect_tensor_attrs(self.root, []) + + assert isinstance(fn, FunctionType) + + fn_globals = fn.__globals__ # run before it gets patched + fn, args = self.create_args_for_root(fn, + isinstance(root, torch.nn.Module), + concrete_args) + + parameter_proxy_cache: Dict[str, Proxy] = { + } # Reduce number of get_attr calls + + # Method dispatch on parameters is not recorded unless it's directly used. + # Thus, we need to insert a proxy when __getattr__ requests a parameter. + @functools.wraps(_orig_module_getattr) + def module_getattr_wrapper(mod, attr): + attr_val = _orig_module_getattr(mod, attr) + ######################################################################## + if digit_version(torch.__version__) >= digit_version('1.13.0'): + return self.getattr(attr, attr_val, parameter_proxy_cache) + else: + return self._module_getattr(attr, attr_val, + parameter_proxy_cache) + ######################################################################## + @functools.wraps(_orig_module_call) + def module_call_wrapper(mod, *args, **kwargs): + + def forward(*args, **kwargs): + return _orig_module_call(mod, *args, **kwargs) + + _autowrap_check( + patcher, + getattr(getattr(mod, 'forward', mod), '__globals__', {}), + self._autowrap_function_ids) + ######################################################################## + auto_wrap(patcher, mod) + ######################################################################## + + return self.call_module(mod, forward, args, kwargs) + + with _Patcher() as patcher: + # allow duplicate patches to support the case of nested calls + patcher.patch_method( + torch.nn.Module, + '__getattr__', + module_getattr_wrapper, + deduplicate=False) + patcher.patch_method( + torch.nn.Module, + '__call__', + module_call_wrapper, + deduplicate=False) + _patch_wrapped_functions(patcher) + ######################################################################## + patcher.visit_once(globals()) + auto_wrap(patcher, self.root) + ######################################################################## + _autowrap_check(patcher, fn_globals, self._autowrap_function_ids) + for module in self._autowrap_search: + _autowrap_check(patcher, module.__dict__, + self._autowrap_function_ids) + self.create_node( + 'output', + 'output', (self.create_arg(fn(*args)), ), {}, + type_expr=fn.__annotations__.get('return', None)) + + self.submodule_paths = None # type:ignore + + return self.graph + + def call_module(self, m: torch.nn.Module, forward: Callable[..., Any], + args: Tuple[Any, ...], kwargs: Dict[str, Any]) -> Any: + + try: + return super().call_module(m, forward, args, kwargs) + except Exception: + module_qualified_name = self.path_of_module(m) + return self.create_proxy('call_module', module_qualified_name, + args, kwargs) + + def create_arg(self, a: Any) -> 'Argument': + try: + arg = super().create_arg(a) + return arg + except Exception: + return a + + +class MMFxTracer(FxTracer): + + def __init__( + self, + autowrap_modules: Tuple = (), + autowrap_functions: Tuple[Callable, ...] = (), + param_shapes_constant: bool = False, + leaf_module: Tuple = (), + ) -> None: + super().__init__(autowrap_modules, autowrap_functions, + param_shapes_constant) + + self.leaf_module = leaf_module + + def is_leaf_module(self, m: torch.nn.Module, + module_qualified_name: str) -> bool: + is_torch_module = super().is_leaf_module(m, module_qualified_name) + + is_leaf = False + for module_type in self.leaf_module: + if isinstance(m, module_type): + is_leaf = True + break + + return is_leaf or is_torch_module diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/__init__.py new file mode 100755 index 000000000..f013c8cb9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/__init__.py @@ -0,0 +1,16 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .cascade_encoder_decoder_loss_calculator import \ + CascadeEncoderDecoderPseudoLoss +from .image_classifier_loss_calculator import ImageClassifierPseudoLoss +from .single_stage_detector_loss_calculator import \ + SingleStageDetectorPseudoLoss +from .sum_loss_calculator import SumPseudoLoss +from .top_down_pose_estimator_loss_calculator import \ + TopdownPoseEstimatorPseudoLoss +from .two_stage_detector_loss_calculator import TwoStageDetectorPseudoLoss + +__all__ = [ + 'ImageClassifierPseudoLoss', 'SingleStageDetectorPseudoLoss', + 'TwoStageDetectorPseudoLoss', 'TopdownPoseEstimatorPseudoLoss', + 'CascadeEncoderDecoderPseudoLoss', 'SumPseudoLoss' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/cascade_encoder_decoder_loss_calculator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/cascade_encoder_decoder_loss_calculator.py new file mode 100755 index 000000000..f4f60c843 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/cascade_encoder_decoder_loss_calculator.py @@ -0,0 +1,26 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +from mmrazor.registry import TASK_UTILS + +try: + from mmseg.models import CascadeEncoderDecoder +except ImportError: + from mmrazor.utils import get_placeholder + CascadeEncoderDecoder = get_placeholder('mmseg') + + +@TASK_UTILS.register_module() +class CascadeEncoderDecoderPseudoLoss: + """Calculate the pseudo loss to trace the topology of a + `CascadeEncoderDecoder` in MMSegmentation with `BackwardTracer`.""" + + def __call__(self, model: CascadeEncoderDecoder) -> torch.Tensor: + pseudo_img = torch.rand(1, 3, 224, 224) + pseudo_output = model.backbone(pseudo_img) + pseudo_output = model.neck(pseudo_output) + # unmodified decode_heads + out = torch.tensor(0.) + for levels in pseudo_output: + out += sum([level.sum() for level in levels]) + return out diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/image_classifier_loss_calculator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/image_classifier_loss_calculator.py new file mode 100755 index 000000000..65e908e30 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/image_classifier_loss_calculator.py @@ -0,0 +1,29 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +from mmrazor.registry import TASK_UTILS + +try: + from mmcls.models import ImageClassifier +except ImportError: + from mmrazor.utils import get_placeholder + ImageClassifier = get_placeholder('mmcls') + + +@TASK_UTILS.register_module() +class ImageClassifierPseudoLoss: + """Calculate the pseudo loss to trace the topology of a `ImageClassifier` + in MMClassification with `BackwardTracer`. + + Args: + input_shape (Tuple): The shape of the pseudo input. Defaults to + (2, 3, 224, 224). + """ + + def __init__(self, input_shape=(2, 3, 224, 224)): + self.input_shape = input_shape + + def __call__(self, model: ImageClassifier) -> torch.Tensor: + pseudo_img = torch.rand(self.input_shape) + pseudo_output = model(pseudo_img) + return pseudo_output.sum() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/single_stage_detector_loss_calculator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/single_stage_detector_loss_calculator.py new file mode 100755 index 000000000..f8554580d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/single_stage_detector_loss_calculator.py @@ -0,0 +1,33 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +from mmrazor.registry import TASK_UTILS + +try: + from mmdet.models import SingleStageDetector +except ImportError: + from mmrazor.utils import get_placeholder + SingleStageDetector = get_placeholder('mmdet') + + +@TASK_UTILS.register_module() +class SingleStageDetectorPseudoLoss: + """Calculate the pseudo loss to trace the topology of a + `SingleStageDetector` in MMDetection with `BackwardTracer`. + + Args: + input_shape (Tuple): The shape of the pseudo input. Defaults to + (2, 3, 224, 224). + """ + + def __init__(self, input_shape=(2, 3, 224, 224)): + self.input_shape = input_shape + + def __call__(self, model: SingleStageDetector) -> torch.Tensor: + pseudo_img = torch.rand(self.input_shape) + pseudo_output = model(pseudo_img) + out = torch.tensor(0.) + for levels in pseudo_output: + out += sum([level.sum() for level in levels]) + + return out diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/sum_loss_calculator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/sum_loss_calculator.py new file mode 100755 index 000000000..408b687b1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/sum_loss_calculator.py @@ -0,0 +1,42 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +from mmrazor.registry import TASK_UTILS + + +@TASK_UTILS.register_module() +class SumPseudoLoss: + """Calculate the pseudo loss to trace the topology by summing all output + tensors. + + Args: + input_shape (Tuple): The shape of the pseudo input. Defaults to + (2, 3, 224, 224). + """ + + def __init__(self, input_shape=(2, 3, 224, 224)): + self.input_shape = input_shape + + def __call__(self, model) -> torch.Tensor: + pseudo_img = torch.rand(self.input_shape) + model.eval() + pseudo_output = model(pseudo_img) + return self._sum_of_output(pseudo_output) + + def _sum_of_output(self, tensor): + """Get a loss by summing all tensors.""" + if isinstance(tensor, torch.Tensor): + return tensor.sum() + elif isinstance(tensor, list) or isinstance(tensor, tuple): + loss = 0 + for t in tensor: + loss = loss + self._sum_of_output(t) + return loss + elif isinstance(tensor, dict): + loss = 0 + for t in tensor.values(): + loss = loss + self._sum_of_output(t) + return loss + else: + raise NotImplementedError( + f'unsuppored type{type(tensor)} to get shape of tensors.') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/top_down_pose_estimator_loss_calculator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/top_down_pose_estimator_loss_calculator.py new file mode 100755 index 000000000..9720194f4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/top_down_pose_estimator_loss_calculator.py @@ -0,0 +1,25 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +from mmrazor.registry import TASK_UTILS + +try: + from mmpose.models import TopdownPoseEstimator +except ImportError: + from mmrazor.utils import get_placeholder + TopdownPoseEstimator = get_placeholder('mmpose') + + +@TASK_UTILS.register_module() +class TopdownPoseEstimatorPseudoLoss: + """Calculate the pseudo loss to trace the topology of a + `TopdownPoseEstimator` in MMPose with `BackwardTracer`.""" + + def __call__(self, model: TopdownPoseEstimator) -> torch.Tensor: + pseudo_img = torch.rand(1, 3, 224, 224) + pseudo_output = model.backbone(pseudo_img) + # immutable decode_heads + out = torch.tensor(0.) + for levels in pseudo_output: + out += sum([level.sum() for level in levels]) + return out diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/two_stage_detector_loss_calculator.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/two_stage_detector_loss_calculator.py new file mode 100755 index 000000000..97ff7d282 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/two_stage_detector_loss_calculator.py @@ -0,0 +1,27 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +from mmrazor.registry import TASK_UTILS + +try: + from mmdet.models import TwoStageDetector +except ImportError: + from mmrazor.utils import get_placeholder + TwoStageDetector = get_placeholder('mmdet') + + +# todo: adapt to mmdet 2.0 +@TASK_UTILS.register_module() +class TwoStageDetectorPseudoLoss: + """Calculate the pseudo loss to trace the topology of a `TwoStageDetector` + in MMDet with `BackwardTracer`.""" + + def __call__(self, model: TwoStageDetector) -> torch.Tensor: + pseudo_img = torch.rand(1, 3, 224, 224) + pseudo_output = model.backbone(pseudo_img) + pseudo_output = model.neck(pseudo_output) + out = torch.tensor(0.) + for levels in pseudo_output: + out += sum([level.sum() for level in levels]) + + return out diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/parsers.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/parsers.py new file mode 100755 index 000000000..c342da716 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/parsers.py @@ -0,0 +1,187 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Callable, Dict + +from .path import (Path, PathConcatNode, PathConvNode, PathDepthWiseConvNode, + PathLinearNode, PathList, PathNormNode) + + +def _is_leaf_grad_fn(grad_fn): + """Determine whether the current node is a leaf node.""" + if type(grad_fn).__name__ == 'AccumulateGrad': + return True + return False + + +def parse_conv(tracer, grad_fn, module2name, param2module, cur_path, + result_paths, visited, shared_module): + """Parse the backward of a conv layer. + + Example: + >>> conv = nn.Conv2d(3, 3, 3) + >>> pseudo_img = torch.rand(1, 3, 224, 224) + >>> out = conv(pseudo_img) + >>> out.grad_fn.next_functions + ((None, 0), (, 0), + (, 0)) + >>> # op.next_functions[0][0] is None means this ThnnConv2DBackward + >>> # op has no parents + >>> # op.next_functions[1][0].variable is the weight of this Conv2d + >>> # module + >>> # op.next_functions[2][0].variable is the bias of this Conv2d + >>> # module + """ + leaf_grad_fn = grad_fn.next_functions[1][0] + while not _is_leaf_grad_fn(leaf_grad_fn): + leaf_grad_fn = leaf_grad_fn.next_functions[0][0] + variable = leaf_grad_fn.variable + param_id = id(variable) + module = param2module[param_id] + name = module2name[module] + parent = grad_fn.next_functions[0][0] + if module.in_channels == module.groups: + cur_path.append(PathDepthWiseConvNode(name)) + else: + cur_path.append(PathConvNode(name)) + # If a module is not a shared module and it has been visited during + # forward, its parent modules must have been traced already. + # However, a shared module will be visited more than once during + # forward, so it is still need to be traced even if it has been + # visited. + if visited[name] and name not in shared_module: + result_paths.append(copy.deepcopy(cur_path)) + else: + visited[name] = True + tracer.backward_trace(parent, module2name, param2module, cur_path, + result_paths, visited, shared_module) + cur_path.pop(-1) + + +# todo: support parsing `MultiheadAttention` and user-defined matrix +# multiplication +def parse_linear(tracer, grad_fn, module2name, param2module, cur_path, + result_paths, visited, shared_module): + """Parse the backward of a conv layer. + + Example: + >>> fc = nn.Linear(3, 3, bias=True) + >>> input = torch.rand(3, 3) + >>> out = fc(input) + >>> out.grad_fn.next_functions + ((, 0), (None, 0), + (, 0)) + >>> # op.next_functions[0][0].variable is the bias of this Linear + >>> # module + >>> # op.next_functions[1][0] is None means this AddmmBackward op + >>> # has no parents + >>> # op.next_functions[2][0] is the TBackward op, and + >>> # op.next_functions[2][0].next_functions[0][0].variable is + >>> # the transpose of the weight of this Linear module + """ + leaf_grad_fn = grad_fn.next_functions[-1][0].next_functions[0][0] + while not _is_leaf_grad_fn(leaf_grad_fn): + leaf_grad_fn = leaf_grad_fn.next_functions[0][0] + variable = leaf_grad_fn.variable + param_id = id(variable) + module = param2module[param_id] + name = module2name[module] + parent = grad_fn.next_functions[-2][0] + + cur_path.append(PathLinearNode(name)) + # If a module is not a shared module and it has been visited during + # forward, its parent modules must have been traced already. + # However, a shared module will be visited more than once during + # forward, so it is still need to be traced even if it has been + # visited. + if visited[name] and name not in shared_module: + result_paths.append(copy.deepcopy(cur_path)) + else: + visited[name] = True + tracer.backward_trace(parent, module2name, param2module, cur_path, + result_paths, visited, shared_module) + + +def parse_cat(tracer, grad_fn, module2name, param2module, cur_path, + result_paths, visited, shared_module): + """Parse the backward of a concat operation. + + Example: + >>> conv = nn.Conv2d(3, 3, 3) + >>> pseudo_img = torch.rand(1, 3, 224, 224) + >>> out1 = conv(pseudo_img) + >>> out2 = conv(pseudo_img) + >>> out = torch.cat([out1, out2], dim=1) + >>> out.grad_fn.next_functions + ((, 0), + (, 0)) + >>> # the length of ``out.grad_fn.next_functions`` is two means + >>> # ``out`` is obtained by concatenating two tensors + """ + parents = grad_fn.next_functions + concat_id = '_'.join([str(id(p)) for p in parents]) + concat_id_list = [str(id(p)) for p in parents] + concat_id_list.sort() + concat_id = '_'.join(concat_id_list) + name = f'concat_{concat_id}' + + visited[name] = True + sub_path_lists = list() + for _, parent in enumerate(parents): + sub_path_list = PathList() + tracer.backward_trace(parent, module2name, param2module, Path(), + sub_path_list, visited, shared_module) + sub_path_lists.append(sub_path_list) + cur_path.append(PathConcatNode(name, sub_path_lists)) + + result_paths.append(copy.deepcopy(cur_path)) + cur_path.pop(-1) + + +def parse_norm(tracer, grad_fn, module2name, param2module, cur_path, + result_paths, visited, shared_module): + """Parse the backward of a concat operation. + + Example: + >>> conv = nn.Conv2d(3, 3, 3) + >>> pseudo_img = torch.rand(1, 3, 224, 224) + >>> out1 = conv(pseudo_img) + >>> out2 = conv(pseudo_img) + >>> out = torch.cat([out1, out2], dim=1) + >>> out.grad_fn.next_functions + ((, 0), + (, 0)) + >>> # the length of ``out.grad_fn.next_functions`` is two means + >>> # ``out`` is obtained by concatenating two tensors + """ + leaf_grad_fn = grad_fn.next_functions[1][0] + while not _is_leaf_grad_fn(leaf_grad_fn): + leaf_grad_fn = leaf_grad_fn.next_functions[0][0] + variable = leaf_grad_fn.variable + param_id = id(variable) + module = param2module[param_id] + name = module2name[module] + parent = grad_fn.next_functions[0][0] + cur_path.append(PathNormNode(name)) + + visited[name] = True + tracer.backward_trace(parent, module2name, param2module, cur_path, + result_paths, visited, shared_module) + cur_path.pop(-1) + + +DEFAULT_BACKWARD_TRACER: Dict[str, Callable] = { + 'ConvolutionBackward': parse_conv, + 'SlowConv2DBackward': parse_conv, + 'ThnnConv2DBackward': parse_conv, + 'CudnnConvolutionBackward': parse_conv, + 'MkldnnConvolutionBackward': parse_conv, + 'SlowConvDilated2DBackward': parse_conv, + 'ThAddmmBackward': parse_linear, + 'AddmmBackward': parse_linear, + 'MmBackward': parse_linear, + 'CatBackward': parse_cat, + 'ThnnBatchNormBackward': parse_norm, + 'CudnnBatchNormBackward': parse_norm, + 'NativeBatchNormBackward': parse_norm, + 'NativeGroupNormBackward': parse_norm +} diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/path.py b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/path.py new file mode 100755 index 000000000..c6597703f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/path.py @@ -0,0 +1,359 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List, Optional, Tuple, Union + + +def _addindent(s_, numSpaces): + s = s_.split('\n') + # don't do anything for single-line stuff + if len(s) == 1: + return s_ + first = s.pop(0) + s = [(numSpaces * ' ') + line for line in s] + s = '\n'.join(s) + s = first + '\n' + s + return s + + +def _merge_node_parents(node2parents, _node2parents): + for node, parents in _node2parents.items(): + if node in node2parents: + cur_parents = node2parents[node] + new_parents_set = set(cur_parents + parents) + new_parents = list(new_parents_set) + node2parents[node] = new_parents + else: + node2parents[node] = parents + + +class PathNode: + """``Node`` is the data structure that represents individual instances + within a ``Path``. It corresponds to a module or an operation such as + concatenation in the model. + + Args: + name (str): Unique identifier of a node. + """ + + def __init__(self, name: str) -> None: + self._name = name + + def get_module_names(self) -> List: + return [self.name] + + @property + def name(self) -> str: + """Get the name of current node.""" + return self._name + + def _get_class_name(self): + return self.__class__.__name__ + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.name == other.name + else: + return False + + def __hash__(self): + return hash(self.name) + + def __repr__(self): + return f'{self._get_class_name()}(\'{self.name}\')' + + +class PathConvNode(PathNode): + """A `ConvNode` corresponds to a Conv module in the original model.""" + pass + + +class PathDepthWiseConvNode(PathNode): + """A `DepthWiseConvNode` corresponds to a depth-wise conv module in the + original model.""" + pass + + +class PathNormNode(PathNode): + """A `NormNode` corresponds to a normalization module in the original + model.""" + pass + + +class PathLinearNode(PathNode): + """A `LinearNode` corresponds to a linear module in the original model.""" + pass + + +class Path: + """``Path`` is the data structure that represents a list of ``Node`` traced + by a tracer. + + Args: + nodes(:obj:`Node` or List[:obj:`Node`], optional): Nodes in a path. + Default to None. + """ + + def __init__(self, + nodes: Optional[Union[PathNode, List[PathNode]]] = None): + self._nodes: List[PathNode] = list() + if nodes is not None: + if isinstance(nodes, PathNode): + nodes = [nodes] + assert isinstance(nodes, (list, tuple)) + for node in nodes: + assert isinstance(node, PathNode) + self._nodes.append(node) + + def get_root_names(self) -> List[str]: + """Get the name of the first node in a path.""" + return self._nodes[0].get_module_names() + + def find_nodes_parents(self, + target_nodes: Tuple, + non_pass: Optional[Tuple] = None) -> Dict: + """Find the parents of a specific node. + + Args: + target_nodes (Tuple): Find the parents of nodes whose types + are one of `target_nodes`. + non_pass (Tuple): Ancestor nodes whose types are one of + `non_pass` are the parents of a specific node. Default to None. + """ + node2parents: Dict[str, List[PathNode]] = dict() + for i, node in enumerate(self._nodes): + if isinstance(node, PathConcatNode): + _node2parents: Dict[str, + List[PathNode]] = node.find_nodes_parents( + target_nodes, non_pass) + _merge_node_parents(node2parents, _node2parents) + continue + + if isinstance(node, target_nodes): + parents = list() + for behind_node in self._nodes[i + 1:]: + if non_pass is None or isinstance(behind_node, non_pass): + parents.append(behind_node) + break + _node2parents = {node.name: parents} + _merge_node_parents(node2parents, _node2parents) + return node2parents + + @property + def nodes(self) -> List: + """Return a list of nodes in the current path.""" + return self._nodes + + def append(self, x: PathNode) -> None: + """Add a node to the end of the current path.""" + assert isinstance(x, PathNode) + self._nodes.append(x) + + def pop(self, *args, **kwargs): + """Temoves the node at the given index from the path and returns the + removed node.""" + return self._nodes.pop(*args, **kwargs) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.nodes == other.nodes + else: + return False + + def __len__(self): + return len(self._nodes) + + def __getitem__(self, item): + return self._nodes[item] + + def __iter__(self): + for node in self._nodes: + yield node + + def _get_class_name(self) -> str: + """Get the name of the current class.""" + return self.__class__.__name__ + + def __repr__(self): + child_lines = [] + for node in self._nodes: + node_str = repr(node) + node_str = _addindent(node_str, 2) + child_lines.append(node_str) + lines = child_lines + + main_str = self._get_class_name() + '(' + if lines: + main_str += '\n ' + ',\n '.join(lines) + '\n' + main_str += ')' + return main_str + + +class PathList: + """``PathList`` is the data structure that represents a list of ``Path`` + traced by a tracer. + + Args: + paths(:obj:`Path` or List[:obj:`Path`], optional): A list of `Path`. + Default to None. + """ + + def __init__(self, paths: Optional[Union[Path, List[Path]]] = None): + self._paths = list() + if paths is not None: + if isinstance(paths, Path): + paths = [paths] + assert isinstance(paths, (list, tuple)) + for path in paths: + assert isinstance(path, Path) + self._paths.append(path) + + def get_root_names(self) -> List[str]: + """Get the root node of all the paths in `PathList`.""" + root_name_list = [path.get_root_names() for path in self._paths] + for root_names in root_name_list[1:]: + assert root_names == root_name_list[0], \ + f'If the input of a module is a concatenation of several ' \ + f'modules\' outputs, we can use `get_root_names` to get the' \ + f' names of these modules. As `get_root_names` is only used' \ + f' in this case, each element in `root_name_list` should be' \ + f' the same. Got root_name_list = {root_name_list}' + return self._paths[0].get_root_names() + + def find_nodes_parents(self, + target_nodes: Tuple, + non_pass: Optional[Tuple] = None): + """Find the parents of a specific node. + + Args: + target_nodes (Tuple): Find the parents of nodes whose types + are one of `target_nodes`. + non_pass (Tuple): Ancestor nodes whose types are one of + `non_pass` are the parents of a specific node. Default to None. + """ + node2parents: Dict[str, List[PathNode]] = dict() + for p in self._paths: + _node2parents = p.find_nodes_parents(target_nodes, non_pass) + _merge_node_parents(node2parents, _node2parents) + return node2parents + + def append(self, x: Path) -> None: + """Add a path to the end of the current PathList.""" + assert isinstance(x, Path) + self._paths.append(x) + + @property + def paths(self): + """Return all paths in the current PathList.""" + return self._paths + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.paths == other.paths + else: + return False + + def __len__(self): + return len(self._paths) + + def __getitem__(self, item): + return self._paths[item] + + def __iter__(self): + for path in self._paths: + yield path + + def _get_class_name(self) -> str: + """Get the name of the current class.""" + return self.__class__.__name__ + + def __repr__(self): + child_lines = [] + for node in self._paths: + node_str = repr(node) + node_str = _addindent(node_str, 2) + child_lines.append(node_str) + lines = child_lines + + main_str = self._get_class_name() + '(' + if lines: + main_str += '\n ' + ',\n '.join(lines) + '\n' + main_str += ')' + return main_str + + +class PathConcatNode(PathNode): + """``ConcatNode`` is the data structure that represents the concatenation + operation in a model. + + Args: + name (str): Unique identifier of a `ConcatNode`. + path_lists (List[PathList]): Several nodes are concatenated and each + node is the root node of all the paths in a `PathList` + (one of `path_lists`). + """ + + def __init__(self, name: str, path_lists: List[PathList]): + super().__init__(name) + self._path_lists = list() + for path_list in path_lists: + assert isinstance(path_list, PathList) + self._path_lists.append(path_list) + + def get_module_names(self) -> List[str]: + """Several nodes are concatenated. + + Get the names of these nodes. + """ + module_names = list() + for path_list in self._path_lists: + module_names.extend(path_list.get_root_names()) + return module_names + + def find_nodes_parents(self, + target_nodes: Tuple, + non_pass: Optional[Tuple] = None): + """Find the parents of a specific node. + + Args: + target_nodes (Tuple): Find the parents of nodes whose types + are one of `target_nodes`. + non_pass (Tuple): Ancestor nodes whose types are one of + `non_pass` are the parents of a specific node. Default to None. + """ + node2parents: Dict[str, List[PathNode]] = dict() + for p in self._path_lists: + _node2parents = p.find_nodes_parents(target_nodes, non_pass) + _merge_node_parents(node2parents, _node2parents) + return node2parents + + @property + def path_lists(self) -> List[PathList]: + """Return all the path_list.""" + return self._path_lists + + def __len__(self): + return len(self._path_lists) + + def __getitem__(self, item): + return self._path_lists[item] + + def __iter__(self): + for path_list in self._path_lists: + yield path_list + + def _get_class_name(self) -> str: + """Get the name of the current class.""" + return self.__class__.__name__ + + def __repr__(self): + child_lines = [] + for node in self._path_lists: + node_str = repr(node) + node_str = _addindent(node_str, 2) + child_lines.append(node_str) + lines = child_lines + + main_str = self._get_class_name() + '(' + if lines: + main_str += '\n ' + ',\n '.join(lines) + '\n' + main_str += ')' + return main_str diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/__init__.py new file mode 100755 index 000000000..e3be94946 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .make_divisible import make_divisible +from .misc import add_prefix +from .optim_wrapper import reinitialize_optim_wrapper_count_status +from .parse_values import parse_values +from .quantization_util import pop_rewriter_function_record, str2class +from .utils import get_module_device, set_requires_grad + +__all__ = [ + 'make_divisible', 'add_prefix', 'reinitialize_optim_wrapper_count_status', + 'str2class', 'get_module_device', 'set_requires_grad', 'parse_values', + 'pop_rewriter_function_record' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/__init__.py new file mode 100755 index 000000000..23eeb6073 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/__init__.py @@ -0,0 +1,15 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This module is used to expand the channels of a supernet. + +We only expose some tool functions, rather than all DynamicOps and +MutableChannelUnits, as They uses a few hacky operations. +""" +from .tools import (expand_expandable_dynamic_model, expand_static_model, + make_channel_divisible, to_expandable_model) + +__all__ = [ + 'make_channel_divisible', + 'to_expandable_model', + 'expand_expandable_dynamic_model', + 'expand_static_model', +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/ops.py b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/ops.py new file mode 100755 index 000000000..f2bc2b046 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/ops.py @@ -0,0 +1,238 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn + +from mmrazor.models.architectures import dynamic_ops +from mmrazor.models.mutables import MutableChannelContainer +from mmrazor.models.utils import get_module_device + + +class ExpandableMixin: + """This minin coroperates with dynamic ops. + + It defines interfaces to expand the channels of ops. We can get a wider + network than original supernet with it. + """ + + def expand(self, zero=False): + """Expand the op. + + Args: + zero (bool, optional): whether to set new weights to zero. Defaults + to False. + """ + return self.get_expand_op( + self.expanded_in_channel, + self.expanded_out_channel, + zero=zero, + ) + + def get_expand_op(self, in_c, out_c, zero=False): + """Get an expanded op. + + Args: + in_c (int): New input channels + out_c (int): New output channels + zero (bool, optional): Whether to zero new weights. Defaults to + False. + """ + pass + + @property + def _original_in_channel(self): + """Return original in channel.""" + raise NotImplementedError() + + @property + def _original_out_channel(self): + """Return original out channel.""" + + @property + def expanded_in_channel(self): + """Return expanded in channel number.""" + if self.in_mutable is not None: + return self.in_mutable.current_mask.numel() + else: + return self._original_in_channel + + @property + def expanded_out_channel(self): + """Return expanded out channel number.""" + if self.out_mutable is not None: + return self.out_mutable.current_mask.numel() + else: + return self._original_out_channel + + @property + def mutable_in_mask(self): + """Return the mutable in mask.""" + device = get_module_device(self) + if self.in_mutable is not None: + return self.in_mutable.current_mask.to(device) + else: + return torch.ones([self.expanded_in_channel]).to(device) + + @property + def mutable_out_mask(self): + """Return the mutable out mask.""" + device = get_module_device(self) + if self.out_mutable is not None: + return self.out_mutable.current_mask.to(device) + else: + return torch.ones([self.expanded_out_channel]).to(device) + + @property + def in_mutable(self) -> MutableChannelContainer: + """In channel mask.""" + return self.get_mutable_attr('in_channels') # type: ignore + + @property + def out_mutable(self) -> MutableChannelContainer: + """Out channel mask.""" + return self.get_mutable_attr('out_channels') # type: ignore + + def zero_weight_(self: nn.Module): + """Zero all weights.""" + for p in self.parameters(): + p.data.zero_() + + @torch.no_grad() + def expand_matrix(self, weight: torch.Tensor, old_weight: torch.Tensor): + """Expand weight matrix.""" + assert len(weight.shape) == 3 # out in c + assert len(old_weight.shape) == 3 # out in c + mask = self.mutable_out_mask.float().unsqueeze( + -1) * self.mutable_in_mask.float().unsqueeze(0) + mask = mask.unsqueeze(-1).expand(*weight.shape) + weight.data.masked_scatter_(mask.bool(), old_weight) + return weight + + @torch.no_grad() + def expand_vector(self, weight: torch.Tensor, old_weight: torch.Tensor): + """Expand weight vector which has the shape of [out, c].""" + assert len(weight.shape) == 2 # out c + assert len(old_weight.shape) == 2 # out c + mask = self.mutable_out_mask + mask = mask.unsqueeze(-1).expand(*weight.shape) + weight.data.masked_scatter_(mask.bool(), old_weight) + return weight + + @torch.no_grad() + def expand_bias(self, bias: torch.Tensor, old_bias: torch.Tensor): + """Expand bias.""" + assert len(bias.shape) == 1 # out c + assert len(old_bias.shape) == 1 # out c + return self.expand_vector(bias.unsqueeze(-1), + old_bias.unsqueeze(-1)).squeeze(1) + + +class ExpandableConv2d(dynamic_ops.DynamicConv2d, ExpandableMixin): + + @property + def _original_in_channel(self): + return self.in_channels + + @property + def _original_out_channel(self): + return self.out_channels + + def get_expand_op(self, in_c, out_c, zero=False): + + if self.groups == 1: + return self._get_expand_op_normal_conv(in_c, out_c, zero=zero) + elif self.in_channels == self.out_channels == self.groups: + return self._get_expand_op_dw_conv(in_c, out_c, zero=zero) + else: + raise NotImplementedError('Groupwise conv is not supported yet.') + + def _get_expand_op_normal_conv(self, in_c, out_c, zero=False): + + module = nn.Conv2d(in_c, out_c, self.kernel_size, self.stride, + self.padding, self.dilation, self.groups, self.bias + is not None, + self.padding_mode).to(get_module_device(self)) + if zero: + ExpandableMixin.zero_weight_(module) + + weight = self.expand_matrix( + module.weight.flatten(2), self.weight.flatten(2)) + module.weight.data = weight.reshape(module.weight.shape) + if module.bias is not None and self.bias is not None: + bias = self.expand_vector( + module.bias.unsqueeze(-1), self.bias.unsqueeze(-1)) + module.bias.data = bias.reshape(module.bias.shape) + return module + + def _get_expand_op_dw_conv(self, in_c, out_c, zero=False): + assert in_c == out_c + module = nn.Conv2d(in_c, out_c, self.kernel_size, self.stride, + self.padding, self.dilation, in_c, self.bias + is not None, + self.padding_mode).to(get_module_device(self)) + if zero: + ExpandableMixin.zero_weight_(module) + + weight = self.expand_vector( + module.weight.flatten(1), self.weight.flatten(1)) + module.weight.data = weight.reshape(module.weight.shape) + if module.bias is not None and self.bias is not None: + bias = self.expand_vector( + module.bias.unsqueeze(-1), self.bias.unsqueeze(-1)) + module.bias.data = bias.reshape(module.bias.shape) + return module + + +class ExpandLinear(dynamic_ops.DynamicLinear, ExpandableMixin): + + @property + def _original_in_channel(self): + return self.in_features + + @property + def _original_out_channel(self): + return self.out_features + + def get_expand_op(self, in_c, out_c, zero=False): + module = nn.Linear(in_c, out_c, self.bias + is not None).to(get_module_device(self)) + if zero: + ExpandableMixin.zero_weight_(module) + + weight = self.expand_matrix( + module.weight.unsqueeze(-1), self.weight.unsqueeze(-1)) + module.weight.data = weight.reshape(module.weight.shape) + if module.bias is not None: + bias = self.expand_vector( + module.bias.unsqueeze(-1), self.bias.unsqueeze(-1)) + module.bias.data = bias.reshape(module.bias.shape) + return module + + +class ExpandableBatchNorm2d(dynamic_ops.DynamicBatchNorm2d, ExpandableMixin): + + @property + def _original_in_channel(self): + return self.num_features + + @property + def _original_out_channel(self): + return self.num_features + + def get_expand_op(self, in_c, out_c, zero=False): + assert in_c == out_c + module = nn.BatchNorm2d(in_c, self.eps, self.momentum, self.affine, + self.track_running_stats).to( + get_module_device(self)) + if zero: + ExpandableMixin.zero_weight_(module) + + if module.running_mean is not None: + module.running_mean.data = self.expand_bias( + module.running_mean, self.running_mean) + + if module.running_var is not None: + module.running_var.data = self.expand_bias(module.running_var, + self.running_var) + module.weight.data = self.expand_bias(module.weight, self.weight) + module.bias.data = self.expand_bias(module.bias, self.bias) + return module diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/tools.py b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/tools.py new file mode 100755 index 000000000..c96a72454 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/tools.py @@ -0,0 +1,91 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict + +import torch.nn as nn + +from mmrazor.models.mutators import ChannelMutator +from .ops import ExpandableMixin +from .unit import ExpandableUnit + + +def to_expandable_model(model: nn.Module) -> ChannelMutator[ExpandableUnit]: + """Convert a static model to an expandable model.""" + state_dict = model.state_dict() + mutator = ChannelMutator[ExpandableUnit]( + channel_unit_cfg=ExpandableUnit, + parse_cfg=dict( + _scope_='mmrazor', + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='FxTracer'), + ) + mutator.prepare_from_supernet(model) + model.load_state_dict(state_dict) + return mutator + + +def expand_expandable_dynamic_model(model: nn.Module, zero=False) -> nn.Module: + """Expand a expandable model and return a expanded static model. + + Args: + model (nn.Module): The model to be expanded. + zero (bool, optional): Whether to zero expanded weight. Defaults to + False. + """ + + def traverse_children(module: nn.Module) -> None: + for name, mutable in module.items(): + if isinstance(mutable, ExpandableMixin): + module[name] = mutable.expand(zero=zero) + if hasattr(mutable, '_modules'): + traverse_children(mutable._modules) + + if isinstance(model, ExpandableMixin): + raise RuntimeError('Root model can not be dynamic op.') + + if hasattr(model, '_modules'): + traverse_children(model._modules) + return model + + +def expand_static_model(model: nn.Module, structure: Dict, zero_weight=True): + """Expand the channels of a model. + + Args: + model (nn.Module): the model to be expanded. + structure (Dict): the channel structure for the model. + divisor (_type_): the divisor to make the channels divisible. + """ + mutator = to_expandable_model(model) + for key, value in structure.items(): + mutator._name2unit[key].expand_to(value) + expand_expandable_dynamic_model(model, zero=zero_weight) + return model + + +def make_channel_divisible(model: nn.Module, divisor, zero_weight=True): + """Expand the channels of a model and return the new divisible channel + structure. + + Args: + model (nn.Module): the model to be expanded. + divisor (_type_): the divisor to make the channels divisible. + """ + # to sta + mutator = to_expandable_model(model) + + structure = mutator.choice_template + for key, num in structure.items(): + unit = mutator._name2unit[key] + if num % divisor == 0: + continue + else: + num = (num // divisor + 1) * divisor + num = max(num, unit.num_channels) + unit.expand_to(num) + + model = expand_expandable_dynamic_model(model, zero=zero_weight) + mutator = to_expandable_model(copy.deepcopy(model)) + + return mutator.choice_template diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/unit.py b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/unit.py new file mode 100755 index 000000000..6d0b036dc --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/unit.py @@ -0,0 +1,31 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +import torch.nn as nn +from mmengine.model.utils import _BatchNormXd + +from mmrazor.models.mutables import (L1MutableChannelUnit, + MutableChannelContainer) +from .ops import ExpandableBatchNorm2d, ExpandableConv2d, ExpandLinear + + +class ExpandableUnit(L1MutableChannelUnit): + """The units to inplace modules with expandable dynamic ops.""" + + def prepare_for_pruning(self, model: nn.Module): + self._replace_with_dynamic_ops( + model, { + nn.Conv2d: ExpandableConv2d, + nn.BatchNorm2d: ExpandableBatchNorm2d, + _BatchNormXd: ExpandableBatchNorm2d, + nn.Linear: ExpandLinear, + }) + self._register_channel_container(model, MutableChannelContainer) + self._register_mutable_channel(self.mutable_channel) + + def expand(self, num): + expand_mask = self.mutable_channel.mask.new_zeros([num]) + mask = torch.cat([self.mutable_channel.mask, expand_mask]) + self.mutable_channel.mask = mask + + def expand_to(self, num): + self.expand(num - self.num_channels) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/make_divisible.py b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/make_divisible.py new file mode 100755 index 000000000..fa3dc4dea --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/make_divisible.py @@ -0,0 +1,46 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Optional + +from mmrazor.utils import print_log + +warn_once = False + + +def make_divisible(value: int, + divisor: int, + min_value: Optional[int] = None, + min_ratio: float = 0.9) -> int: + """Make divisible function. + + This function rounds the channel number down to the nearest value that can + be divisible by the divisor. + + Args: + value (int): The original channel number. + divisor (int): The divisor to fully divide the channel number. + min_value (int, optional): The minimum value of the output channel. + Default: None, means that the minimum value equal to the divisor. + min_ratio (float): The minimum ratio of the rounded channel + number to the original channel number. Default: 0.9. + Returns: + int: The modified output channel number + """ + + if min_value is None: + min_value = divisor + if min_value < divisor: + global warn_once + if warn_once is False: + print_log((f'min_value=={min_value} should greater or equal to ' + f'divisor=={divisor}, ' + 'so we make min_value equal divisor.'), + level='warning') + warn_once = True + + min_value = divisor + + new_value = max(min_value, int(value + divisor / 2) // divisor * divisor) + # Make sure that round down does not go down by more than (1-min_ratio). + if new_value < min_ratio * value: + new_value += divisor + return new_value diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/misc.py b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/misc.py new file mode 100755 index 000000000..42c7b553d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/misc.py @@ -0,0 +1,20 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict + + +def add_prefix(inputs: Dict, prefix: str) -> Dict: + """Add prefix for dict. + + Args: + inputs (dict): The input dict with str keys. + prefix (str): The prefix to add. + + Returns: + dict: The dict with keys updated with ``prefix``. + """ + + outputs = dict() + for name, value in inputs.items(): + outputs[f'{prefix}.{name}'] = value + + return outputs diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/optim_wrapper.py b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/optim_wrapper.py new file mode 100755 index 000000000..753f3bd7e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/optim_wrapper.py @@ -0,0 +1,29 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmengine.logging import MMLogger +from mmengine.optim import OptimWrapper +from torch.nn import Module + + +def reinitialize_optim_wrapper_count_status(model: Module, + optim_wrapper: OptimWrapper, + accumulative_counts: int, + verbose: bool = True) -> None: + if verbose: + logger = MMLogger.get_current_instance() + logger.warning('Reinitialize count status of optim wrapper') + + original_max_iters = \ + optim_wrapper.message_hub.runtime_info['max_iters'] + new_max_iters = original_max_iters * accumulative_counts + original_init_iters = \ + optim_wrapper.message_hub.runtime_info['iter'] + new_init_iters = original_init_iters * accumulative_counts + + if verbose: + logger.info(f'original `init_iters`: {original_init_iters}, ' + f'new `init_iters`: {new_init_iters}; ' + f'orginal `max_iters`: {original_max_iters}, ' + f'new `max_iters`: {new_max_iters}') + + optim_wrapper.initialize_count_status( + model=model, init_counts=new_init_iters, max_counts=new_max_iters) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/parse_values.py b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/parse_values.py new file mode 100755 index 000000000..67e98688b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/parse_values.py @@ -0,0 +1,18 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List + + +def parse_values(candidate_lists: List[list]): + """Parse a list with format `(min_range, max_range, step)`. + + NOTE: this method is required when customizing search space in configs. + """ + + def _range_to_list(input_range: List[int]) -> List[int]: + assert len(input_range) == 3, ( + 'The format should be `(min_range, max_range, step)` with dim=3, ' + f'but got dim={len(input_range)}.') + start, end, step = input_range + return list(range(start, end + 1, step)) + + return [_range_to_list(i) for i in candidate_lists] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/quantization_util.py b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/quantization_util.py new file mode 100755 index 000000000..36d108372 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/quantization_util.py @@ -0,0 +1,60 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmengine.utils import import_modules_from_strings + + +def pop_rewriter_function_record(rewriter_context, function_record_to_pop): + """Delete user-specific rewriters from `RewriterContext._rewriter_manager`. + + We use the model which is rewritten by mmdeploy to build quantized models. + However not all the functions rewritten by mmdeploy need to be rewritten in + mmrazor. For example, mmdeploy rewrite + `mmcls.models.classifiers.ImageClassifier.forward` and + `mmcls.models.classifiers.BaseClassifier.forward` for deployment. But they + can't be rewritten by mmrazor as ptq and qat are done in mmrazor. So to + ensure ptq and qat proceed normally, we have to remove these record from + `RewriterContext._rewriter_manager`. + """ + function_record_backup = {} + for record in function_record_to_pop: + records = rewriter_context._rewriter_manager.function_rewriter. \ + _registry._rewrite_records + if record in records: + function_record_backup[record] = records.pop(record) + return function_record_backup + + +def _check_valid_source(source): + """Check if the source's format is valid.""" + if not isinstance(source, str): + raise TypeError(f'source should be a str ' + f'instance, but got {type(source)}') + + assert len(source.split('.')) > 1, \ + 'source must have at least one `.`' + + +def str2class(str_inputs): + clss = [] + if not isinstance(str_inputs, tuple) and not isinstance(str_inputs, list): + str_inputs_list = [str_inputs] + else: + str_inputs_list = str_inputs + for s_class in str_inputs_list: + _check_valid_source(s_class) + mod_str = '.'.join(s_class.split('.')[:-1]) + cls_str = s_class.split('.')[-1] + try: + mod = import_modules_from_strings(mod_str) + except ImportError: + raise ImportError(f'{mod_str} is not imported correctly.') + imported_cls: type = getattr(mod, cls_str) + if not isinstance(imported_cls, type): + raise TypeError(f'{cls_str} should be a type ' + f'instance, but got {type(imported_cls)}') + clss.append(imported_cls) + if isinstance(str_inputs, list): + return clss + elif isinstance(str_inputs, tuple): + return tuple(clss) + else: + return clss[0] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/utils.py b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/utils.py new file mode 100755 index 000000000..b2fc4962b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/models/utils/utils.py @@ -0,0 +1,39 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List, Union + +import torch +import torch.nn as nn + + +def get_module_device(module: nn.Module) -> torch.device: + """Get the device of a module. + + Args: + module (nn.Module): A module contains the parameters. + """ + try: + next(module.parameters()) + except StopIteration as e: + raise ValueError('The input module should contain parameters.') from e + + if next(module.parameters()).is_cuda: + return next(module.parameters()).get_device() + + return torch.device('cpu') + + +def set_requires_grad(nets: Union[nn.Module, List[nn.Module]], + requires_grad: bool = False) -> None: + """Set requires_grad for all the networks. + + Args: + nets (nn.Module | list[nn.Module]): A list of networks or a single + network. + requires_grad (bool): Whether the networks require gradients or not + """ + if not isinstance(nets, list): + nets = [nets] + for net in nets: + if net is not None: + for param in net.parameters(): + param.requires_grad = requires_grad diff --git a/cv/distiller/CWD/mmrazor/mmrazor/registry/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/registry/__init__.py new file mode 100755 index 000000000..63ce9b1ef --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/registry/__init__.py @@ -0,0 +1,15 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .registry import (DATA_SAMPLERS, DATASETS, HOOKS, LOOPS, METRICS, + MODEL_WRAPPERS, MODELS, OPTIM_WRAPPER_CONSTRUCTORS, + OPTIM_WRAPPERS, OPTIMIZERS, PARAM_SCHEDULERS, + RUNNER_CONSTRUCTORS, RUNNERS, TASK_UTILS, TRANSFORMS, + VISBACKENDS, VISUALIZERS, WEIGHT_INITIALIZERS, + sub_model) + +__all__ = [ + 'RUNNERS', 'RUNNER_CONSTRUCTORS', 'HOOKS', 'DATASETS', 'DATA_SAMPLERS', + 'TRANSFORMS', 'MODELS', 'WEIGHT_INITIALIZERS', 'OPTIMIZERS', + 'OPTIM_WRAPPERS', 'OPTIM_WRAPPER_CONSTRUCTORS', 'TASK_UTILS', + 'PARAM_SCHEDULERS', 'METRICS', 'MODEL_WRAPPERS', 'LOOPS', 'VISBACKENDS', + 'VISUALIZERS', 'sub_model' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/registry/registry.py b/cv/distiller/CWD/mmrazor/mmrazor/registry/registry.py new file mode 100755 index 000000000..7f915ee74 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/registry/registry.py @@ -0,0 +1,141 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""MMRazor provides 17 registry nodes to support using modules across projects. +Each node is a child of the root registry in MMEngine. + +More details can be found at +https://mmengine.readthedocs.io/en/latest/tutorials/registry.html. +""" +from typing import Any, Dict, Optional, Union + +from mmengine.config import Config, ConfigDict +from mmengine.registry import DATA_SAMPLERS as MMENGINE_DATA_SAMPLERS +from mmengine.registry import DATASETS as MMENGINE_DATASETS +from mmengine.registry import HOOKS as MMENGINE_HOOKS +from mmengine.registry import LOOPS as MMENGINE_LOOPS +from mmengine.registry import METRICS as MMENGINE_METRICS +from mmengine.registry import MODEL_WRAPPERS as MMENGINE_MODEL_WRAPPERS +from mmengine.registry import MODELS as MMENGINE_MODELS +from mmengine.registry import \ + OPTIM_WRAPPER_CONSTRUCTORS as MMENGINE_OPTIM_WRAPPER_CONSTRUCTORS +from mmengine.registry import OPTIM_WRAPPERS as MMENGINE_OPTIM_WRAPPERS +from mmengine.registry import OPTIMIZERS as MMENGINE_OPTIMIZERS +from mmengine.registry import PARAM_SCHEDULERS as MMENGINE_PARAM_SCHEDULERS +from mmengine.registry import \ + RUNNER_CONSTRUCTORS as MMENGINE_RUNNER_CONSTRUCTORS +from mmengine.registry import RUNNERS as MMENGINE_RUNNERS +from mmengine.registry import TASK_UTILS as MMENGINE_TASK_UTILS +from mmengine.registry import TRANSFORMS as MMENGINE_TRANSFORMS +from mmengine.registry import VISBACKENDS as MMENGINE_VISBACKENDS +from mmengine.registry import VISUALIZERS as MMENGINE_VISUALIZERS +from mmengine.registry import \ + WEIGHT_INITIALIZERS as MMENGINE_WEIGHT_INITIALIZERS +from mmengine.registry import Registry, build_from_cfg + + +def build_razor_model_from_cfg( + cfg: Union[dict, ConfigDict, Config], + registry: 'Registry', + default_args: Optional[Union[dict, ConfigDict, Config]] = None) -> Any: + + # TODO relay on mmengine:HAOCHENYE/config_new_feature + if cfg.get('cfg_path', None) and not cfg.get('type', None): + from mmengine.hub import get_model + model = get_model(**cfg) # type: ignore + return model + + return_architecture = False + if cfg.get('_return_architecture_', None): + return_architecture = cfg.pop('_return_architecture_') + razor_model = build_from_cfg(cfg, registry, default_args) + if return_architecture: + return razor_model.architecture + else: + return razor_model + + +# Registries For Runner and the related +# manage all kinds of runners like `EpochBasedRunner` and `IterBasedRunner` +RUNNERS = Registry('runner', parent=MMENGINE_RUNNERS) +# manage runner constructors that define how to initialize runners +RUNNER_CONSTRUCTORS = Registry( + 'runner constructor', parent=MMENGINE_RUNNER_CONSTRUCTORS) +# manage all kinds of loops like `EpochBasedTrainLoop` +LOOPS = Registry('loop', parent=MMENGINE_LOOPS) +# manage all kinds of hooks like `CheckpointHook` +HOOKS = Registry('hook', parent=MMENGINE_HOOKS) + +# Registries For Data and the related +# manage data-related modules +DATASETS = Registry('dataset', parent=MMENGINE_DATASETS) +DATA_SAMPLERS = Registry('data sampler', parent=MMENGINE_DATA_SAMPLERS) +TRANSFORMS = Registry('transform', parent=MMENGINE_TRANSFORMS) + +# manage all kinds of modules inheriting `nn.Module` +MODELS = Registry( + 'model', parent=MMENGINE_MODELS, build_func=build_razor_model_from_cfg) +# manage all kinds of model wrappers like 'MMDistributedDataParallel' +MODEL_WRAPPERS = Registry('model_wrapper', parent=MMENGINE_MODEL_WRAPPERS) +# manage all kinds of weight initialization modules like `Uniform` +WEIGHT_INITIALIZERS = Registry( + 'weight initializer', parent=MMENGINE_WEIGHT_INITIALIZERS) + +# Registries For Optimizer and the related +# manage all kinds of optimizers like `SGD` and `Adam` +OPTIMIZERS = Registry('optimizer', parent=MMENGINE_OPTIMIZERS) +# manage optimizer wrapper +OPTIM_WRAPPERS = Registry('optimizer_wrapper', parent=MMENGINE_OPTIM_WRAPPERS) +# manage constructors that customize the optimization hyperparameters. +OPTIM_WRAPPER_CONSTRUCTORS = Registry( + 'optimizer wrapper constructor', + parent=MMENGINE_OPTIM_WRAPPER_CONSTRUCTORS) +# manage all kinds of parameter schedulers like `MultiStepLR` +PARAM_SCHEDULERS = Registry( + 'parameter scheduler', parent=MMENGINE_PARAM_SCHEDULERS) + +# manage all kinds of metrics +METRICS = Registry('metric', parent=MMENGINE_METRICS) + +# manage task-specific modules like anchor generators and box coders +TASK_UTILS = Registry('task util', parent=MMENGINE_TASK_UTILS) + +# Registries For Visualizer and the related +# manage visualizer +VISUALIZERS = Registry('visualizer', parent=MMENGINE_VISUALIZERS) +# manage visualizer backend +VISBACKENDS = Registry('vis_backend', parent=MMENGINE_VISBACKENDS) + + +# manage sub models for downstream repos +@MODELS.register_module() +def sub_model(cfg, + fix_subnet, + mode: str = 'mutable', + prefix: str = '', + extra_prefix: str = '', + init_weight_from_supernet: bool = False, + init_cfg: Optional[Dict] = None, + **kwargs): + model = MODELS.build(cfg) + # Save path type cfg process, set init_cfg directly. + if init_cfg: + # update init_cfg when init_cfg is valid. + model.init_cfg = init_cfg + + if init_weight_from_supernet: + # init weights from supernet first before it turns into a sub model. + model.init_weights() + + from mmrazor.structures import load_fix_subnet + + load_fix_subnet( + model, + fix_subnet, + load_subnet_mode=mode, + prefix=prefix, + extra_prefix=extra_prefix) + + if not init_weight_from_supernet: + # init weights from the specific sub model. + model.init_weights() + + return model diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/__init__.py new file mode 100755 index 000000000..7f15c5d45 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/__init__.py @@ -0,0 +1,3 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .quantization import * # noqa: F401,F403 +from .subnet import * # noqa: F401,F403 diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/__init__.py new file mode 100755 index 000000000..b22fe57d8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .base_graph import BaseGraph, BaseNode +from .module_graph import ModuleGraph, ModuleNode + +__all__ = ['BaseGraph', 'BaseNode', 'ModuleNode', 'ModuleGraph'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/base_graph.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/base_graph.py new file mode 100755 index 000000000..4c40e0359 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/base_graph.py @@ -0,0 +1,233 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This module defines BaseNode and BaseGraph, which are used to model Directed +Acyclic Graph(DAG)""" +from collections import OrderedDict +from copy import copy +from typing import Any, Callable, Generic, Iterator, List, TypeVar + +# BaseNode && BaseGraph + + +class BaseNode: + """A single node in a graph.""" + + def __init__(self, name: str, val: Any) -> None: + """ + Args: + name (str): name of the node. + val (any): content of the node. + """ + self.val = val + self.name = name + self.prev_nodes: List = [] + self.next_nodes: List = [] + + # node operation + + def add_prev_node(self, node: 'BaseNode'): + """add previous node.""" + if node not in self.prev_nodes: + self.prev_nodes.append(node) + if self not in node.next_nodes: + node.next_nodes.append(self) + + def add_next_node(self, node: 'BaseNode'): + """add next node.""" + if node not in self.next_nodes: + self.next_nodes.append(node) + if self not in node.prev_nodes: + node.prev_nodes.append(self) + + @classmethod + def copy_from(cls, node: 'BaseNode'): + """Copy a node, and generate a new node with current node type.""" + return cls(node.name, node.val) + + # compare operation + + def __hash__(self) -> int: + """Hash the node.""" + return hash((self.val, self.name)) + + def __eq__(self, other): + """Compare two nodes.""" + return self.val is other.val and self.name == other.name + + # other + + def __repr__(self) -> str: + return self.name + + +BASENODE = TypeVar('BASENODE', bound=BaseNode) + + +class BaseGraph(Generic[BASENODE]): + """A Directed Acyclic Graph(DAG)""" + + def __init__(self) -> None: + super().__init__() + self.nodes: OrderedDict[str, BASENODE] = OrderedDict() + + # graph operations + + @classmethod + def copy_from(cls, + graph: 'BaseGraph', + node_converter: Callable = BaseNode.copy_from): + """Copy a graph, and generate a new graph of the current class. + + Args: + graph (BaseGraph): the graph to be copied. + node_converter (Callable): a function that converts node, + when coping graph. + """ + old2new = {} + new_graph = cls() + # copy nodes + for old in graph: + old2new[old] = new_graph.add_or_find_node(node_converter(old)) + + # connect + for old in graph: + for pre in old.prev_nodes: + new_graph.connect(old2new[pre], old2new[old]) + return new_graph + + # node operations + + def add_or_find_node(self, node: BASENODE): + """Add a node to the graph. + + If the node has exsited in the graph, the function will return the node + recorded in the graph. + """ + find = self.find_node(node) + if find is not None: + return find + else: + self.add_node(node) + return node + + def find_node(self, node: BaseNode): + """Find a node and return.""" + if node.name in self.nodes and node.val == self.nodes[node.name].val: + return self.nodes[node.name] + else: + return None + + def add_node(self, node: BASENODE): + """Add a node.""" + if node.name not in self.nodes: + self.nodes[node.name] = node + else: + raise Exception(f'{node.name} already exists in graph') + + def connect(self, pre_node: BASENODE, next_node: BASENODE): + """Add an edge from pre_node to next_node.""" + pre_node_ = self.find_node(pre_node) + next_node_ = self.find_node(next_node) + assert pre_node_ is not None and next_node_ is not None, \ + f"{pre_node},{next_node} don't exist in the graph." + pre_node = pre_node_ + next_node = next_node_ + pre_node.add_next_node(next_node) + next_node.add_prev_node(pre_node) + + def disconnect(self, pre_node: BASENODE, next_node: BASENODE): + """Remove the edge form pre_node to next_node.""" + pre_node_ = self.find_node(pre_node) + next_node_ = self.find_node(next_node) + assert pre_node_ is not None and next_node_ is not None, \ + f"{pre_node},{next_node} don't exist in the graph." + pre_node = pre_node_ + next_node = next_node_ + if next_node in pre_node.next_nodes: + pre_node.next_nodes.remove(next_node) + if pre_node in next_node.prev_nodes: + next_node.prev_nodes.remove(pre_node) + + def delete_node(self, node: BASENODE): + """Delete a node with its related edges.""" + node = self.find_node(node) + assert node is not None + + if len(node.prev_nodes) == 0: + for next in copy(node.next_nodes): + self.disconnect(node, next) + elif len(node.next_nodes) == 0: + for pre in copy(node.prev_nodes): + self.disconnect(pre, node) + elif len(node.prev_nodes) == 1: + pre_node = node.prev_nodes[0] + self.disconnect(pre_node, node) + for next in copy(node.next_nodes): + self.disconnect(node, next) + self.connect(pre_node, next) + elif len(node.next_nodes) == 1: + next_node = node.next_nodes[0] + self.disconnect(node, next_node) + for pre in copy(node.prev_nodes): + self.disconnect(pre, node) + self.connect(pre, next_node) + else: + raise Exception(f'not delete {node}, \ + as it has more than one inputs and outputs') + self.nodes.pop(node.name) + + # work as a collection + + def __iter__(self) -> Iterator[BASENODE]: + """Traverse all nodes in the graph.""" + for x in self.nodes.values(): + yield x + + def __contains__(self, node: BASENODE) -> bool: + """Check if a node is contained in the graph.""" + return node.name in self.nodes + + def __len__(self) -> int: + """Number of nodes in the graph.""" + return len(self.nodes) + + # other + + def __repr__(self): + res = f'Graph with {len(self)} nodes:\n' + for node in self: + res += '{0:<80} -> {1:^80} -> {2:<80}\n'.format( + str(node.prev_nodes), node.__repr__(), str(node.next_nodes)) + return res + + # traverse + + def topo_traverse(self) -> Iterator[BASENODE]: + """Traverse the graph in topologitcal order.""" + + def _in_degree(graph: BaseGraph): + degree = {} + for name, node in graph.nodes.items(): + degree[name] = len(node.prev_nodes) + return degree + + def find_zero_degree_node(in_degree): + for node_name in in_degree: + if in_degree[node_name] == 0: + return node_name + raise Exception(f'no zero degree node\n{in_degree}') + + in_degree = _in_degree(self) + + while len(in_degree) > 0: + node_name = find_zero_degree_node(in_degree) # visit the node + in_degree.pop(node_name) + yield self.nodes[node_name] + for next in self.nodes[node_name].next_nodes: + in_degree[next.name] -= 1 + + def topo_sort(self): + """Sort all node in topological order.""" + sorted_nodes = OrderedDict() + for node in self.topo_traverse(): + sorted_nodes[node.name] = node + self.nodes = sorted_nodes diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_flow.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_flow.py new file mode 100755 index 000000000..990826be9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_flow.py @@ -0,0 +1,220 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""Including modules for ChannelFlow to analyze channel dependency.""" +import copy +import itertools +import sys +from typing import List, Set, Union + +from mmrazor.utils import IndexDict + +sys.setrecursionlimit(int(pow(2, 20))) + + +class ChannelElem: + """A ChannelElem represents a channel in ChannelFlow.""" + + def __init__(self, owning_tensor: 'ChannelTensor', + index_in_tensor: int) -> None: + """A ChannelElem represents a channel in channelflow. + + Args: + owning_tensor (ChannelTensor): the ChannelTensor which the + ChannelElem belongs to. + index_in_tensor (int): the index in the owning_tensor. + """ + self._parent: Union[None, 'ChannelElem'] = None + self._subs: Set[ChannelElem] = set() + self.owing_tensor = owning_tensor + self.index_in_tensoor = index_in_tensor + self._hash_cache = None + self._min_elem_set_index_cache = None + + # channel elem operations + + @classmethod + def union_two(cls, elem1: 'ChannelElem', elem2: 'ChannelElem'): + """Bind two ChannelElems.""" + root1 = elem1.root + root2 = elem2.root + if root1 is not root2: + root2._set_parent(root1) + + def union(self, elem: 'ChannelElem'): + """Bind with anther ChannelElem.""" + ChannelElem.union_two(self, elem) + + # hash related + + @property + def owing_elem_set(self): + """Get ChannelElem set representation.""" + root = self.root + return root.subs + + def reset_cache(self): + """Reset hash cache.""" + self._hash_cache = None + self._min_elem_set_index_cache = None + + @property + def elem_set_hash(self): + """Get the hash of the owning ChannelElems set.""" + if self._hash_cache is not None: + return self._hash_cache + else: + tensor_list = list(self.owing_elem_set) + tensor_set = set([elem.owing_tensor for elem in tensor_list]) + frozen_set = frozenset(tensor_set) + hash = frozen_set.__hash__() + for elem in self.owing_elem_set: + assert elem._hash_cache is None + elem._hash_cache = hash + return hash + + @property + def min_elem_set_index(self): + """Minimal index in ChannelTensors.""" + if self._min_elem_set_index_cache is not None: + return self._min_elem_set_index_cache + else: + elem_set = self.owing_elem_set + min_index = int(pow(2, 32)) + for elem in elem_set: + min_index = min(min_index, elem.index_in_tensoor) + for elem in elem_set: + assert elem._min_elem_set_index_cache is None + elem._min_elem_set_index_cache = min_index + return min_index + + # work as a disjoint set + + @property + def root(self) -> 'ChannelElem': + """Get root of the owing ChannelElem set.""" + if self._parent is None: + return self + else: + root = self._parent.root + self._unset_parent() + self._set_parent(root) + return root + + @property + def subs(self): + """Get all Elements in the set.""" + subs = copy.copy(self._subs) + subs.add(self) + for elem in self._subs: + subs = subs.union(elem.subs) + return subs + + def _set_parent(self, parent: 'ChannelElem'): + """Set parent for the ChannelElem.""" + assert self._parent is None + assert parent.root is not self + self._parent = parent + parent._subs.add(self) + + def _unset_parent(self): + """Unset parent of the ChannelElem.""" + assert self._parent is not None + old_parent = self._parent + old_parent._subs.remove(self) + self._parent = None + + +class ChannelTensor: + """The ChannelTensor in ChannelFlow.""" + + def __init__(self, num_channel_elem: int) -> None: + """ChannelTensor works as a proxy of a tensor. + + Args: + num_channel_elem (int): number of channels(ChannelElems) + """ + self.elems = [ChannelElem(self, i) for i in range(num_channel_elem)] + + # tensor operations + + def union(self, tensor: 'ChannelTensor'): + """Bind with another ChannelTensor.""" + return self.__class__.union_two(self, tensor) + + @classmethod + def union_two(cls, tensor1: 'ChannelTensor', tensor2: 'ChannelTensor'): + """Bind two ChannelTensors.""" + assert len(tensor1) == len(tensor2), f'{len(tensor1)}!={len(tensor2)}' + for e1, e2 in zip(tensor1, tensor2): + ChannelElem.union_two(e1, e2) + + @classmethod + def cat(cls, tensors: List['ChannelTensor']): + """Cat multiple ChannelTensors.""" + elems = list(itertools.chain(*[t.elems for t in tensors])) + new_tensor = ChannelTensor(len(elems)) + new_tensor.elems = elems + return new_tensor + + def expand(self, expand_ratio: int): + """Expand self ChannelTensor.""" + new_tensor = ChannelTensor(expand_ratio * len(self)) + + for i in range(len(self)): + for j in range(expand_ratio): + self[i].union(new_tensor[i * expand_ratio + j]) + return new_tensor + + # hash operation + + @property + def elems_hash_with_index(self): + """Return hash of the ChannelElems in the ChannelTensor with index.""" + elem_hashes = [(elem.elem_set_hash, elem.min_elem_set_index) + for elem in self.elems] + return elem_hashes + + @property + def elems_hash_dict(self): + """Return hash of the ChannelElems in the ChannelTensor.""" + elem_hash_with_index = self.elems_hash_with_index + unit_dict = IndexDict() + start = 0 + for e in range(1, len(self)): + if (elem_hash_with_index[e][0] != elem_hash_with_index[e - 1][0] + or elem_hash_with_index[e][1] < + elem_hash_with_index[e - 1][1]): + + unit_dict[(start, e)] = elem_hash_with_index[start][0] + start = e + unit_dict[start, len(self)] = elem_hash_with_index[start][0] + return unit_dict + + # work as a tensor + + def __getitem__(self, key: Union[int, slice]): + if isinstance(key, int): + return self.elems[key] + elif isinstance(key, slice): + elems = self.elems[key] + tensor = ChannelTensor(len(elems)) + tensor.elems = elems + return tensor + else: + raise NotImplementedError() + + def __len__(self): + return len(self.elems) + + def __iter__(self): + for e in self.elems: + yield e + + def __add__(self, tensor: 'ChannelTensor'): + return ChannelTensor.cat([self, tensor]) + + # others + + def _reset_channel_elem_cache(self): + """Reset hash of all ChannelElems in the ChannelTensor.""" + for elem in self.elems: + elem.reset_cache() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_graph.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_graph.py new file mode 100755 index 000000000..40f8da088 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_graph.py @@ -0,0 +1,245 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Callable, Dict, List + +from torch.nn import Module + +from mmrazor.utils import print_log +from .base_graph import BaseGraph +from .channel_flow import ChannelTensor +from .channel_nodes import (ChannelDismatchError, ChannelNode, EndNode, + ExpandChannelNode, InputChannelNode, + default_channel_node_converter) +from .module_graph import ModuleGraph, NoInputError, NoOutputError + + +class ChannelGraph(ModuleGraph[ChannelNode]): + """ChannelGraph is used to trace the channel dependency of a model. + + A ChannelGraph generates a ChannelTensor as the input to the model. Then, + the tensor can forward through all nodes and collect channel dependency. + """ + + @classmethod + def copy_from(cls, + graph: 'BaseGraph', + node_converter: Callable = default_channel_node_converter): + """Copy from a ModuleGraph.""" + assert isinstance(graph, ModuleGraph) + channel_graph: ChannelGraph = super().copy_from(graph, node_converter) + channel_graph._insert_expand_node() + return channel_graph + + def generate_units_config(self) -> Dict: + """Generate configs of MutableChannelUnits according to the Graph. + + "hash"{ + 'init_args':{ + 'num_channels': 10 + } + 'channels':{ + 'input_related':[ + { + "name":"backbone.bn1", + "start":0, + "end":64, + "expand_ratio":1, + "is_output_channel":false + } + ], + 'output_related':[ + ... + ] + } + } + """ + + chanel_config_template: Dict = { + 'init_args': { + 'num_channels': 1 + }, + 'channels': { + 'input_related': [], + 'output_related': [] + } + } + + def process_tensor(node: ChannelNode, is_output_tensor, + unit_hash_dict: Dict): + if is_output_tensor: + tensor = node.out_channel_tensor + else: + tensor = node.in_channel_tensor + assert tensor is not None + for (start, end), hash in tensor.elems_hash_dict.items(): + channel_config = { + 'name': node.module_name if node.is_module else node.val, + 'start': start, + 'end': end, + 'is_output_channel': is_output_tensor + } + if hash not in unit_hash_dict: + unit_hash_dict[hash] = copy.deepcopy( + chanel_config_template) + related_dict = unit_hash_dict[hash]['channels'][ + 'output_related' if is_output_tensor else 'input_related'] + if channel_config not in related_dict: + related_dict.append(channel_config) + + def fill_num_channels(units_config: Dict): + + def min_num_channels(channel_configs: List[Dict]): + min_num_channels = int(pow(2, 32)) + for channel in channel_configs: + min_num_channels = min(min_num_channels, + channel['end'] - channel['start']) + return min_num_channels + + for name in units_config: + units_config[name]['init_args'][ + 'num_channels'] = min_num_channels( + units_config[name]['channels']['input_related'] + + units_config[name]['channels']['output_related']) + + unit_hash_dict: Dict = {} + self._reset_channel_elem_cache() + for node in self.topo_traverse(): + process_tensor(node, True, unit_hash_dict) + process_tensor(node, False, unit_hash_dict) + fill_num_channels(unit_hash_dict) + return unit_hash_dict + + def forward(self, num_input_channel=3): + """Generate a ChanneelTensor and let it forwards through the graph.""" + for node in self.topo_traverse(): + node.reset_channel_tensors() + for i, node in enumerate(self.topo_traverse()): + node: ChannelNode + if len(node.prev_nodes) == 0: + tensor = ChannelTensor(num_input_channel) + node.forward([tensor]) + else: + node.forward() + self._merge_same_module() + + # graph modification + + def _add_input_before(self, node: ChannelNode): + """Add a input node before a ChannelNode.""" + try: + in_channels = node.in_channels + except Exception: + in_channels = 3 + input_node = InputChannelNode( + f'auto_input_{in_channels}', + 'input_placeholder', + input_channels=in_channels) # type: ignore + input_node = self.add_or_find_node(input_node) + self.connect(input_node, node) + + def _add_output_after(self, node: ChannelNode): + """Add a output node after a ChannelNode.""" + + output_node = EndNode('auto_output', + 'output_placeholder') # type: ignore + output_node = self.add_or_find_node(output_node) + self.connect(node, output_node) + + def _convert_a_node_to_end_node(self, node: ChannelNode): + """Convert a node to end node.""" + + end_node = EndNode('auto_end', 'output_placeholder') + end_node = self.add_or_find_node(end_node) + for prev in copy.copy(node.prev_nodes): + self.disconnect(prev, node) + self.connect(prev, end_node) + self._add_input_before(node) + + def _merge_same_module(self): + """Union all nodes with the same module to the same unit.""" + module2node: Dict[Module, List[ChannelNode]] = dict() + for node in self: + if isinstance(node.val, + Module) and len(list(node.val.parameters())) > 0: + if node.val not in module2node: + module2node[node.val] = [] + if node not in module2node[node.val]: + module2node[node.val].append(node) + + for module in module2node: + if len(module2node[module]) > 1: + nodes = module2node[module] + assert nodes[0].in_channel_tensor is not None and \ + nodes[0].out_channel_tensor is not None + for node in nodes[1:]: + nodes[0].in_channel_tensor.union(node.in_channel_tensor) + nodes[0].out_channel_tensor.union(node.out_channel_tensor) + + def _insert_expand_node(self): + """Insert expand nodes in the graph.""" + num_expand_nodes = 0 + nodes: List[ChannelNode] = copy.copy(list(self.topo_traverse())) + for node in nodes: + try: + node.check_channel() + except Exception: + for pre_node in node.prev_nodes: + pre_node: ChannelNode + if (pre_node.out_channels < node.in_channels + and node.in_channels % pre_node.out_channels == 0): + print_log( + (f'As the channels of {pre_node} and {node} ' + 'dismatch, we add an ExpandNode between them.'), + level='warning') + expand_ratio = ( + node.in_channels // pre_node.out_channels) + # insert a expand node + new_node = ExpandChannelNode( + f'expand_{num_expand_nodes}', + 'expand', + expand_ratio=expand_ratio) + num_expand_nodes += 1 + self.add_node(new_node) + self.connect(pre_node, new_node) + self.connect(new_node, node) + self.disconnect(pre_node, node) + + # others + + def _check(self, node: ChannelNode, fix=False): + """Helper for self.check, including check whether the Graph has any + error and fix errors.""" + try: + node.check_channel() + node.check() + except Exception as e: + if not fix: + raise e + else: + try: + raise e + except NoOutputError as e: + print_log(f'add a output after {node}, error: {e}', + 'debug') + self._add_output_after(node) + except NoInputError as e: + print_log( + f'add a input before {node}, error: {e}', + level='debug') + self._add_input_before(node) + except ChannelDismatchError as e: + print_log((f'{node} has channel error, so' + f'we convert it to a EndNode. error: {e}'), + level='debug') + self._convert_a_node_to_end_node(node) + + self._check(node, fix=True) + + def _reset_channel_elem_cache(self): + """Reset hash cache of ChannelTensors.""" + # may has bug, as some tensor not recorded by node.xxxx_tensors + for node in self.topo_traverse(): + assert (node.in_channel_tensor is not None + and node.out_channel_tensor is not None), f'{node}' + node.in_channel_tensor._reset_channel_elem_cache() + node.out_channel_tensor._reset_channel_elem_cache() diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_nodes.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_nodes.py new file mode 100755 index 000000000..be8e3dee3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_nodes.py @@ -0,0 +1,533 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""ChannelNodes are basic node type of ChannelGraph. + +Different ChannelNodes represent different modules. +""" +import operator +from abc import abstractmethod +from typing import List, Union + +import torch +import torch.nn as nn +from mmcv.cnn.bricks import Scale +from mmengine import MMLogger + +from mmrazor.utils import print_log +from .channel_flow import ChannelTensor +from .module_graph import ModuleNode + +# error types + + +class ChannelDismatchError(Exception): + pass + + +def assert_channel(condition, node): + if not condition: + raise ChannelDismatchError(node.name) + + +# ChannelNode + + +class ChannelNode(ModuleNode): + """A ChannelNode is like a torch module. It accepts a ChannelTensor and + output a ChannelTensor. The difference is that the torch module transforms + a tensor, while the ChannelNode records the information of channel + dependency in the ChannelTensor. + + Args: + name (str): The name of the node. + val (Union[nn.Module, str]): value of the node. + module_name (str, optional): the module name of the module of the + node. + """ + + # init + + def __init__(self, + name: str, + val: Union[nn.Module, str], + module_name='') -> None: + + super().__init__(name, val, module_name) + self.in_channel_tensor: Union[None, ChannelTensor] = None + self.out_channel_tensor: Union[None, ChannelTensor] = None + self.return_tensor: Union[None, ChannelTensor] = None + + @classmethod + def copy_from(cls, node): + """Copy from a ModuleNode.""" + assert isinstance(node, ModuleNode) + return cls(node.name, node.val, node.module_name) + + def reset_channel_tensors(self): + """Reset the owning ChannelTensors.""" + self.in_channel_tensor = None + self.out_channel_tensor = None + + # forward + + def forward(self, in_channel_tensors=None): + """Forward with ChannelTensors.""" + if in_channel_tensors is None: + out_channel_tensors = [ + node.return_tensor for node in self.prev_nodes + ] + in_channel_tensors = out_channel_tensors + try: + self.return_tensor = self.channel_forward(in_channel_tensors) + except Exception as e: + raise Exception(f'{e},{self.name}') + + @abstractmethod + def channel_forward(self, channel_tensors: List[ChannelTensor]): + """Forward with ChannelTensors.""" + assert len(channel_tensors) == 1, f'{len(channel_tensors)}' + + self.in_channel_tensor = channel_tensors[0] + self.out_channel_tensor = ChannelTensor(self.out_channels) + return self.out_channel_tensor + + # channels + + # @abstractmethod + @property + def in_channels(self) -> int: + """Get the number of input channels of the node.""" + try: + return self._in_channels + except NotImplementedError: + return \ + self._get_in_channels_by_prev_nodes(self.prev_nodes) + + # @abstractmethod + @property + def out_channels(self) -> int: + """Get the number of output channels of the node.""" + try: + return self._out_channels + except NotImplementedError: + return self._get_out_channel_by_in_channels(self.in_channels) + + def check_channel(self): + """Check if the node has a channel error.""" + for node in self.prev_nodes: + assert_channel(node.out_channels == self.in_channels, self) + + @property + def _in_channels(self) -> int: + """Get in channel number of by the module self.""" + raise NotImplementedError( + f'{self.name}({self.__class__.__name__}) has no _in_channels') + + @property + def _out_channels(self) -> int: + """Get out channel number of by the module self.""" + raise NotImplementedError( + f'{self.name}({self.__class__.__name__}) has no _out_channels') + + def _get_out_channel_by_in_channels(self, in_channels): + """Get output channel number by the input channel number.""" + return in_channels + + def _get_in_channels_by_prev_nodes(self, prev_nodes): + """Get input channel numbers by previous nodes.""" + if len(prev_nodes) == 0: + print_log( + (f'As {self.name} ' + 'has no prev nodes, so we set the in channels of it to 3.'), + level='debug') + return 3 + else: + return prev_nodes[0].out_channels + + def __repr__(self) -> str: + return f'{self.name}_({self.in_channels},{self.out_channels})' + + +# basic nodes + + +class PassUnionChannelNode(ChannelNode): + """A PassUnionChannelNode has the same number of input channels and output + channels. + + Besides, the corresponding input channels and output channels belong to one + channel unit. Such as BatchNorm, Relu. + """ + + def channel_forward(self, channel_tensors: List[ChannelTensor]): + """Channel forward.""" + return PassUnionChannelNode._channel_forward(self, channel_tensors[0]) + + @staticmethod + def _channel_forward(node: ChannelNode, tensor: ChannelTensor): + """Channel forward.""" + assert node.in_channels == node.out_channels + assert isinstance(tensor, ChannelTensor) + node.in_channel_tensor = tensor + node.out_channel_tensor = tensor + return node.out_channel_tensor + + def __repr__(self) -> str: + return super().__repr__() + '_uion' + + +class PassChannelNode(ChannelNode): + + def _get_in_channels_by_prev_nodes(self, prev_nodes): + assert len(self.prev_nodes) == 1 + node0: ChannelNode = self.prev_nodes[0] + return node0.out_channels + + def channel_forward(self, channel_tensors: List[ChannelTensor]): + assert len(channel_tensors) == 1 + self.in_channel_tensor = ChannelTensor(1) + self.out_channel_tensor = ChannelTensor(1) + return channel_tensors[0] + + def __repr__(self) -> str: + return super().__repr__() + '_pass' + + +class MixChannelNode(ChannelNode): + """A MixChannelNode has independent input channels and output channels.""" + + def channel_forward(self, channel_tensors: List[ChannelTensor]): + """Channel forward.""" + assert len(channel_tensors) <= 1 + if len(channel_tensors) == 1: + self.in_channel_tensor = channel_tensors[0] + self.out_channel_tensor = ChannelTensor(self.out_channels) + else: + raise NotImplementedError() + return self.out_channel_tensor + + def __repr__(self) -> str: + return super().__repr__() + '_mix' + + +class BindChannelNode(ChannelNode): + """A BindChannelNode has multiple inputs, and all input channels belong to + the same channel unit.""" + + def channel_forward(self, channel_tensors: List[ChannelTensor]): + """Channel forward.""" + assert len(channel_tensors) > 0, f'{self}' + # align channel_tensors + for tensor in channel_tensors[1:]: + channel_tensors[0].union(tensor) + self.in_channel_tensor = channel_tensors[0] + self.out_channel_tensor = channel_tensors[0] + return self.out_channel_tensor + + def __repr__(self) -> str: + return super().__repr__() + '_bind' + + def check_channel(self): + for node in self.prev_nodes: + assert_channel(node.out_channels == self.in_channels, self) + + +class CatChannelNode(ChannelNode): + """A CatChannelNode cat all input channels.""" + + def channel_forward(self, channel_tensors: List[ChannelTensor]): + tensor_cat = ChannelTensor.cat(channel_tensors) + self.in_channel_tensor = tensor_cat + self.out_channel_tensor = tensor_cat + return self.out_channel_tensor + + def check_channel(self): + in_num = [node.out_channels for node in self.prev_nodes] + assert_channel(sum(in_num) == self.in_channels, self) + + def _get_in_channels_by_prev_nodes(self, prev_nodes): + assert len(prev_nodes) > 0 + nums = [node.out_channels for node in prev_nodes] + return sum(nums) + + def __repr__(self) -> str: + return super().__repr__() + '_cat' + + +class ExpandChannelNode(ChannelNode): + + def __init__(self, + name: str, + val: Union[nn.Module, str], + module_name='', + expand_ratio=1) -> None: + super().__init__(name, val, module_name) + self.expand_ratio = expand_ratio + + def _get_out_channel_by_in_channels(self, in_channels): + return in_channels * self.expand_ratio + + def channel_forward(self, channel_tensors: List[ChannelTensor]): + assert len(channel_tensors) == 1, f'{self}' + assert self.out_channels >= self.in_channels, f'{self}' + assert self.out_channels % self.in_channels == 0, f'{self}' + tensor0 = channel_tensors[0] + self.in_channel_tensor = tensor0 + self.out_channel_tensor = tensor0.expand(self.expand_ratio) + return self.out_channel_tensor + + def __repr__(self) -> str: + return super().__repr__() + f'_expand({self.expand_ratio})' + + +class InputChannelNode(ChannelNode): + + def __init__(self, + name: str, + val: Union[nn.Module, str], + module_name='', + input_channels=3) -> None: + super().__init__(name, val, module_name) + self._input_channels = input_channels + + def channel_forward(self, channel_tensors: List[ChannelTensor]): + input_tensor = ChannelTensor(self._input_channels) + self.in_channel_tensor = input_tensor + self.out_channel_tensor = input_tensor + return input_tensor + + @property + def _in_channels(self) -> int: + return self._input_channels + + def __repr__(self) -> str: + return super().__repr__() + '_input' + + +class EndNode(ChannelNode): + + def channel_forward(self, channel_tensors: List[ChannelTensor]): + tensor_end = ChannelTensor(1) + self.in_channel_tensor = tensor_end + self.out_channel_tensor = tensor_end + for channel in channel_tensors: + channel.union(tensor_end.expand(len(channel))) + return self.out_channel_tensor + + def __repr__(self) -> str: + return super().__repr__() + '_end' + + def check_channel(self): + pass + + +# module nodes + + +class ConvNode(MixChannelNode): + """A ConvNode corresponds to a Conv2d module. + + It can deal with normal conv, dwconv and gwconv. + """ + + def __init__(self, + name: str, + val: Union[nn.Module, str], + module_name='') -> None: + super().__init__(name, val, module_name) + assert isinstance(self.val, nn.Conv2d) + + @property + def conv_type(self): + if self.val.groups == 1: + return 'conv' + elif self.val.in_channels == self.out_channels == self.val.groups: + return 'dwconv' + else: + return 'gwconv' + + def channel_forward(self, channel_tensors: List[ChannelTensor]): + if self.conv_type == 'conv': + return super().channel_forward(channel_tensors) + elif self.conv_type == 'dwconv': + return PassUnionChannelNode._channel_forward( + self, channel_tensors[0]) + elif self.conv_type == 'gwconv': + return self._gw_conv_channel_forward(channel_tensors) + else: + raise NotImplementedError(f'{self}') + + def _gw_conv_channel_forward(self, channel_tensors: List[ChannelTensor]): + + assert len(channel_tensors) == 1 + tensor0 = channel_tensors[0] + conv: nn.Conv2d = self.val + group_union(tensor0, conv.groups) + self.in_channel_tensor = tensor0 + self.out_channel_tensor = ChannelTensor(self.out_channels) + group_union(self.out_channel_tensor, conv.groups) + return self.out_channel_tensor + + @property + def _in_channels(self) -> int: + return self.val.in_channels + + @property + def _out_channels(self) -> int: + return self.val.out_channels + + def __repr__(self) -> str: + return super().__repr__() + '_conv' + + +class LinearNode(MixChannelNode): + """A LinearNode corresponds to a Linear module.""" + + def __init__(self, + name: str, + val: Union[nn.Module, str], + module_name='') -> None: + super().__init__(name, val, module_name) + assert isinstance(self.val, nn.Linear) + + @property + def _in_channels(self) -> int: + return self.val.in_features + + @property + def _out_channels(self) -> int: + return self.val.out_features + + def __repr__(self) -> str: + return super().__repr__() + '_linear' + + +class BnNode(PassUnionChannelNode): + """A NormNode corresponds to a BatchNorm2d module.""" + + def __init__(self, + name: str, + val: Union[nn.Module, str], + module_name='') -> None: + super().__init__(name, val, module_name) + assert isinstance(self.val, + nn.modules.batchnorm._BatchNorm), f'{type(self.val)}' + + @property + def _in_channels(self) -> int: + return self.val.num_features + + @property + def _out_channels(self) -> int: + return self.val.num_features + + def __repr__(self) -> str: + return super().__repr__() + '_bn' + + +class GroupNormNode(PassUnionChannelNode): + + def __init__(self, + name: str, + val: Union[nn.Module, str], + module_name='') -> None: + super().__init__(name, val, module_name) + assert isinstance(self.val, nn.GroupNorm) + self.val: nn.GroupNorm + + @property + def _in_channels(self) -> int: + return self.val.num_channels + + @property + def _out_channels(self) -> int: + return self.val.num_channels + + def channel_forward(self, channel_tensors: List[ChannelTensor]): + out_tensor = super().channel_forward(channel_tensors) + group_tensor = ChannelTensor(self.in_channels // self.val.num_groups) + group_union(out_tensor, self.val.num_groups, group_tensor) + return out_tensor + + def __repr__(self) -> str: + return super().__repr__() + '_gn' + + +# converter + +channel_nodes_mapping = { + 'module': { + nn.Conv2d: ConvNode, + nn.modules.batchnorm._BatchNorm: BnNode, + nn.Linear: LinearNode, + nn.modules.ReLU: PassChannelNode, + nn.modules.Hardtanh: PassChannelNode, + # pools + nn.modules.pooling._AvgPoolNd: PassChannelNode, + nn.modules.pooling._AdaptiveAvgPoolNd: PassChannelNode, + nn.modules.pooling._MaxPoolNd: PassChannelNode, + nn.modules.pooling._AdaptiveMaxPoolNd: PassChannelNode, + Scale: PassChannelNode, + nn.modules.GroupNorm: GroupNormNode, + }, + 'function': { + torch.add: BindChannelNode, + torch.cat: CatChannelNode, + operator.add: BindChannelNode, + }, + 'str': { + 'bind_placeholder': BindChannelNode, + 'pass_placeholder': PassUnionChannelNode, + 'cat_placeholder': CatChannelNode, + 'input_placeholder': InputChannelNode, + 'output_placeholder': EndNode + }, +} + + +def default_channel_node_converter( + node: ModuleNode, + module_mapping=channel_nodes_mapping['module'], + function_mapping=channel_nodes_mapping['function'], + name_mapping=channel_nodes_mapping['str']) -> ChannelNode: + """The default node converter for ChannelNode.""" + + def warn(default='PassUnionChannelNode'): + logger = MMLogger.get_current_instance() + logger.info( + (f"{node.name}({node.module_name}) node can't find match type of" + 'channel_nodes,' + f'replaced with {default} by default.')) + + if isinstance(node.val, nn.Module): + # module_mapping + for module_type in module_mapping: + if isinstance(node.val, module_type): + return module_mapping[module_type].copy_from(node) + + elif isinstance(node.val, str): + for module_type in name_mapping: + if node.val == module_type: + return name_mapping[module_type].copy_from(node) + else: + for fun_type in function_mapping: + if node.val == fun_type: + return function_mapping[fun_type].copy_from(node) + if len(node.prev_nodes) > 1: + warn('BindChannelNode') + return BindChannelNode.copy_from(node) + else: + warn('PassUnionChannelNode') + return PassUnionChannelNode.copy_from(node) + + +# helper functions + + +def group_union(tensor: ChannelTensor, groups: int, group_tensor=None): + """Group-wise union for ChannelTensor.""" + c_per_group = len(tensor) // groups + if group_tensor is None: + group_tensor = ChannelTensor(c_per_group) + assert groups * len(group_tensor) == len(tensor) + for i in range(groups): + tensor[i * c_per_group:(i + 1) * c_per_group].union(group_tensor) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/module_graph.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/module_graph.py new file mode 100755 index 000000000..d90771940 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/module_graph.py @@ -0,0 +1,507 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This module defines ModuleNode and ModuleGraph. + +They model the computation graph of a model based on BaseNode and BaseGraph +""" +import copy +from collections import OrderedDict +from typing import Dict, List, TypeVar, Union + +import torch.nn as nn +from torch.nn import Module + +from mmrazor.models.task_modules.tracer.backward_tracer import BackwardTracer +from mmrazor.models.task_modules.tracer.loss_calculator import \ + ImageClassifierPseudoLoss +from mmrazor.models.task_modules.tracer.path import (Path, PathConcatNode, + PathList, PathNode) +from mmrazor.registry import TASK_UTILS +from mmrazor.utils import print_log +from .base_graph import BaseGraph, BaseNode +from .pseudo_fx_graph import FxBaseNode + + +# ModuleNode && ModuleGraph +class NoOutputError(Exception): + """An error occurs when no output node for a leaf node.""" + + def __init__(self, node, *args: object) -> None: + super().__init__(f'{node}', *args) + self.node = node + + pass + + +class NoInputError(Exception): + """An error occurs when no input node for a leaf node.""" + + def __init__(self, node, *args: object) -> None: + super().__init__(f'{node}', *args) + self.node = node + + +def my_assert(condiion, exception): + """assert helper function.""" + if not condiion: + raise exception + + +class ModuleNode(BaseNode): + """A node in a computation graph. + + All nodes are divided to four types, the detail of definition can be found + in functions self.is_{xxx}_node. + """ + + pre_defined_node_val_str = [ + 'cat_placeholder', 'bind_placeholder', 'pass_placeholder' + ] + + def __init__(self, + name: str, + val: Union[Module, str], + module_name='') -> None: + """ + Args: + name (str): the name of the node + val (Module | str): content of the node. It can be Module or + string. If val is a string, the string can only be one of + self.pre_defined_node_val_str + Note: + Here, we give an example of expand_ratio. + >>> class Pool(nn.Module): + def forward(x): + return F.adaptive_avg_pool2d(x,2).flatten(1) + >>> node= ModuleNode('pass_0',Pool(),expand_ratio=4) + >>> assert node.out_channels == node.in_channels*4 + """ + + super().__init__(name, val) + self.module_name = module_name + + # other + + @property + def is_module(self): + """Whether the node includes a module.""" + return isinstance(self.val, nn.Module) + + def __repr__(self) -> str: + repr = f'{self.name}' + if self.module_name != '': + repr += f'({self.module_name})' + return repr + + # node type + + @property + def basic_type(self) -> str: + """The basic type of the node. + + Basic types are divided into seveval major types, detailed in + self.is_{xxx}_node + """ + if isinstance(self.val, Module): + if isinstance(self.val, nn.Conv2d): + if self.val.groups == 1: + return 'conv2d' + elif self.val.groups == self.val.in_channels == \ + self.val.out_channels: + return 'dwconv2d' + else: + return 'gwconv2d' + elif isinstance(self.val, nn.modules.batchnorm._BatchNorm): + return 'bn' + elif isinstance(self.val, nn.Linear): + return 'linear' + else: + raise NotImplementedError(f'{self.val}') + else: + if self.val in [ + 'cat_placeholder', 'bind_placeholder', 'pass_placeholder' + ]: + return self.val + else: + raise NotImplementedError() + + def is_pass_node(self): + """pass node represent a module whose in-channels correspond out- + channels one-to-one.""" + return self.basic_type in ['bn', 'dwconv2d', 'pass_placeholder'] + + def is_cat_node(self): + """cat node represents a cat module.""" + return self.basic_type == 'cat_placeholder' + + def is_bind_node(self): + """bind node represent a node that has multiple inputs, and their + channels are bound one-to-one.""" + return self.basic_type == 'bind_placeholder' + + def is_mix_node(self): + """mix node represents a module that mixs all input channels and + generete new output channels, such as conv and linear.""" + return self.basic_type in ['conv2d', 'linear', 'gwconv2d'] + + def is_input(self): + """Whether the node is an input node.""" + return self.val == 'input_placeholder' + + def is_output(self): + """Whether the node is an output node.""" + return self.val == 'output_placeholder' + + def check(self): + """Check whether the node has any error.""" + if self.is_input(): + assert len(self.prev_nodes) == 0, f'{self}' + my_assert(len(self.next_nodes) > 0, NoOutputError(self)) + elif self.is_output(): + my_assert(len(self.prev_nodes) > 0, NoInputError(self)) + assert len(self.next_nodes) == 0, f'{self}' + else: + my_assert(len(self.prev_nodes) > 0, NoInputError(self)) + my_assert(len(self.next_nodes) > 0, NoOutputError(self)) + + +MODULENODE = TypeVar('MODULENODE', bound=ModuleNode) + + +class ModuleGraph(BaseGraph[MODULENODE]): + """Computatation Graph.""" + + def __init__(self, model=None) -> None: + super().__init__() + self._model: nn.Module = model + + # functions to generate module graph. + + @staticmethod + def init_from_backward_tracer( + model: Module, + backward_tracer=BackwardTracer( + loss_calculator=ImageClassifierPseudoLoss()), + ): + """init module graph using backward tracer.""" + if isinstance(backward_tracer, dict): + backward_tracer = TASK_UTILS.build(backward_tracer) + path_lists = backward_tracer.trace(model) + converter = PathToGraphConverter(path_lists, model) + converter.graph.refresh_module_name() + return converter.graph + + @staticmethod + def init_from_model(model: Module): + """init module graph from a model which uses connect_module to record + the relation among modules.""" + pass + + # others + def refresh_module_name(self): + """Refresh the module name.""" + module2name = {} + for name, module in self._model.named_modules(): + module2name[module] = name + + for node in self: + if isinstance(node.val, nn.Module): + node.module_name = module2name[node.val] + + def check(self, fix=False): + """Check whether the Graph has any error.""" + for node in copy.copy(list(self.topo_traverse())): + self._check(node, fix=fix) + + def _check(self, node, fix=False): + """Helper method for self.check.""" + try: + node.check() + except Exception as e: + if not fix: + raise e + else: + try: + raise e + except NoOutputError as e: + print_log( + f'add a output after {node}, error: {e}', + level='debug') + self._add_output_after(node) + except NoInputError as e: + print_log( + f'add a input before {node}, error: {e}', + level='debug') + self._add_input_before(node) + + self._check(node, fix=True) + + def _add_input_before(self, node): + """Add an input node before a node.""" + input_node = ModuleNode('auto_input', + 'input_placeholder') # type: ignore + input_node = self.add_or_find_node(input_node) + self.connect(input_node, node) + + def _add_output_after(self, node): + """Add an output node after a node.""" + output_node = ModuleNode('auto_output', + 'output_placeholder') # type: ignore + output_node = self.add_or_find_node(output_node) + self.connect(node, output_node) + + +# Converter + + +class GraphConverter: + """Base class for converters for ModuleGraph.""" + + def __init__(self, model) -> None: + self.graph = ModuleGraph[ModuleNode](model) + self.cat_placeholder_num = 0 + self.bind_placeholder_num = 0 + self.pass_placeholder_num = 0 + + # add node + + def _new_placeholder_node(self, type: str, expand_ratio=1): + """New cat/bind/pass node.""" + assert type in [ + 'cat_placeholder', 'pass_placeholder', 'bind_placeholder' + ] + if expand_ratio != 1: + assert type == 'pass_placeholder' + if type == 'cat_placeholder': + num = self.cat_placeholder_num + self.cat_placeholder_num += 1 + elif type == 'pass_placeholder': + num = self.pass_placeholder_num + self.pass_placeholder_num += 1 + elif type == 'bind_placeholder': + num = self.bind_placeholder_num + self.bind_placeholder_num += 1 + else: + pass + node = ModuleNode(f'{type}_{num}', type) + self.graph.add_or_find_node(node) + return node + + # insert nodes + + def _insert_node_before(self, node: ModuleNode, new_node: ModuleNode): + """Insert a new node before a node.""" + for pre in node.prev_nodes: + self.graph.connect(pre, new_node) + for pre in new_node.prev_nodes: + self.graph.disconnect(pre, node) + self.graph.connect(new_node, node) + + def _insert_bind_nodes(self): + """Add bind nodes before the nodes which only need one previous node + but have more than one.""" + + need_bind_nodes = [] + for node in self.graph: + if (isinstance(node.val, nn.Conv2d) + or isinstance(node.val, nn.Linear) + or isinstance(node.val, nn.modules.batchnorm._BatchNorm)): + if len(node.prev_nodes) > 1: + need_bind_nodes.append(node) + for node in need_bind_nodes: + bind_node = self._new_placeholder_node('bind_placeholder') + self._insert_node_before(node, bind_node) + + def _insert_pass_nodes(self): + """Add pass nodes where the channel conflict.""" + for node in copy.copy(list(self.graph.nodes.values())): + if len(node.prev_nodes) == 1: + pre: ModuleNode = node.prev_nodes[0] + if node.in_channels != pre.out_channels: + assert node.in_channels % pre.out_channels == 0, \ + f'{node.name} channel error' + pass_node = self._new_placeholder_node( + 'pass_placeholder', + node.in_channels // pre.out_channels) + self._insert_node_before(node, pass_node) + + def _remove_redundant_pass_nodes(self): + """Remove redundant pass nodes, which do not change number of channels + and do not represent any module.""" + for node in copy.copy(list(self.graph.nodes.values())): + if (node.is_pass_node() and len(node.prev_nodes) == 1 + and len(node.next_nodes) == 1 + and not isinstance(node.val, nn.Module) + and node.in_channels == node.out_channels): + self.graph.delete_node(node) + + # topo_rename_nodes + def _topo_rename(self): + """Rename cat, bind, pass nodes in topological order.""" + self.cat_placeholder_num = 0 + self.bind_placeholder_num = 0 + self.pass_placeholder_num = 0 + sorted_nodes = OrderedDict() + for node in self.graph.topo_traverse(): + node: ModuleNode + if isinstance(node.val, Module): + pass + elif node.is_pass_node(): + node.name = f'pass_{self.pass_placeholder_num}' + self.pass_placeholder_num += 1 + elif node.is_cat_node(): + node.name = f'cat_{self.cat_placeholder_num}' + self.cat_placeholder_num += 1 + elif node.is_bind_node(): + node.name = f'bind_{self.bind_placeholder_num}' + self.bind_placeholder_num += 1 + else: + pass + sorted_nodes[node.name] = node + self.graph.nodes = sorted_nodes + + # other + def _post_process(self): + """Some post process after init a basic module graph.""" + # self._remove_redundant_pass_nodes() + self._insert_bind_nodes() + self._topo_rename() + + +class PathToGraphConverter(GraphConverter): + """The class converts pathlist, which is generated by backward tracer, to a + module graph.""" + + def __init__(self, path_list: PathList, model: Module) -> None: + """ + Args: + path_list (PathList): path_list generated by backward tracer. + model (Module): the model corresponding to the path_list + """ + super().__init__(model) + self.path_list = path_list + self.cat_dict: Dict[str, str] = {} + self.name2module = dict(model.named_modules()) + self._parse(self.path_list) + + self._insert_bind_nodes() + self._topo_rename() + + def _parse(self, path_list: PathList): + """Parse path list.""" + self._parse_helper(path_list, []) + + def _parse_helper(self, path_unit: Union[PathList, Path, PathNode], + next_nodes: List[ModuleNode]): + """Parse a node(unit) in path list.""" + current_node = None + # path_list + if isinstance(path_unit, PathList): + for single_path in path_unit: # sibling + self._parse_helper(single_path, next_nodes) + + # path: + elif isinstance(path_unit, Path): + current_nexts = next_nodes + for node in path_unit: # parent -> children + current_node = self._parse_helper(node, current_nexts) + current_nexts = [current_node] + + # Node + elif isinstance(path_unit, PathNode): + + # cat node: [cat_path_lists] + if isinstance(path_unit, PathConcatNode): + current_node = self._add_or_find_node(path_unit) + self._connect_nexts(current_node, next_nodes) + for catpath in path_unit.path_lists: # sibling + self._parse_helper(catpath, [current_node]) + + # single node + else: + current_node = self._add_or_find_node(path_unit) + self._connect_nexts(current_node, next_nodes) + return current_node + + def _add_or_find_cat_node(self, pathnode: PathConcatNode): + """Receive a cat-node. + + If the cat-node exists in the graph, the corresponding node is + returned, or a new cat node is added to the graph. + """ + + def unify_cat_name(name: str): + cat_name = name.split('_') + inputs = sorted(cat_name[1:]) + return f"cat_{'_'.join(inputs)}" + + name_id = pathnode.name + name_id = unify_cat_name(name_id) + if name_id in self.cat_dict: + name = self.cat_dict[name_id] + else: + name = f'cat_{self.cat_placeholder_num}' + self.cat_placeholder_num += 1 + self.cat_dict[name_id] = name + node = self.graph.add_or_find_node(ModuleNode(name, 'cat_placeholder')) + return node + + def _add_or_find_node(self, pathnode: PathNode) -> Module: + """Receive a cat-node. + + If the cat-node exists in the graph, the corresponding node is + returned, or a new cat node is added to the graph. + """ + if isinstance(pathnode, PathConcatNode): + return self._add_or_find_cat_node(pathnode) + else: + name = pathnode.name + assert name in self.name2module, f"{name} doesn't exist in model" + module = self.name2module[name] + return self.graph.add_or_find_node(ModuleNode(name, module)) + + def _connect_nexts(self, node, nexts: List[ModuleNode]): + """Connext the node and the nodes in nexts.""" + for next in nexts: + self.graph.connect(node, next) + + +class FxTracerToGraphConverter(GraphConverter): + """Use fx tracer to parse model, and generate module-graph.""" + + def __init__(self, base_graph, model=None) -> None: + """ + Args: + model (Module): the model which will be parsed + is_extra_leaf_module (Callable): a function used to determine, + if a module is a leaf module except torch pre-defined modules + """ + super().__init__(model) + self.base_graph = base_graph + self._convert_graph() + + def _node_converter(self, node: FxBaseNode): + """Convert a fxnode to a module-node.""" + if node.is_function(): + val = node.function() + elif node.is_input(): + val = 'input_placeholder' + elif node.is_output(): + val = 'output_placeholder' + elif node.is_method(): + val = node.method() + elif node.is_get_attr(): + val = 'get_attr' + elif node.is_module(): + val = node.module() + else: + raise NotImplementedError(f'{node} is unsupported') + + new_node = ModuleNode(node.name, val) + return new_node + + def _convert_graph(self): + """Convert a torch-graph to a module-graph.""" + base_graph = self.base_graph + # copy_nodes and connect + module_graph = ModuleGraph.copy_from(base_graph, self._node_converter) + self.graph = module_graph diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/pseudo_fx_graph.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/pseudo_fx_graph.py new file mode 100755 index 000000000..210fc2302 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/pseudo_fx_graph.py @@ -0,0 +1,105 @@ +# Copyright (c) OpenMMLab. All rights reserved. +"""This module define FxTracer and related classes.""" + +import torch + +from mmrazor.utils import get_placeholder + +try: + import torch.fx as fx + from torch.fx.node import Node as FxNode +except ImportError: + fx = get_placeholder('torch>=1.12') + FxNode = get_placeholder('torch>=1.12') +from mmrazor.structures.graph.base_graph import BaseGraph, BaseNode + + +class FxBaseNode(BaseNode): + """Node to record FxNode.""" + + def __init__(self, name: str, val: FxNode) -> None: + super().__init__(name, val) + + def module(self): + """Union[Module | None]: the module the fxnode corresponding to.""" + self.val: FxNode + model = self.val.graph.owning_module + if self.val.op == 'call_module': + target = self.val.target + target = target.split('.') + obj = model + for t in target: + obj = getattr(obj, t) + return obj + else: + return None + + def function(self): + """Union[Callable | Node]: the function the fxnode corresponding to.""" + if self.is_function(): + return self.val.target + else: + return None + + def method(self): + if self.is_method(): + return self.val.target + else: + return None + + # base type + # placeholder|call_method|call_module|call_function|get_attr|output + + def is_function(self): + """Bool: if the fxnode represents 'call_function'""" + return self.val.op == 'call_function' + + def is_module(self): + """Bool: if the fxnode represents 'call_module'""" + return self.val.op == 'call_module' + + def is_input(self): + """Bool: if the fxnode represents input or output tensors""" + return self.val.op == 'placeholder' + + def is_output(self): + return self.val.op == 'output' + + def is_method(self): + """Bool: if the fxnode represents 'call_method'""" + return self.val.op == 'call_method' + + def is_get_attr(self): + """Bool: if the fxnode represents 'get_attr'""" + return self.val.op == 'get_attr' + + # extended type + + def is_cat(self): + """Bool: if the fxnode represents a cat node""" + return self.is_function() and self.function() is torch.cat + + # other + + def __repr__(self) -> str: + return f'{self.name}({self.val.op})' + + +def parse_torch_graph(torch_graph): + """BaseGraph: convert torch graph to self.graph""" + torch_graph: fx.graph.Graph + + def add_node(graph, fxnode): + node = graph.add_or_find_node(FxBaseNode(fxnode.name, fxnode)) + return node + + graph = BaseGraph[FxBaseNode]() + # copy_nodes + for fxnode in torch_graph.nodes: + add_node(graph, fxnode) + + # connect nodes + for fxnode in torch_graph.nodes: + for pre_node in fxnode.all_input_nodes: + graph.connect(add_node(graph, pre_node), add_node(graph, fxnode)) + return graph diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/__init__.py new file mode 100755 index 000000000..cbf28034f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/__init__.py @@ -0,0 +1,3 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .backend_config import * # noqa: F401,F403 +from .qconfig import * # noqa: F401,F403 diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/__init__.py new file mode 100755 index 000000000..151968f8d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/__init__.py @@ -0,0 +1,21 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .academic import (get_academic_backend_config, + get_academic_backend_config_dict) +from .mapping import BackendConfigs +from .native import get_native_backend_config, get_native_backend_config_dict +from .openvino import (get_openvino_backend_config, + get_openvino_backend_config_dict) +from .tensorrt import (get_tensorrt_backend_config, + get_tensorrt_backend_config_dict) + +__all__ = [ + 'BackendConfigs', + 'get_native_backend_config', + 'get_native_backend_config_dict', + 'get_academic_backend_config', + 'get_academic_backend_config_dict', + 'get_openvino_backend_config', + 'get_openvino_backend_config_dict', + 'get_tensorrt_backend_config', + 'get_tensorrt_backend_config_dict', +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/academic.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/academic.py new file mode 100755 index 000000000..6b4f0d598 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/academic.py @@ -0,0 +1,56 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +try: + from torch.ao.quantization.backend_config import BackendConfig, DTypeConfig +except ImportError: + from mmrazor.utils import get_placeholder + BackendConfig = get_placeholder('torch>=1.13') + DTypeConfig = get_placeholder('torch>=1.13') + +from .common_operator_config_utils import (_get_conv_configs, + _get_linear_configs) + +# ===================== +# | BACKEND CONFIGS | +# ===================== + + +def get_academic_backend_config() -> BackendConfig: + """Return the `BackendConfig` for academic reseaching. + + Note: + Learn more about BackendConfig, please refer to: + https://github.com/pytorch/pytorch/tree/master/torch/ao/quantization/backend_config # noqa: E501 + """ + + # =================== + # | DTYPE CONFIGS | + # =================== + # weighted op int8 dtype config + # this is config for ops that has quantized weights, like linear, conv + weighted_op_int8_dtype_config = DTypeConfig( + input_dtype=torch.quint8, + output_dtype=torch.quint8, + weight_dtype=torch.qint8, + bias_dtype=torch.float, + ) + + conv_dtype_configs = [weighted_op_int8_dtype_config] + linear_dtype_configs = [weighted_op_int8_dtype_config] + + return BackendConfig('academic') \ + .set_backend_pattern_configs(_get_conv_configs(conv_dtype_configs)) \ + .set_backend_pattern_configs(_get_linear_configs(linear_dtype_configs)) + + +def get_academic_backend_config_dict(): + """Return the `BackendConfig` for academic reseaching in dictionary + form.""" + return get_academic_backend_config().to_dict() + + +__all__ = [ + 'get_academic_backend_config', + 'get_academic_backend_config_dict', +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/common_operator_config_utils.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/common_operator_config_utils.py new file mode 100755 index 000000000..0a381d5d0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/common_operator_config_utils.py @@ -0,0 +1,639 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import operator +from collections import namedtuple +from typing import List + +import torch +import torch.nn as nn + +from mmrazor import digit_version + +try: + import torch.nn.functional as F + import torch.nn.intrinsic as nni + import torch.nn.intrinsic.qat as nniqat + import torch.nn.qat as nnqat + import torch.nn.quantized._reference as nnqr + from torch.ao.quantization.backend_config import (BackendPatternConfig, + DTypeConfig, + ObservationType) + from torch.ao.quantization.fake_quantize import FixedQParamsFakeQuantize + from torch.ao.quantization.fuser_method_mappings import ( + fuse_conv_bn, fuse_conv_bn_relu, fuse_convtranspose_bn, fuse_linear_bn, + reverse2, reverse3, reverse_sequential_wrapper2) + from torch.ao.quantization.qconfig_mapping import \ + _FIXED_QPARAMS_OP_TO_OBSERVER +except ImportError: + from mmrazor.utils import get_package_placeholder, get_placeholder + F = get_package_placeholder('torch>=1.13') + nni = get_package_placeholder('torch>=1.13') + nniqat = get_package_placeholder('torch>=1.13') + nnqat = get_package_placeholder('torch>=1.13') + nnqr = get_package_placeholder('torch>=1.13') + BackendPatternConfig = get_placeholder('torch>=1.13') + DTypeConfig = get_placeholder('torch>=1.13') + ObservationType = get_placeholder('torch>=1.13') + FixedQParamsFakeQuantize = get_placeholder('torch>=1.13') + fuse_conv_bn = get_placeholder('torch>=1.13') + fuse_conv_bn_relu = get_placeholder('torch>=1.13') + fuse_convtranspose_bn = get_placeholder('torch>=1.13') + fuse_linear_bn = get_placeholder('torch>=1.13') + reverse2 = get_placeholder('torch>=1.13') + reverse3 = get_placeholder('torch>=1.13') + reverse_sequential_wrapper2 = get_placeholder('torch>=1.13') + _FIXED_QPARAMS_OP_TO_OBSERVER = get_placeholder('torch>=1.13') + +_ConvMetadata = namedtuple('_ConvMetadata', [ + 'root', 'transpose', 'bn', 'reference', 'transpose_reference', + 'fused_conv_relu', 'fused_conv_bn', 'fused_conv_bn_relu', 'qat', + 'relu_qat', 'bn_qat', 'bn_relu_qat', 'func' +]) + +if digit_version(torch.__version__) >= digit_version('1.13.0'): + _Conv1dMetadata = _ConvMetadata( + nn.Conv1d, nn.ConvTranspose1d, nn.BatchNorm1d, nnqr.Conv1d, + nnqr.ConvTranspose1d, nni.ConvReLU1d, nni.ConvBn1d, nni.ConvBnReLU1d, + nnqat.Conv1d, nniqat.ConvReLU1d, nniqat.ConvBn1d, nniqat.ConvBnReLU1d, + F.conv1d) + _Conv2dMetadata = _ConvMetadata( + nn.Conv2d, nn.ConvTranspose2d, nn.BatchNorm2d, nnqr.Conv2d, + nnqr.ConvTranspose2d, nni.ConvReLU2d, nni.ConvBn2d, nni.ConvBnReLU2d, + nnqat.Conv2d, nniqat.ConvReLU2d, nniqat.ConvBn2d, nniqat.ConvBnReLU2d, + F.conv2d) + _Conv3dMetadata = _ConvMetadata( + nn.Conv3d, nn.ConvTranspose3d, nn.BatchNorm3d, nnqr.Conv3d, + nnqr.ConvTranspose3d, nni.ConvReLU3d, nni.ConvBn3d, nni.ConvBnReLU3d, + nnqat.Conv3d, nniqat.ConvReLU3d, nniqat.ConvBn3d, nniqat.ConvBnReLU3d, + F.conv3d) +else: + toy_val = _ConvMetadata(*[i for i in range(13)]) + _Conv1dMetadata = toy_val + _Conv2dMetadata = toy_val + _Conv3dMetadata = toy_val + + +def _get_binary_op_configs( + dtype_configs: List[DTypeConfig]) -> List[BackendPatternConfig]: + binary_op_configs: List[BackendPatternConfig] = [] + num_tensor_args_to_observation_type_mapping = { + # TODO: this is not used right now since we have extra check in prepare + # will need to change this to NO_OBSERVER later after we implemented + # Tensor dtype inference properly + 0: ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT, + 1: ObservationType.OUTPUT_SHARE_OBSERVER_WITH_INPUT, + 2: ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT, + } + for op_with_quantized_bop_scalar_variant in [ + operator.add, torch.add, operator.mul, torch.mul + ]: + bop_patterns = [(torch.nn.ReLU, op_with_quantized_bop_scalar_variant), + (torch.nn.functional.relu, + op_with_quantized_bop_scalar_variant), + (torch.relu, op_with_quantized_bop_scalar_variant), + op_with_quantized_bop_scalar_variant] + for bop_pattern in bop_patterns: + binary_op_configs.append( + BackendPatternConfig(bop_pattern).set_dtype_configs( + dtype_configs) # noqa: E131 + ._set_num_tensor_args_to_observation_type( + num_tensor_args_to_observation_type_mapping)) + # matmul + binary_op_configs.append( + BackendPatternConfig(torch.matmul).set_dtype_configs( + dtype_configs) # noqa: E131 + ) + return binary_op_configs + + +def _get_linear_configs( + dtype_configs: List[DTypeConfig]) -> List[BackendPatternConfig]: + """Return all configs related to linear modules and ops.""" + observation_type = ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + linear_configs: List[BackendPatternConfig] = [] + + # (1) Single linear modules/functions + # ------------------------------------- + # linear module + linear_configs.append( + BackendPatternConfig(torch.nn.Linear).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + torch.nn.Linear).set_reference_quantized_module( + nnqr.Linear).set_qat_module(nnqat.Linear)) + # linear qat module + linear_configs.append( + BackendPatternConfig(nnqat.Linear).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + torch.nn.Linear).set_reference_quantized_module(nnqr.Linear)) + # functional linear + linear_configs.append( + BackendPatternConfig(torch.nn.functional.linear).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs)._set_input_type_to_index({ + 'weight': 1, + 'bias': 2 + })) + + # (2) Linear + relu + # ------------------- + # 2.1 linear module + relu fusion config + # linear relu, linear module + relu module + linear_configs.append( + BackendPatternConfig( + (torch.nn.ReLU, + torch.nn.Linear)).set_dtype_configs(dtype_configs) # noqa: E131 + .set_fuser_method(reverse_sequential_wrapper2( + nni.LinearReLU)).set_fused_module(nni.LinearReLU)) + # linear relu, linear module + functional relu + linear_configs.append( + BackendPatternConfig( + (torch.nn.functional.relu, + torch.nn.Linear)).set_dtype_configs(dtype_configs) # noqa: E131 + .set_fuser_method(reverse_sequential_wrapper2( + nni.LinearReLU)).set_fused_module(nni.LinearReLU)) + + # 2.2 linear module + relu, fused module configs + # linear relu, fused module + linear_configs.append( + BackendPatternConfig(nni.LinearReLU).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + torch.nn.Linear).set_reference_quantized_module( + nnqr.Linear).set_qat_module(nniqat.LinearReLU)) + # linear relu, qat fused module + linear_configs.append( + BackendPatternConfig(nniqat.LinearReLU).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + torch.nn.Linear).set_reference_quantized_module(nnqr.Linear)) + # 2.3 functional linear + relu configs + # linear relu, functional linear + relu module + linear_configs.append( + BackendPatternConfig( + (torch.nn.ReLU, + F.linear)).set_observation_type(observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs)) + # linear relu, functional linear + functional relu + linear_configs.append( + BackendPatternConfig( + (F.relu, + F.linear)).set_observation_type(observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs)) + + # (3) Linear + batchnorm + # ------------------------ + # 3.1 linear bn fusion + linear_configs.append( + BackendPatternConfig( + (nn.BatchNorm1d, + nn.Linear)).set_dtype_configs(dtype_configs) # noqa: E131 + .set_fuser_method(reverse2(fuse_linear_bn)).set_fused_module( + nni.LinearBn1d)) + + # 3.2 linear bn fused + # linear bn, fused module + linear_configs.append( + BackendPatternConfig(nni.LinearBn1d).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + torch.nn.Linear).set_reference_quantized_module( + nnqr.Linear).set_qat_module(nniqat.LinearBn1d)) + # linear bn, qat fused module + linear_configs.append( + BackendPatternConfig(nniqat.LinearBn1d).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + torch.nn.Linear).set_reference_quantized_module(nnqr.Linear)) + return linear_configs + + +def _get_conv_configs(dtype_configs): + """Return all configs related to conv modules and ops.""" + conv_configs = [] + observation_type = ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + for convs in [_Conv1dMetadata, _Conv2dMetadata, _Conv3dMetadata]: + + # (1) Single conv modules/functions + # ----------------------------------- + # conv module + conv_configs.append( + BackendPatternConfig(convs.root).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + convs.root).set_reference_quantized_module( + convs.reference).set_qat_module(convs.qat)) + # conv qat module + conv_configs.append( + BackendPatternConfig(convs.qat).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + convs.root).set_reference_quantized_module(convs.reference)) + # functional conv + conv_configs.append( + BackendPatternConfig(convs.func).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs)._set_input_type_to_index({ + 'weight': + 1, + 'bias': + 2 + })) + + # (2) Conv + relu + # ----------------- + # 2.1 conv module + relu fusion configs + # conv relu fusion, conv module + relu module + conv_configs.append( + BackendPatternConfig( + (torch.nn.ReLU, + convs.root)).set_dtype_configs(dtype_configs) # noqa: E131 + .set_fuser_method( + reverse_sequential_wrapper2( + convs.fused_conv_relu)).set_fused_module( + convs.fused_conv_relu)) + # conv relu fusion, conv module + functional relu + conv_configs.append( + BackendPatternConfig( + (F.relu, + convs.root)).set_dtype_configs(dtype_configs) # noqa: E131 + .set_fuser_method( + reverse_sequential_wrapper2( + convs.fused_conv_relu)).set_fused_module( + convs.fused_conv_relu)) + # 2.2 conv module + relu fused module configs + # conv relu, fused module + conv_configs.append( + BackendPatternConfig(convs.fused_conv_relu).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + convs.root).set_reference_quantized_module( + convs.reference).set_qat_module(convs.relu_qat)) + # conv relu, qat fused module + conv_configs.append( + BackendPatternConfig(convs.relu_qat).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + convs.root).set_reference_quantized_module(convs.reference)) + # 2.3 functional conv + relu configs + # conv relu, functional conv + relu module + conv_configs.append( + BackendPatternConfig( + (torch.nn.ReLU, convs.func)).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs)) + # conv relu, functional conv + functional relu + conv_configs.append( + BackendPatternConfig((F.relu, convs.func)).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs)) + + # fused conv relu + conv_configs.append( + BackendPatternConfig(convs.fused_conv_relu).set_dtype_configs( + dtype_configs) # noqa: E131 + .set_qat_module(convs.relu_qat)) + + conv_configs.append( + BackendPatternConfig(convs.relu_qat).set_dtype_configs( + dtype_configs) # noqa: E131 + .set_root_module(convs.root).set_reference_quantized_module( + convs.reference)) + + # (3) Conv + batchnorm (+ relu) + # ------------------------------- + # 3.1 conv bn fusion configs + # conv + bn fusion + conv_configs.append( + BackendPatternConfig( + (convs.bn, + convs.root)).set_dtype_configs(dtype_configs) # noqa: E131 + .set_fuser_method(reverse2(fuse_conv_bn)).set_fused_module( + convs.fused_conv_bn)) + # conv + bn + relu module fusion + conv_configs.append( + BackendPatternConfig( + (nn.ReLU, + (convs.bn, + convs.root))).set_dtype_configs(dtype_configs) # noqa: E131 + .set_fuser_method(reverse3(fuse_conv_bn_relu)).set_fused_module( + convs.fused_conv_bn_relu)) + # conv + bn + relu functional fusion + conv_configs.append( + BackendPatternConfig( + (F.relu, + (convs.bn, + convs.root))).set_dtype_configs(dtype_configs) # noqa: E131 + .set_root_module(convs.root).set_fuser_method( + reverse3(fuse_conv_bn_relu)).set_fused_module( + convs.fused_conv_bn_relu)) + # TODO: we can add fusion for torch.relu as well + + # 3.2 conv + bn (+ relu) fused module configs + # fused conv bn + conv_configs.append( + BackendPatternConfig(convs.fused_conv_bn).set_dtype_configs( + dtype_configs) # noqa: E131 + .set_qat_module(convs.bn_qat)) + + # fused conv bn relu + conv_configs.append( + BackendPatternConfig(convs.fused_conv_bn_relu).set_dtype_configs( + dtype_configs) # noqa: E131 + .set_qat_module(convs.bn_relu_qat)) + + # conv bn, qat fused module + conv_configs.append( + BackendPatternConfig(convs.bn_qat).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + convs.root).set_reference_quantized_module(convs.reference)) + # conv bn relu, qat fused module + conv_configs.append( + BackendPatternConfig(convs.bn_relu_qat).set_observation_type( + observation_type) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + convs.root).set_reference_quantized_module(convs.reference)) + + # (4) conv transpose and its fusion + # 4.1 conv transpose config + conv_configs.append( + BackendPatternConfig(convs.transpose).set_dtype_configs( + dtype_configs) # noqa: E131 + .set_root_module(convs.transpose).set_reference_quantized_module( + convs.transpose_reference)) + + # 4.2 conv transpose + bn fusion + conv_configs.append( + BackendPatternConfig( + (convs.bn, convs.transpose)).set_dtype_configs( + dtype_configs) # noqa: E131 + .set_fuser_method(reverse2(fuse_convtranspose_bn)).set_root_module( + convs.transpose).set_reference_quantized_module( + convs.transpose_reference)) + + return conv_configs + + +def _get_cat_config(dtype_configs: List[DTypeConfig]) -> BackendPatternConfig: + return BackendPatternConfig(torch.cat) \ + .set_observation_type( + ObservationType.OUTPUT_SHARE_OBSERVER_WITH_INPUT) \ + .set_dtype_configs(dtype_configs) + + +def _get_ln_configs( + dtype_configs: List[DTypeConfig]) -> List[BackendPatternConfig]: + ln_configs = [] + ln_configs.append( + BackendPatternConfig(torch.nn.LayerNorm).set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + ) # noqa: E131 + .set_dtype_configs(dtype_configs)) + ln_configs.append( + BackendPatternConfig( + torch.nn.functional.layer_norm).set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + ) # noqa: E131 + .set_dtype_configs(dtype_configs)._set_input_type_to_index({ + 'weight': 2, + 'bias': 3 + })) + return ln_configs + + +def _get_default_op_configs( + dtype_configs: List[DTypeConfig]) -> List[BackendPatternConfig]: + configs = [] + default_ops = [ + torch.nn.ELU, + torch.nn.LeakyReLU, + torch.nn.Hardswish, + torch.nn.InstanceNorm1d, + torch.nn.InstanceNorm2d, + torch.nn.InstanceNorm3d, + torch.nn.Dropout, + torch.nn.PReLU, + torch.nn.functional.elu, + torch.nn.functional.hardswish, + torch.nn.functional.leaky_relu, + torch.nn.functional.dropout, + ] + for op in default_ops: + configs.append( + BackendPatternConfig(op).set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + ) # noqa: E131 + .set_dtype_configs(dtype_configs)) + + configs.append( + BackendPatternConfig( + torch.nn.functional.group_norm).set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + ) # noqa: E131 + .set_dtype_configs(dtype_configs)._set_input_type_to_index({ + 'weight': 2, + 'bias': 3 + })) + + configs.append( + BackendPatternConfig( + torch.nn.functional.instance_norm).set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + ) # noqa: E131 + .set_dtype_configs(dtype_configs)._set_input_type_to_index({ + 'weight': 3, + 'bias': 4 + })) + return configs + + +def _get_fixed_qparams_op_configs( + dtype_configs: List[DTypeConfig]) -> List[BackendPatternConfig]: + fixed_qparams_op_configs = [] + op_to_obs = _FIXED_QPARAMS_OP_TO_OBSERVER.items() + for fixed_qparam_op, output_observer in op_to_obs: + fixed_qparams_op_configs.append( + # TODO: The _overwrite_output keys are temporary, since we don't + # want to put observer in the configs we expect that it's provided + # by user What we want to put here is the requirement on observers, + # in this case dtype, quant_min, quant_max etc., but we need to + # first move all configs to backend_config_dict to do that, we'll + # remove these keys after we fully migrated everything to use + # backend_config_dict + BackendPatternConfig(fixed_qparam_op).set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + ) # noqa: E131 + .set_dtype_configs(dtype_configs). + _set_overwrite_output_fake_quantize( + FixedQParamsFakeQuantize.with_args(observer=output_observer) + )._set_overwrite_output_observer(output_observer)) + return fixed_qparams_op_configs + + +def _get_share_qparams_op_configs(dtype_configs): + """Get the operator config for the operators that works for both float and + quantized input if input is quantized, the output Tensor shares the same + quantization parameter with input. Example operator: avgpool2d, reshape, + transpose, maxpool2d Example observed operator: + + observer_0 - avgpool2d - observer_0 (same observer instance as input) + """ + + def _get_share_qprams_op_backend_config(op): + return BackendPatternConfig(op) \ + .set_observation_type( + ObservationType.OUTPUT_SHARE_OBSERVER_WITH_INPUT) \ + .set_dtype_configs(dtype_configs) + + share_qparams_ops = [ + torch.nn.AdaptiveAvgPool1d, + torch.nn.AdaptiveAvgPool2d, + torch.nn.AdaptiveAvgPool3d, + torch.nn.AvgPool1d, + torch.nn.AvgPool2d, + torch.nn.AvgPool3d, + torch.nn.Hardtanh, + torch.nn.Identity, + torch.nn.MaxPool1d, + torch.nn.MaxPool2d, + torch.nn.MaxPool3d, + torch.nn.ReLU, + torch.adaptive_avg_pool1d, + torch.nn.functional.adaptive_avg_pool2d, + torch.nn.functional.adaptive_avg_pool3d, + torch.nn.functional.hardtanh, + torch.nn.functional.hardtanh_, + torch.nn.functional.interpolate, + torch.nn.functional.max_pool1d, + torch.nn.functional.max_pool2d, + torch.nn.functional.max_pool3d, + torch.nn.functional.relu, + torch.nn.functional.relu6, + torch.avg_pool1d, + torch._C._nn.avg_pool2d, + torch._C._nn.avg_pool3d, + torch.clamp, + torch.flatten, + torch.mean, + torch.repeat_interleave, + torch.transpose, + torch.squeeze, + torch.stack, + torch.unsqueeze, + operator.floordiv, + 'contiguous', + 'clamp', + 'detach', + 'detach_', + 'mean', + 'permute', + 'repeat', + 'repeat_interleave', + 'reshape', + 'resize_', + 'relu', + 'relu_', + 'shape', + 'size', + 'squeeze', + 'squeeze_', + 'transpose', + 'unsqueeze', + 'unsqueeze_', + 'view', + ] + return [ + _get_share_qprams_op_backend_config(op) for op in share_qparams_ops + ] + + +def _get_bn_configs( + dtype_configs: List[DTypeConfig]) -> List[BackendPatternConfig]: + """Get configs related to batchnorm.""" + bn_configs = [] + bn_to_fused_bn = { + torch.nn.BatchNorm2d: nni.BNReLU2d, + torch.nn.BatchNorm3d: nni.BNReLU3d, + } + for bn in bn_to_fused_bn.keys(): + fused_bn = bn_to_fused_bn[bn] + # bn module + relu module fusion config + bn_configs.append( + BackendPatternConfig( + (torch.nn.ReLU, + bn)).set_dtype_configs(dtype_configs) # noqa: E131 + .set_fuser_method(reverse_sequential_wrapper2( + fused_bn)).set_fused_module(fused_bn)) + # bn module + F.relu fusion config + bn_configs.append( + BackendPatternConfig( + (torch.nn.functional.relu, + bn)).set_dtype_configs(dtype_configs) # noqa: E131 + .set_fuser_method(reverse_sequential_wrapper2( + bn_to_fused_bn[bn])).set_fused_module(fused_bn)) + bn_configs.append( + BackendPatternConfig(bn).set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + ) # noqa: E131 + .set_dtype_configs(dtype_configs)) + + # fused bn configs + for fused_bn in bn_to_fused_bn.values(): + bn_configs.append( + BackendPatternConfig(fused_bn).set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + ) # noqa: E131 + .set_dtype_configs(dtype_configs)) + return bn_configs + + +def _get_rnn_op_configs( + dtype_configs: List[DTypeConfig]) -> List[BackendPatternConfig]: + rnn_op_configs = [] + for rnn_op, ref_rnn_op in [(nn.GRUCell, nnqr.GRUCell), + (nn.LSTMCell, nnqr.LSTMCell), + (nn.RNNCell, nnqr.RNNCell), + (nn.LSTM, nnqr.LSTM)]: + rnn_op_configs.append( + BackendPatternConfig(rnn_op).set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + ) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + rnn_op).set_reference_quantized_module(ref_rnn_op)) + return rnn_op_configs + + +def _get_embedding_op_configs( + dtype_configs: List[DTypeConfig]) -> List[BackendPatternConfig]: + embedding_op_configs = [] + for embedding_op, qat_embedding_op, ref_embedding_op in [ + (nn.Embedding, nnqat.Embedding, nnqr.Embedding), + (nn.EmbeddingBag, nnqat.EmbeddingBag, nnqr.EmbeddingBag), + ]: + embedding_op_configs.append( + BackendPatternConfig(embedding_op).set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + ) # noqa: E131 + .set_dtype_configs(dtype_configs).set_qat_module(qat_embedding_op). + set_root_module(embedding_op).set_reference_quantized_module( + ref_embedding_op)._set_input_output_observed( + False)) # This is temporary, and will be removed soon + # config for qat op + embedding_op_configs.append( + BackendPatternConfig(qat_embedding_op).set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT + ) # noqa: E131 + .set_dtype_configs(dtype_configs).set_root_module( + embedding_op).set_reference_quantized_module( + ref_embedding_op)._set_input_output_observed( + False)) # This is temporary, and will be removed soon + return embedding_op_configs + + +__all__ = [ + '_get_binary_op_configs', + '_get_linear_configs', + '_get_conv_configs', + '_get_share_qparams_op_configs', +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/mapping.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/mapping.py new file mode 100755 index 000000000..b9cc5372b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/mapping.py @@ -0,0 +1,23 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +from mmrazor import digit_version +from .academic import get_academic_backend_config +from .native import get_native_backend_config +from .openvino import get_openvino_backend_config +from .tensorrt import get_tensorrt_backend_config + +if digit_version(torch.__version__) >= digit_version('1.13.0'): + BackendConfigs = { + 'academic': get_academic_backend_config(), + 'native': get_native_backend_config(), + 'tensorrt': get_tensorrt_backend_config(), + 'openvino': get_openvino_backend_config() + } +else: + BackendConfigs = { + 'academic': None, + 'native': None, + 'tensorrt': None, + 'openvino': None + } diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/native.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/native.py new file mode 100755 index 000000000..59085a56a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/native.py @@ -0,0 +1,147 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +try: + from torch.ao.quantization.backend_config import BackendConfig, DTypeConfig +except ImportError: + from mmrazor.utils import get_placeholder + BackendConfig = get_placeholder('torch>=1.13') + DTypeConfig = get_placeholder('torch>=1.13') + +from .common_operator_config_utils import ( # noqa: F401,F403 + _get_binary_op_configs, _get_bn_configs, _get_cat_config, + _get_conv_configs, _get_default_op_configs, _get_embedding_op_configs, + _get_fixed_qparams_op_configs, _get_linear_configs, _get_ln_configs, + _get_rnn_op_configs, _get_share_qparams_op_configs) + +# ===================== +# | BACKEND CONFIGS | +# ===================== + + +def get_native_backend_config() -> BackendConfig: + """Return the `BackendConfig` for PyTorch Native backend (fbgemm/qnnpack). + + Note: + Learn more about BackendConfig, please refer to: + https://github.com/pytorch/pytorch/tree/master/torch/ao/quantization/backend_config # noqa: E501 + """ + # TODO: express this BackendConfig as a union of the FBGEMM and QNNPACK + # BackendConfigs + + # =================== + # | DTYPE CONFIGS | + # =================== + # weighted op int8 dtype config + # this is config for ops that has quantized weights, like linear, conv + weighted_op_int8_dtype_config = DTypeConfig( + input_dtype=torch.quint8, + output_dtype=torch.quint8, + weight_dtype=torch.qint8, + bias_dtype=torch.float, + ) + + default_op_quint8_dtype_config = DTypeConfig( + input_dtype=torch.quint8, + output_dtype=torch.quint8, + ) + + default_dynamic_int8_dtype_config = DTypeConfig( + input_dtype=torch.quint8, + output_dtype=torch.float, + weight_dtype=torch.qint8, + bias_dtype=torch.float, + # currently the dtype check is not yet enabled, so we provided the + # dtype_configs but it is not really used yet, + # we will enable it a bit later after we moved everything to + # backend_config_dict + is_dynamic=True, + ) + + default_dynamic_float16_dtype_config = DTypeConfig( + input_dtype=torch.float16, + output_dtype=torch.float, + weight_dtype=torch.float16, + bias_dtype=torch.float, + # currently the dtype check is not yet enabled, so we provided the + # dtype_configs but it is not really used yet, we will enable it a bit + # later after we moved everything to backend_config_dict + is_dynamic=True, + ) + + # Needed for LayerNorm and f.layer_norm, since currently the kernel only + # supports float weights + input_output_only_quint8_dtype_config = DTypeConfig( + input_dtype=torch.quint8, + output_dtype=torch.quint8, + weight_dtype=torch.float, + bias_dtype=torch.float, + ) + + weight_only_quint8_dtype_config = DTypeConfig( + input_dtype=torch.float, + output_dtype=torch.float, + weight_dtype=torch.quint8, + ) + + weight_only_quint4x2_dtype_config = DTypeConfig( + input_dtype=torch.float, + output_dtype=torch.float, + weight_dtype=torch.quint4x2, + ) + + conv_dtype_configs = [weighted_op_int8_dtype_config] + linear_dtype_configs = [ + weighted_op_int8_dtype_config, + default_dynamic_int8_dtype_config, + default_dynamic_float16_dtype_config, + ] + binary_op_dtype_configs = [weighted_op_int8_dtype_config] + default_op_dtype_configs = [default_op_quint8_dtype_config] + fixed_qparams_op_dtype_configs = [weighted_op_int8_dtype_config] + share_qparams_op_dtype_configs = [default_op_quint8_dtype_config] + rnn_op_dtype_configs = [ + default_dynamic_int8_dtype_config, + default_dynamic_float16_dtype_config, + ] + embedding_op_dtype_configs = [ + weight_only_quint8_dtype_config, + weight_only_quint4x2_dtype_config, + ] + layer_norm_op_dtype_configs = [input_output_only_quint8_dtype_config] + + return BackendConfig('native') \ + .set_backend_pattern_configs( + _get_conv_configs(conv_dtype_configs)) \ + .set_backend_pattern_configs( + _get_linear_configs(linear_dtype_configs)) \ + .set_backend_pattern_configs( + _get_binary_op_configs(binary_op_dtype_configs)) \ + .set_backend_pattern_config( + _get_cat_config(default_op_dtype_configs)) \ + .set_backend_pattern_configs( + _get_default_op_configs(default_op_dtype_configs)) \ + .set_backend_pattern_configs( + _get_fixed_qparams_op_configs(fixed_qparams_op_dtype_configs)) \ + .set_backend_pattern_configs( + _get_share_qparams_op_configs(share_qparams_op_dtype_configs)) \ + .set_backend_pattern_configs( + _get_bn_configs(default_op_dtype_configs)) \ + .set_backend_pattern_configs( + _get_ln_configs(layer_norm_op_dtype_configs)) \ + .set_backend_pattern_configs( + _get_rnn_op_configs(rnn_op_dtype_configs)) \ + .set_backend_pattern_configs( + _get_embedding_op_configs(embedding_op_dtype_configs)) + + +def get_native_backend_config_dict(): + """Return the `BackendConfig` for PyTorch Native backend (fbgemm/qnnpack) + in dictionary form.""" + return get_native_backend_config().to_dict() + + +__all__ = [ + 'get_native_backend_config', + 'get_native_backend_config_dict', +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/openvino.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/openvino.py new file mode 100755 index 000000000..5e3051f75 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/openvino.py @@ -0,0 +1,89 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +try: + from torch.ao.quantization.backend_config import (BackendConfig, + BackendPatternConfig, + DTypeConfig, + ObservationType) +except ImportError: + from mmrazor.utils import get_placeholder + BackendConfig = get_placeholder('torch>=1.13') + BackendPatternConfig = get_placeholder('torch>=1.13') + DTypeConfig = get_placeholder('torch>=1.13') + ObservationType = get_placeholder('torch>=1.13') + +from .common_operator_config_utils import (_get_binary_op_configs, + _get_conv_configs, + _get_linear_configs, + _get_share_qparams_op_configs) + + +def get_openvino_backend_config() -> BackendConfig: + """Return the `BackendConfig` for the OpenVINO backend. + + Note: + Learn more about BackendConfig, please refer to: + https://github.com/pytorch/pytorch/tree/master/torch/ao/quantization/backend_config # noqa: E501 + """ + # dtype configs + weighted_op_qint8_dtype_config = DTypeConfig( + input_dtype=torch.quint8, + output_dtype=torch.quint8, + weight_dtype=torch.qint8, + bias_dtype=torch.float, + ) + non_weighted_op_qint8_dtype_config = DTypeConfig( + input_dtype=torch.quint8, + output_dtype=torch.quint8, + ) + + addmm_config = BackendPatternConfig(torch.addmm) \ + .set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT) \ + .add_dtype_config(weighted_op_qint8_dtype_config) \ + ._set_input_type_to_index({ + 'bias': 0, + 'input': 1, + 'weight': 2, + }) + cat_config = BackendPatternConfig(torch.cat) \ + .set_observation_type( + ObservationType.OUTPUT_SHARE_OBSERVER_WITH_INPUT) \ + .add_dtype_config(non_weighted_op_qint8_dtype_config) + conv_dtype_configs = [ + weighted_op_qint8_dtype_config, + ] + linear_dtype_configs = [ + weighted_op_qint8_dtype_config, + ] + binary_op_dtype_configs = [ + weighted_op_qint8_dtype_config, + ] + share_qparams_op_dtype_configs = [ + non_weighted_op_qint8_dtype_config, + ] + # there might be things not supported in fx2trt, but it will error out + # during fx2trt conversion and can support them after that + return BackendConfig('openvino') \ + .set_backend_pattern_configs(_get_conv_configs(conv_dtype_configs)) \ + .set_backend_pattern_config(addmm_config) \ + .set_backend_pattern_config(cat_config) \ + .set_backend_pattern_configs( + _get_linear_configs(linear_dtype_configs)) \ + .set_backend_pattern_configs( + _get_binary_op_configs(binary_op_dtype_configs)) \ + .set_backend_pattern_configs( + _get_share_qparams_op_configs(share_qparams_op_dtype_configs)) + + +def get_openvino_backend_config_dict(): + """Return the `BackendConfig` for the OpenVINO backend in dictionary + form.""" + return get_openvino_backend_config().to_dict() + + +__all__ = [ + 'get_openvino_backend_config', + 'get_openvino_backend_config_dict', +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/tensorrt.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/tensorrt.py new file mode 100755 index 000000000..8dddbac91 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/tensorrt.py @@ -0,0 +1,68 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + +try: + from torch.ao.quantization.backend_config import (BackendConfig, + BackendPatternConfig, + DTypeConfig, + ObservationType) +except ImportError: + from mmrazor.utils import get_placeholder + BackendConfig = get_placeholder('torch>=1.13') + BackendPatternConfig = get_placeholder('torch>=1.13') + DTypeConfig = get_placeholder('torch>=1.13') + ObservationType = get_placeholder('torch>=1.13') + +from .common_operator_config_utils import (_get_conv_configs, + _get_linear_configs) + + +def get_tensorrt_backend_config() -> BackendConfig: + """Return the `BackendConfig` for the TensorRT backend. + + Note: + Learn more about BackendConfig, please refer to: + https://github.com/pytorch/pytorch/tree/master/torch/ao/quantization/backend_config # noqa: E501 + """ + # dtype configs + weighted_op_qint8_dtype_config = DTypeConfig( + input_dtype=torch.qint8, + output_dtype=torch.qint8, + weight_dtype=torch.qint8, + bias_dtype=torch.float, + ) + + addmm_config = BackendPatternConfig(torch.addmm) \ + .set_observation_type( + ObservationType.OUTPUT_USE_DIFFERENT_OBSERVER_AS_INPUT) \ + .add_dtype_config(weighted_op_qint8_dtype_config) \ + ._set_input_type_to_index({ + 'bias': 0, + 'input': 1, + 'weight': 2, + }) + conv_dtype_configs = [ + weighted_op_qint8_dtype_config, + ] + linear_dtype_configs = [ + weighted_op_qint8_dtype_config, + ] + # there might be things not supported in fx2trt, but it will error out + # during fx2trt conversion and can support them after that + return BackendConfig('tensorrt') \ + .set_backend_pattern_configs(_get_conv_configs(conv_dtype_configs)) \ + .set_backend_pattern_config(addmm_config) \ + .set_backend_pattern_configs( + _get_linear_configs(linear_dtype_configs)) + + +def get_tensorrt_backend_config_dict(): + """Return the `BackendConfig` for the TensorRT backend in dictionary + form.""" + return get_tensorrt_backend_config().to_dict() + + +__all__ = [ + 'get_tensorrt_backend_config', + 'get_tensorrt_backend_config_dict', +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/qconfig.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/qconfig.py new file mode 100755 index 000000000..ab682be39 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/qconfig.py @@ -0,0 +1,200 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Union + +import torch +from mmengine.config import Config + +try: + from torch.ao.quantization import FakeQuantize, QConfig + from torch.ao.quantization.utils import is_per_tensor +except ImportError: + from mmrazor.utils import get_placeholder + QConfig = get_placeholder('torch>=1.13') + FakeQuantize = get_placeholder('torch>=1.13') + is_per_tensor = get_placeholder('torch>=1.13') + +from mmrazor.registry import MODELS + +RequiredArgs = [ + 'w_qscheme', 'a_qscheme', 'w_fake_quant', 'a_fake_quant', 'w_observer', + 'a_observer' +] + +RetainArgsPerTensor = [ + 'dtype', 'qscheme', 'quant_min', 'quant_max', 'reduce_range' +] +RetainArgsPerChannel = RetainArgsPerTensor + ['ch_axis'] + + +class QSchemeHandler(object): + """Convert the qscheme of custom user-friendly qconfig to args needed in + observers. + + Args: + qdtype (str): Quantization dtype. It should is 'quint8' or 'qint8', + and should be supported by the deploy backend. Defaults to 'quint8' + bit (int): Quantization bit number. Defaults to 8. + is_symmetry (bool): Is symmetry quantization or not. Defaults to True. + is_per_channel (bool): Is per-channel quantization or not. + Defaults to False. + """ + + def __init__(self, + qdtype: str = 'quint8', + bit: int = 8, + is_symmetry: bool = True, + is_per_channel: bool = False, + **kwargs): + assert qdtype in ('quint8', 'qint8'), \ + 'qdtype is incorrect, it should be quint8 or qint8.' + self.qdtype = qdtype + self.bit = bit + self.is_symmetry = is_symmetry + self.is_per_channel = is_per_channel + + if self.is_per_channel: + self.torch_qscheme = torch.per_channel_symmetric \ + if self.is_symmetry else torch.per_channel_affine + else: + self.torch_qscheme = torch.per_tensor_symmetric \ + if self.is_symmetry else torch.per_tensor_affine + if 'is_symmetric_range' in kwargs: + self.is_symmetric_range = kwargs['is_symmetric_range'] + del kwargs['is_symmetric_range'] + else: + self.is_symmetric_range = False + self.kwargs = kwargs + + def to_observer_params(self): + """Generate the args needed in observers.""" + if self.qdtype == 'quint8': + quant_min = 0 + quant_max = 2**self.bit - 1 + else: + quant_max = 2**(self.bit - 1) - 1 + if self.is_symmetric_range: + quant_min = -2**(self.bit - 1) + 1 + else: + quant_min = -2**(self.bit - 1) + + # `dtype` will be same as BackenConfig's + naive_para = { + 'dtype': torch.quint8 if self.qdtype == 'quint8' else torch.qint8, + 'quant_min': quant_min, + 'quant_max': quant_max, + 'qscheme': self.torch_qscheme, + 'reduce_range': False + } + if self.is_per_channel: + naive_para['ch_axis'] = 0 + all_para = self.kwargs.copy() + all_para.update(naive_para) + return all_para + + def __str__(self): + """Print generated args for observers.""" + return f'dtype: {self.dtype} / bit: {self.bit} / is_symmetry: {self.is_symmetry} / \ + is_per_channel: {self.is_per_channel} \ + / extra_kwargs: {self.kwargs}' + + +class QConfigHandler(): + """Convert custom user-friendly qconfig format to torch's QConfig. + + Args: + qconfig (Dict | Config): custom user-friendly qconfig format, + including setting observers, fakequants and quantization schemes + for weights and activations. + Note: + whether quantization scheme is per-channel or not depends on + used observer, if observer support per-channel quantization, its name + should contain 'PerChannel'. + """ + + def __init__(self, qconfig: Union[Dict, Config]): + if not self.check_qconfig(qconfig): + raise ValueError('The format of qconfig is incorrect.') + else: + w_observer = MODELS.get(qconfig['w_observer']['type']) + a_observer = MODELS.get(qconfig['a_observer']['type']) + w_is_per_channel = False + a_is_per_channel = False + # import pdb;pdb.set_trace() + if 'PerChannel' in w_observer.__name__: + w_is_per_channel = True + if 'PerChannel' in a_observer.__name__: + a_is_per_channel = True + self.w_qscheme = QSchemeHandler( + is_per_channel=w_is_per_channel, **qconfig['w_qscheme']) + self.a_qscheme = QSchemeHandler( + is_per_channel=a_is_per_channel, **qconfig['a_qscheme']) + + w_fake_quant = MODELS.get(qconfig['w_fake_quant']['type']) + w_observer_kwargs = self.w_qscheme.to_observer_params() + a_fake_quant = MODELS.get(qconfig['a_fake_quant']['type']) + a_observer_kwargs = self.a_qscheme.to_observer_params() + + self.w_fake_quant = w_fake_quant.with_args( + observer=w_observer, **w_observer_kwargs) + self.a_fake_quant = a_fake_quant.with_args( + observer=a_observer, **a_observer_kwargs) + + @staticmethod + def check_qconfig(qconfig: Union[Dict, Config]): + """Check whether the passed qconfig's format meets requirement.""" + is_pass = True + for arg in RequiredArgs: + val = qconfig.get(arg, None) + if isinstance(val, dict) and arg in qconfig.keys(): + continue + else: + is_pass = False + break + return is_pass + + def convert(self): + """Generate torch's QConfig with built fake_quants.""" + torch_qconfig = QConfig( + weight=self.w_fake_quant, activation=self.a_fake_quant) + return torch_qconfig + + @staticmethod + def replace_fakequant(fake_quant_org: FakeQuantize, + qscheme_org: QSchemeHandler, + update_qparams: bool = True): + """Replace origin fakequants in model with the specified fakequant, + which is in favor of deploying the quantized model.""" + assert isinstance(qscheme_org, QSchemeHandler) + observer_kwargs = qscheme_org.to_observer_params() + if is_per_tensor(observer_kwargs['qscheme']): + observer = MODELS.get('MinMaxObserver') + retain_args = RetainArgsPerTensor + else: + observer = MODELS.get('PerChannelMinMaxObserver') + retain_args = RetainArgsPerChannel + pop_keys = [] + for k in observer_kwargs.keys(): + if k not in retain_args: + pop_keys.append(k) + for k in pop_keys: + observer_kwargs.pop(k) + fake_quant = MODELS.get('FakeQuantize') + fake_quant_wrapper = fake_quant.with_args( + observer=observer, **observer_kwargs) + if update_qparams: + device = fake_quant_org.scale.device + fake_quant_ins = fake_quant_wrapper().to(device) + fake_quant_ins.scale.copy_(fake_quant_org.scale) + fake_quant_ins.zero_point.copy_(fake_quant_org.zero_point) + obs = fake_quant_ins.activation_post_process + obs_org = fake_quant_org.activation_post_process + obs.min_val.resize_(obs_org.min_val.shape).copy_(obs_org.min_val) + obs.max_val.resize_(obs_org.max_val.shape).copy_(obs_org.max_val) + return fake_quant_ins + else: + return fake_quant_wrapper + + def fixed_w_fakequant(self): + """Make `self.w_fake_quant` fixed as the consistent fakequant.""" + self.w_fake_quant = self.replace_fakequant( + self.w_fake_quant(), self.w_qscheme, update_qparams=False) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/__init__.py new file mode 100755 index 000000000..af69cc96e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/__init__.py @@ -0,0 +1,7 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .candidate import Candidates +from .fix_subnet import convert_fix_subnet, export_fix_subnet, load_fix_subnet + +__all__ = [ + 'load_fix_subnet', 'export_fix_subnet', 'convert_fix_subnet', 'Candidates' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/candidate.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/candidate.py new file mode 100755 index 000000000..9f0ebc344 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/candidate.py @@ -0,0 +1,184 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from collections import UserList +from typing import Any, Dict, List, Optional, Union + + +class Candidates(UserList): + """The data structure of sampled candidate. The format is Union[Dict[str, + Dict], List[Dict[str, Dict]]]. + Examples: + >>> candidates = Candidates() + >>> subnet_1 = {'1': 'choice1', '2': 'choice2'} + >>> candidates.append(subnet_1) + >>> candidates + [{"{'1': 'choice1', '2': 'choice2'}": + {'score': 0.0, 'flops': 0.0, 'params': 0.0, 'latency': 0.0}}] + >>> candidates.set_resources(0, 49.9, 'flops') + >>> candidates.set_score(0, 100.) + >>> candidates + [{"{'1': 'choice1', '2': 'choice2'}": + {'score': 100.0, 'flops': 49.9, 'params': 0.0, 'latency': 0.0}}] + >>> subnet_2 = {'choice_3': 'layer_3', 'choice_4': 'layer_4'} + >>> candidates.append(subnet_2) + >>> candidates + [{"{'1': 'choice1', '2': 'choice2'}": + {'score': 100.0, 'flops': 49.9, 'params': 0.0, 'latency': 0.0}}, + {"{'choice_3': 'layer_3', 'choice_4':'layer_4'}": + {'score': 0.0, 'flops': 0.0, 'params': 0.0, 'latency': 0.0}}] + >>> candidates.subnets + [{'1': 'choice1', '2': 'choice2'}, + {'choice_3': 'layer_3', 'choice_4': 'layer_4'}] + >>> candidates.resources('flops') + [49.9, 0.0] + >>> candidates.scores + [100.0, 0.0] + """ + _format_return = Union[Dict[str, Dict], List[Dict[str, Dict]]] + _format_input = Union[Dict, List[Dict], Dict[str, Dict], List[Dict[str, + Dict]]] + _indicators = ('score', 'flops', 'params', 'latency') + + def __init__(self, initdata: Optional[_format_input] = None): + self.data = [] + if initdata is not None: + initdata = self._format(initdata) + if isinstance(initdata, list): + self.data = initdata + else: + self.data.append(initdata) + + @property + def scores(self) -> List[float]: + """The scores of candidates.""" + return [ + round(value.get('score', 0.), 2) for item in self.data + for _, value in item.items() + ] + + def resources(self, key_indicator: str = 'flops') -> List[float]: + """The resources of candidates.""" + assert key_indicator in ['flops', 'params', 'latency'] + return [ + value.get(key_indicator, 0.) for item in self.data + for _, value in item.items() + ] + + @property + def subnets(self) -> List[Dict]: + """The subnets of candidates.""" + import copy + assert len(self.data) > 0, ('Got empty candidates.') + if 'value_subnet' in self.data[0]: + subnets = [] + for data in self.data: + subnet = dict() + _data = copy.deepcopy(data) + for k1 in ['value_subnet', 'channel_subnet']: + for k2 in self._indicators: + _data[k1].pop(k2) + subnet[k1] = _data[k1] + subnets.append(subnet) + return subnets + else: + return [eval(key) for item in self.data for key, _ in item.items()] + + def _format(self, data: _format_input) -> _format_return: + """Transform [Dict, ...] to Union[Dict[str, Dict], List[Dict[str, + Dict]]]. + + Args: + data: Four types of input are supported: + 1. Dict: only include network information. + 2. List[Dict]: multiple candidates only include network + information. + 3. Dict[str, Dict]: network information and the corresponding + resources. + 4. List[Dict[str, Dict]]: multiple candidate information. + Returns: + Union[Dict[str, Dict], UserList[Dict[str, Dict]]]: + A dict or a list of dict that contains a pair of network + information and the corresponding Score | FLOPs | Params | + Latency results in each candidate. + Notes: + Score | FLOPs | Params | Latency: + 1. a candidate resources with a default value of -1 indicates + that it has not been estimated. + 2. a candidate resources with a default value of 0 indicates + that some indicators have been evaluated. + """ + + def _format_item( + cond: Union[Dict, Dict[str, Dict]]) -> Dict[str, Dict]: + """Transform Dict to Dict[str, Dict].""" + if isinstance(list(cond.values())[0], dict): + for value in list(cond.values()): + for key in list(self._indicators): + value.setdefault(key, 0.) + return cond + else: + return {str(cond): {}.fromkeys(self._indicators, -1)} + + if isinstance(data, UserList): + return [_format_item(i) for i in data.data] + + elif isinstance(data, list): + return [_format_item(i) for i in data] + + else: + return _format_item(data) + + def append(self, item: _format_input) -> None: + """Append operation.""" + item = self._format(item) + if isinstance(item, list): + self.data = self.data + item + else: + self.data.append(item) + + def insert(self, i: int, item: _format_input) -> None: + """Insert operation.""" + item = self._format(item) + self.data.insert(i, item) + + def extend(self, other: Any) -> None: + """Extend operation.""" + other = self._format(other) + if isinstance(other, list): + self.data.extend(other) + else: + self.data.extend([other]) + + def set_score(self, i: int, score: float) -> None: + """Set score to the specified subnet by index.""" + self.set_resource(i, score, 'score') + + def set_resource(self, + i: int, + resources: float, + key_indicator: str = 'flops') -> None: + """Set resources to the specified subnet by index.""" + assert key_indicator in ['score', 'flops', 'params', 'latency'] + for _, value in self.data[i].items(): + value[key_indicator] = resources + + def update_resources(self, resources: list, start: int = 0) -> None: + """Update resources to the specified candidate.""" + end = start + len(resources) + assert len( + self.data) >= end, 'Check the number of candidate resources.' + for i, item in enumerate(self.data[start:end]): + for _, value in item.items(): + value.update(resources[i]) + + def sort_by(self, + key_indicator: str = 'score', + reverse: bool = True) -> None: + """Sort by a specific indicator in descending order. + + Args: + key_indicator (str): sort all candidates by key_indicator. + Defaults to 'score'. + reverse (bool): sort all candidates in descending order. + """ + self.data.sort( + key=lambda x: list(x.values())[0][key_indicator], reverse=reverse) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/fix_subnet.py b/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/fix_subnet.py new file mode 100755 index 000000000..56b33be76 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/fix_subnet.py @@ -0,0 +1,218 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict, Optional, Tuple + +from mmengine import fileio +from torch import nn + +from mmrazor.registry import MODELS +from mmrazor.utils import FixMutable, ValidFixMutable +from mmrazor.utils.typing import DumpChosen + + +def _dynamic_to_static(model: nn.Module) -> None: + # Avoid circular import + from mmrazor.models.architectures.dynamic_ops import DynamicMixin + + def traverse_children(module: nn.Module) -> None: + for name, mutable in module.items(): + if isinstance(mutable, DynamicMixin): + module[name] = mutable.to_static_op() + if hasattr(mutable, '_modules'): + traverse_children(mutable._modules) + + if isinstance(model, DynamicMixin): + raise RuntimeError('Root model can not be dynamic op.') + + if hasattr(model, '_modules'): + traverse_children(model._modules) + + +def load_fix_subnet(model: nn.Module, + subnet_dict: ValidFixMutable, + load_subnet_mode: str = 'mutable', + prefix: str = '', + extra_prefix: str = '') -> None: + """Load fix subnet.""" + if prefix and extra_prefix: + raise RuntimeError('`prefix` and `extra_prefix` can not be set at the ' + f'same time, but got {prefix} vs {extra_prefix}') + if isinstance(subnet_dict, str): + subnet_dict = fileio.load(subnet_dict) + if not isinstance(subnet_dict, dict): + raise TypeError('subnet_dict should be a `str` or `dict`' + f'but got {type(subnet_dict)}') + + from mmrazor.models.architectures.dynamic_ops import DynamicMixin + if isinstance(model, DynamicMixin): + raise RuntimeError('Root model can not be dynamic op.') + + if load_subnet_mode == 'mutable': + _load_fix_subnet_by_mutable(model, subnet_dict, prefix, extra_prefix) + elif load_subnet_mode == 'mutator': + _load_fix_subnet_by_mutator(model, subnet_dict) + else: + raise ValueError(f'Invalid load_subnet_mode {load_subnet_mode}, ' + 'only mutable or mutator is supported.') + + # convert dynamic op to static op + _dynamic_to_static(model) + + +def _load_fix_subnet_by_mutable(model: nn.Module, + subnet_dict: Dict, + prefix: str = '', + extra_prefix: str = '') -> None: + # Avoid circular import + from mmrazor.models.mutables import DerivedMutable, MutableChannelContainer + from mmrazor.models.mutables.base_mutable import BaseMutable + + def load_fix_module(module): + """Load fix module.""" + if getattr(module, 'alias', None): + alias = module.alias + assert alias in subnet_dict, \ + f'The alias {alias} is not in fix_modules, ' \ + 'please check your `subnet_dict`.' + # {chosen=xx, meta=xx) + chosen = subnet_dict.get(alias, None) + else: + if prefix: + mutable_name = name.lstrip(prefix) + elif extra_prefix: + mutable_name = extra_prefix + name + else: + mutable_name = name + if mutable_name not in subnet_dict and not isinstance( + module, MutableChannelContainer): + raise RuntimeError( + f'The module name {mutable_name} is not in ' + 'subnet_dict, please check your `subnet_dict`.') + # {chosen=xx, meta=xx) + chosen = subnet_dict.get(mutable_name, None) + + if not isinstance(chosen, DumpChosen): + chosen = DumpChosen(**chosen) + if not module.is_fixed: + module.fix_chosen(chosen.chosen) + + for name, module in model.named_modules(): + # The format of `chosen`` is different for each type of mutable. + # In the corresponding mutable, it will check whether the `chosen` + # format is correct. + if isinstance(module, (MutableChannelContainer)): + continue + + if isinstance(module, BaseMutable): + if isinstance(module, DerivedMutable): + for source_mutable in module.source_mutables: + load_fix_module(source_mutable) + else: + load_fix_module(module) + + +def _load_fix_subnet_by_mutator(model: nn.Module, mutator_cfg: Dict) -> None: + if 'channel_unit_cfg' not in mutator_cfg: + raise ValueError('mutator_cfg must contain key channel_unit_cfg, ' + f'but got mutator_cfg:' + f'{mutator_cfg}') + mutator = MODELS.build(mutator_cfg) + mutator.parse_cfg['from_cfg'] = True + mutator.prepare_from_supernet(model) + + +def export_fix_subnet( + model: nn.Module, + export_subnet_mode: str = 'mutable', + slice_weight: bool = False, + export_channel: bool = False) -> Tuple[FixMutable, Optional[Dict]]: + """Export subnet that can be loaded by :func:`load_fix_subnet`. Include + subnet structure and subnet weight. + + Args: + model (nn.Module): The target model to export. + export_subnet_mode (bool): Subnet export method choice. + Export by `mutable.dump_chosen()` when set to 'mutable' (NAS) + Export by `mutator.config_template()` when set to 'mutator' (Prune) + slice_weight (bool): Export subnet weight. Default to False. + export_channel (bool): Whether to export the mutator's channel. + Often required when finetune is needed for the exported subnet. + Default to False. + + Return: + fix_subnet (ValidFixMutable): Exported subnet choice config. + static_model (Optional[Dict]): Exported static model state_dict. + Valid when `slice_weight`=True. + """ + fix_subnet = dict() + if export_subnet_mode == 'mutable': + fix_subnet = _export_subnet_by_mutable(model) + elif export_subnet_mode == 'mutator': + fix_subnet = _export_subnet_by_mutator(model, export_channel) + else: + raise ValueError(f'Invalid export_subnet_mode {export_subnet_mode}, ' + 'only mutable or mutator is supported.') + + if slice_weight: + # export subnet ckpt + from mmrazor.models.mutators import ChannelMutator + + copied_model = copy.deepcopy(model) + if hasattr(model, 'mutator') and \ + isinstance(model.mutator, ChannelMutator): + _dynamic_to_static(copied_model) + else: + load_fix_subnet(copied_model, fix_subnet) + + if next(copied_model.parameters()).is_cuda: + copied_model.cuda() + return fix_subnet, copied_model + else: + return fix_subnet, None + + +def _export_subnet_by_mutable(model: nn.Module) -> Dict: + + # Avoid circular import + from mmrazor.models.mutables import DerivedMutable, MutableChannelContainer + from mmrazor.models.mutables.base_mutable import BaseMutable + + def module_dump_chosen(module, fix_subnet): + if module.alias: + fix_subnet[module.alias] = module.dump_chosen() + else: + fix_subnet[name] = module.dump_chosen() + + fix_subnet: Dict[str, DumpChosen] = dict() + for name, module in model.named_modules(): + if isinstance(module, BaseMutable): + if isinstance(module, MutableChannelContainer): + continue + elif isinstance(module, DerivedMutable): + for source_mutable in module.source_mutables: + module_dump_chosen(source_mutable, fix_subnet) + else: + module_dump_chosen(module, fix_subnet) + return fix_subnet + + +def _export_subnet_by_mutator(model: nn.Module, export_channel: bool) -> Dict: + if not hasattr(model, 'mutator'): + raise ValueError('model should contain `mutator` attribute, but got ' + f'{type(model)} model') + fix_subnet = model.mutator.config_template( + with_channels=export_channel, with_unit_init_args=True) + + return fix_subnet + + +def convert_fix_subnet(fix_subnet: Dict[str, DumpChosen]): + """Convert the fixed subnet to avoid python typing error.""" + from mmrazor.utils.typing import DumpChosen + + converted_fix_subnet = dict() + for k, v in fix_subnet.items(): + assert isinstance(v, DumpChosen) + converted_fix_subnet[k] = dict(chosen=v.chosen) + + return converted_fix_subnet diff --git a/cv/distiller/CWD/mmrazor/mmrazor/testing/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/testing/__init__.py new file mode 100755 index 000000000..54dfd30ed --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/testing/__init__.py @@ -0,0 +1,3 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from ._fast_stop_training_hook import FastStopTrainingHook # noqa: F401,F403 +from ._fx_models import * # noqa: F401, F403 diff --git a/cv/distiller/CWD/mmrazor/mmrazor/testing/_fast_stop_training_hook.py b/cv/distiller/CWD/mmrazor/mmrazor/testing/_fast_stop_training_hook.py new file mode 100755 index 000000000..9d029b9b8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/testing/_fast_stop_training_hook.py @@ -0,0 +1,27 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmengine.hooks import Hook + +from mmrazor.registry import HOOKS + + +@HOOKS.register_module() +class FastStopTrainingHook(Hook): + """Set runner's epoch information to the model.""" + + def __init__(self, by_epoch, save_ckpt=False, stop_iter_or_epoch=5): + self.by_epoch = by_epoch + self.save_ckpt = save_ckpt + self.stop_iter_or_epoch = stop_iter_or_epoch + + def after_train_iter(self, runner, batch_idx: int, data_batch: None, + outputs: None) -> None: + if self.save_ckpt and self.by_epoch: + # If it is epoch-based and want to save weights, + # we must run at least 1 epoch. + return + if runner.iter >= self.stop_iter_or_epoch: + raise RuntimeError('quick exit') + + def after_train_epoch(self, runner) -> None: + if runner.epoch >= self.stop_iter_or_epoch - 1: + raise RuntimeError('quick exit') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/testing/_fx_models.py b/cv/distiller/CWD/mmrazor/mmrazor/testing/_fx_models.py new file mode 100755 index 000000000..6bf42e16a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/testing/_fx_models.py @@ -0,0 +1,44 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional, Tuple, Union + +import torch.nn as nn +from mmcv.cnn import ConvModule + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class ConvBNReLU(nn.Module): + + def __init__( + self, + in_channel: int, + out_channel: int, + kernel_size: Union[int, Tuple[int, int]] = 1, + stride: Union[int, Tuple[int, int]] = 1, + padding: Union[int, Tuple[int, int]] = 0, + dilation: Union[int, Tuple[int, int]] = 1, + groups: int = 1, + bias: Union[str, bool] = 'auto', + conv_cfg: Optional[Dict] = None, + norm_cfg: Optional[Dict] = None, + act_cfg: Dict = dict(type='ReLU'), + inplace: bool = True, + with_spectral_norm: bool = False, + padding_mode: str = 'zeros', + order: tuple = ('conv', 'norm', 'act'), + init_cfg: Optional[Dict] = None, + ) -> None: + super().__init__() + self.conv_module = ConvModule(in_channel, out_channel, kernel_size, + stride, padding, dilation, groups, bias, + conv_cfg, norm_cfg, act_cfg, inplace, + with_spectral_norm, padding_mode, order) + self.toy_attr1 = 1 + self.toy_attr2 = 2 + + def forward(self, x): + x = self.conv_module.conv(x) + x = self.conv_module.norm(x) + x = self.conv_module.activate(x) + return x diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/utils/__init__.py new file mode 100755 index 000000000..7d23ca632 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/utils/__init__.py @@ -0,0 +1,18 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .index_dict import IndexDict +from .log_tools import get_level, print_log +from .misc import find_latest_checkpoint +from .placeholder import get_package_placeholder, get_placeholder +from .runtime_info import RuntimeInfo +from .setup_env import register_all_modules, setup_multi_processes +from .typing import (FixMutable, MultiMutatorsRandomSubnet, + SingleMutatorRandomSubnet, SupportRandomSubnet, + ValidFixMutable) + +__all__ = [ + 'find_latest_checkpoint', 'setup_multi_processes', 'register_all_modules', + 'FixMutable', 'ValidFixMutable', 'SingleMutatorRandomSubnet', + 'MultiMutatorsRandomSubnet', 'SupportRandomSubnet', 'get_placeholder', + 'IndexDict', 'get_level', 'print_log', 'RuntimeInfo', + 'get_package_placeholder' +] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/index_dict.py b/cv/distiller/CWD/mmrazor/mmrazor/utils/index_dict.py new file mode 100755 index 000000000..a053024ac --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/utils/index_dict.py @@ -0,0 +1,61 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from collections import OrderedDict +from typing import Tuple, TypeVar + +VT = TypeVar('VT') # Value type + + +class IndexDict(OrderedDict): + """IndexDict inherits from OrderedDict[Tuple[int, int], VT]. Each IndexDict + object is a OrderDict object which using index(Tuple[int,int]) as key and + Any as value. + + The key type is Tuple[a: int,b: int]. It indicates a range in + the [a,b). + + IndexDict has three features: + 1. ensure a key always is a index(Tuple[int,int]). + 1. ensure the the indexes are sorted by ascending order. + 2. ensure there is no overlap among indexes. + """ + + def __setitem__(self, __k: Tuple[int, int], __v): + """set item.""" + start, end = __k + assert start < end + self._assert_no_over_lap(start, end) + super().__setitem__(__k, __v) + self._sort() + + def _sort(self): + """sort the dict accorrding to index.""" + items = sorted(self.items()) + self.clear() + for k, v in items: + super().__setitem__(k, v) + + def _assert_no_over_lap(self, start, end): + """Assert the index [start,end) has no over lav with existed + indexes.""" + assert (start, end) not in self, 'index overlap' + + def __contains__(self, __o) -> bool: + """Bool: if the index has any overlap with existed indexes""" + if super().__contains__(__o): + return True + else: + self._assert_is_index(__o) + start, end = __o + existed = False + for s, e in self.keys(): + existed = (s <= start < e or s < end < e or + (s < start and end < e)) or existed + + return existed + + def _assert_is_index(self, index): + """Assert the index is an instance of Tuple[int,int]""" + assert isinstance(index, Tuple) \ + and len(index) == 2 \ + and isinstance(index[0], int) \ + and isinstance(index[1], int) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/log_tools.py b/cv/distiller/CWD/mmrazor/mmrazor/utils/log_tools.py new file mode 100755 index 000000000..787dc1927 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/utils/log_tools.py @@ -0,0 +1,29 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import logging + +from mmengine import MMLogger +from mmengine import print_log as engine_print_log + + +def get_level(level='info'): + if isinstance(level, str): + level = level.upper() + assert level in logging._nameToLevel + level = logging._nameToLevel[level] + elif isinstance(level, int): + pass + else: + raise NotImplementedError() + return level + + +def print_log(msg, logger='current', level='info'): + engine_print_log(msg, logger, get_level(level)) + + +def set_log_level(level='debug'): + level = get_level(level) + + logger = MMLogger.get_current_instance() + logger.handlers[0].setLevel(level) + logger.setLevel(level) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/misc.py b/cv/distiller/CWD/mmrazor/mmrazor/utils/misc.py new file mode 100755 index 000000000..1c12b21ef --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/utils/misc.py @@ -0,0 +1,38 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import glob +import os.path as osp +import warnings + + +def find_latest_checkpoint(path, suffix='pth'): + """Find the latest checkpoint from the working directory. + + Args: + path(str): The path to find checkpoints. + suffix(str): File extension. Defaults to pth. + + Returns: + latest_path(str | None): File path of the latest checkpoint. + + References: + .. [1] https://github.com/microsoft/SoftTeacher + /blob/main/ssod/utils/patch.py + """ + if not osp.exists(path): + warnings.warn('The path of checkpoints does not exist.') + return None + if osp.exists(osp.join(path, f'latest.{suffix}')): + return osp.join(path, f'latest.{suffix}') + + checkpoints = glob.glob(osp.join(path, f'*.{suffix}')) + if len(checkpoints) == 0: + warnings.warn('There are no checkpoints in the path.') + return None + latest = -1 + latest_path = None + for checkpoint in checkpoints: + count = int(osp.basename(checkpoint).split('_')[-1].split('.')[0]) + if count > latest: + latest = count + latest_path = checkpoint + return latest_path diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/placeholder.py b/cv/distiller/CWD/mmrazor/mmrazor/utils/placeholder.py new file mode 100755 index 000000000..9af35f7a4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/utils/placeholder.py @@ -0,0 +1,57 @@ +# Copyright (c) OpenMMLab. All rights reserved. +def get_placeholder(string: str) -> object: + """Get placeholder instance which can avoid raising errors when down-stream + dependency is not installed properly. + + Args: + string (str): the dependency's name, i.e. `mmcls` + + Raises: + ImportError: raise it when the dependency is not installed properly. + + Returns: + object: PlaceHolder instance. + """ + + def raise_import_error(package_name): + raise ImportError( + f'`{package_name}` is not installed properly, plz check.') + + class PlaceHolder(): + + def __init__(self) -> None: + raise_import_error(string) + + return PlaceHolder + + +def get_package_placeholder(string: str) -> object: + """Get placeholder instance which can avoid raising errors when down-stream + dependency is not installed properly. + + Args: + string (str): the dependency's name, i.e. `mmcls` + + Raises: + ImportError: raise it when the dependency is not installed properly. + + Returns: + object: PlaceHolder instance. + """ + + def raise_import_error(package_name): + raise ImportError( + f'`{package_name}` is not installed properly, plz check.') + + class PlaceHolderMetaclass(type): + """Used to support usage of PlaceHolder.xxxx.""" + + def __getattr__(self, name): + raise_import_error(string) + + class PlaceHolder(metaclass=PlaceHolderMetaclass): + + def __init__(self) -> None: + raise_import_error(string) + + return PlaceHolder diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/runtime_info.py b/cv/distiller/CWD/mmrazor/mmrazor/utils/runtime_info.py new file mode 100755 index 000000000..f117c2d06 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/utils/runtime_info.py @@ -0,0 +1,58 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import math + +from mmengine import Config, MessageHub + + +class RuntimeInfo(): + """A tools to get runtime info in MessageHub.""" + + @classmethod + def info(cls): + hub = MessageHub.get_current_instance() + return hub.runtime_info + + @classmethod + def get_info(cls, key): + info = cls.info() + if key in info: + return info[key] + else: + raise KeyError(key) + + @classmethod + def epoch(cls): + return cls.get_info('epoch') + + @classmethod + def max_epochs(cls): + return cls.get_info('max_epochs') + + @classmethod + def iter(cls): + return cls.get_info('iter') + + @classmethod + def max_iters(cls): + return cls.get_info('max_iters') + + @classmethod + def iter_by_epoch(cls): + iter_per_epoch = math.ceil(cls.max_iters() / cls.max_epochs()) + return cls.iter() % iter_per_epoch + + @classmethod + def iter_pre_epoch(cls): + iter_per_epoch = math.ceil(cls.max_iters() / cls.max_epochs()) + return iter_per_epoch + + @classmethod + def config(cls): + cfg: str = cls.get_info('cfg') + config = Config.fromstring(cfg, '.py') + return config + + @classmethod + def work_dir(cls): + config = cls.config() + return config['work_dir'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/setup_env.py b/cv/distiller/CWD/mmrazor/mmrazor/utils/setup_env.py new file mode 100755 index 000000000..a091933aa --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/utils/setup_env.py @@ -0,0 +1,85 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import datetime +import os +import platform +import warnings + +import cv2 +import torch.multiprocessing as mp +from mmengine import DefaultScope + + +def setup_multi_processes(cfg): + """Setup multi-processing environment variables.""" + # set multi-process start method as `fork` to speed up the training + if platform.system() != 'Windows': + mp_start_method = cfg.get('mp_start_method', 'fork') + current_method = mp.get_start_method(allow_none=True) + if current_method is not None and current_method != mp_start_method: + warnings.warn( + f'Multi-processing start method `{mp_start_method}` is ' + f'different from the previous setting `{current_method}`.' + f'It will be force set to `{mp_start_method}`. You can change ' + f'this behavior by changing `mp_start_method` in your config.') + mp.set_start_method(mp_start_method, force=True) + + # disable opencv multithreading to avoid system being overloaded + opencv_num_threads = cfg.get('opencv_num_threads', 0) + cv2.setNumThreads(opencv_num_threads) + + # setup OMP threads + # This code is referred from https://github.com/pytorch/pytorch/blob/master/torch/distributed/run.py # noqa + if 'OMP_NUM_THREADS' not in os.environ and cfg.data.workers_per_gpu > 1: + omp_num_threads = 1 + warnings.warn( + f'Setting OMP_NUM_THREADS environment variable for each process ' + f'to be {omp_num_threads} in default, to avoid your system being ' + f'overloaded, please further tune the variable for optimal ' + f'performance in your application as needed.') + os.environ['OMP_NUM_THREADS'] = str(omp_num_threads) + + # setup MKL threads + if 'MKL_NUM_THREADS' not in os.environ and cfg.data.workers_per_gpu > 1: + mkl_num_threads = 1 + warnings.warn( + f'Setting MKL_NUM_THREADS environment variable for each process ' + f'to be {mkl_num_threads} in default, to avoid your system being ' + f'overloaded, please further tune the variable for optimal ' + f'performance in your application as needed.') + os.environ['MKL_NUM_THREADS'] = str(mkl_num_threads) + + +def register_all_modules(init_default_scope: bool = True) -> None: + """Register all modules in mmrazor into the registries. + + Args: + init_default_scope (bool): Whether initialize the mmrazor default scope. + When `init_default_scope=True`, the global default scope will be + set to `mmrazor`, and all registries will build modules from mmrazor's + registry node. To understand more about the registry, please refer + to https://github.com/open-mmlab/mmengine/blob/main/docs/en/tutorials/registry.md + Defaults to True. + """ # noqa + + import mmrazor.datasets # noqa: F401,F403 + import mmrazor.engine # noqa: F401,F403 + import mmrazor.implementations # noqa: F401,F403 + import mmrazor.models # noqa: F401,F403 + import mmrazor.structures # noqa: F401,F403 + if init_default_scope: + never_created = DefaultScope.get_current_instance() is None \ + or not DefaultScope.check_instance_created('mmrazor') + if never_created: + DefaultScope.get_instance('mmrazor', scope_name='mmrazor') + return + current_scope = DefaultScope.get_current_instance() + if current_scope.scope_name != 'mmrazor': # type: ignore + warnings.warn( + 'The current default scope ' # type: ignore + f'"{current_scope.scope_name}" is not ' + '"mmrazor", `register_all_modules` will force the current' + 'default scope to be "mmrazor". If this is not expected, ' + 'please set `init_default_scope=False`.') + # avoid name conflict + new_instance_name = f'mmrazor-{datetime.datetime.now()}' + DefaultScope.get_instance(new_instance_name, scope_name='mmrazor') diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/typing.py b/cv/distiller/CWD/mmrazor/mmrazor/utils/typing.py new file mode 100755 index 000000000..0d1126f2a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/utils/typing.py @@ -0,0 +1,37 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from pathlib import Path +from typing import Any, Dict, List, NamedTuple, Optional, Union + +FixMutable = Dict[str, Any] +ValidFixMutable = Union[str, Path, FixMutable] + +# RANDOM_SUBNET means the subnet sampled by one or more mutators. Usually used +# for supernet training or searching. + +# `SingleMutatorRandomSubnet`` sampled by a mutator, its format is a dict, the +# keys of the dict are the group_id in the mutator‘s search groups, and the +# values ​​of the dict are the choices corresponding to all mutables in each +# search group. + +# One search group may contains N mutables. More details of search groups see +# docs for :class:`mmrazor.models.mutators.OneShotModuleMutator`. +SingleMutatorRandomSubnet = Dict[int, Any] + +# For some more complex algorithms, multiple mutators may be used, and the +# corresponding format will be a list +MultiMutatorsRandomSubnet = List[SingleMutatorRandomSubnet] + +SupportRandomSubnet = Union[SingleMutatorRandomSubnet, + MultiMutatorsRandomSubnet] + +Chosen = Union[str, float, List[str]] +ChosenMeta = Optional[Dict[str, Any]] + + +class DumpChosen(NamedTuple): + chosen: Chosen + meta: ChosenMeta = None + + +# DumpChosen = NamedTuple('DumpChosen', [('chosen', Chosen), +# ('meta', ChosenMeta)]) diff --git a/cv/distiller/CWD/mmrazor/mmrazor/version.py b/cv/distiller/CWD/mmrazor/mmrazor/version.py new file mode 100755 index 000000000..6a60b40f3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/version.py @@ -0,0 +1,28 @@ +# Copyright (c) OpenMMLab. All rights reserved + +__version__ = '1.0.0' + + +def parse_version_info(version_str): + """Parse a version string into a tuple. + + Args: + version_str (str): The version string. + Returns: + tuple[int | str]: The version info, e.g., "1.3.0" is parsed into + (1, 3, 0), and "2.0.0rc1" is parsed into (2, 0, 0, 'rc1'). + """ + version_info = [] + for x in version_str.split('.'): + if x.isdigit(): + version_info.append(int(x)) + elif x.find('rc') != -1: + patch_version = x.split('rc') + version_info.append(int(patch_version[0])) + version_info.append(f'rc{patch_version[1]}') + return tuple(version_info) + + +version_info = parse_version_info(__version__) + +__all__ = ['__version__', 'version_info', 'parse_version_info'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/visualization/__init__.py b/cv/distiller/CWD/mmrazor/mmrazor/visualization/__init__.py new file mode 100755 index 000000000..993202428 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/visualization/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .local_visualizer import modify + +__all__ = ['modify'] diff --git a/cv/distiller/CWD/mmrazor/mmrazor/visualization/local_visualizer.py b/cv/distiller/CWD/mmrazor/mmrazor/visualization/local_visualizer.py new file mode 100755 index 000000000..5834e8eca --- /dev/null +++ b/cv/distiller/CWD/mmrazor/mmrazor/visualization/local_visualizer.py @@ -0,0 +1,115 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import warnings +from typing import Optional, Tuple + +import cv2 +import matplotlib.pyplot as plt +import numpy as np +import torch +import torch.nn.functional as F +from mmengine.dist import master_only +from mmengine.visualization.utils import (convert_overlay_heatmap, + img_from_canvas) + + +@master_only +def modify(featmap: torch.Tensor, + overlaid_image: Optional[np.ndarray] = None, + channel_reduction: Optional[str] = 'pixel_wise_max', + topk: int = 20, + arrangement: Tuple[int, int] = (4, 5), + resize_shape: Optional[tuple] = None, + alpha: float = 0.5): + assert isinstance(featmap, + torch.Tensor), (f'`featmap` should be torch.Tensor,' + f' but got {type(featmap)}') + assert featmap.ndim == 3, f'Input dimension must be 3, ' \ + f'but got {featmap.ndim}' + featmap = featmap.detach().cpu() + + if overlaid_image is not None: + if overlaid_image.ndim == 2: + overlaid_image = cv2.cvtColor(overlaid_image, cv2.COLOR_GRAY2RGB) + + if overlaid_image.shape[:2] != featmap.shape[1:]: + warnings.warn(f'Since the spatial dimensions of ' + f'overlaid_image: {overlaid_image.shape[:2]} and ' + f'featmap: {featmap.shape[1:]} are not same, ' + f'the feature map will be interpolated. ' + f'This may cause mismatch problems ï¼') + if resize_shape is None: + overlaid_image_h, overlaid_image_w = overlaid_image.shape[:2] + feat_h, feat_w = featmap.shape[-2:] + if feat_h / feat_w > overlaid_image_h / overlaid_image_w: + feat_h = round(feat_w * overlaid_image_h / + overlaid_image_w) + else: + feat_w = round(feat_h * overlaid_image_w / + overlaid_image_h) + featmap = featmap[..., :feat_h, :feat_w] + featmap = F.interpolate( + featmap[None], overlaid_image.shape[:2], + mode='bilinear')[0] + + if resize_shape is not None: + featmap = F.interpolate( + featmap[None], resize_shape, mode='bilinear', + align_corners=False)[0] + if overlaid_image is not None: + overlaid_image = cv2.resize(overlaid_image, resize_shape[::-1]) + + if channel_reduction is not None: + assert channel_reduction in [ + 'squeeze_mean', 'select_max', 'pixel_wise_max'], \ + f'Mode only support "squeeze_mean", "select_max", ' \ + f'"pixel_wise_max", but got {channel_reduction}' + if channel_reduction == 'select_max': + sum_channel_featmap = torch.sum(featmap, dim=(1, 2)) + _, indices = torch.topk(sum_channel_featmap, 1) + feat_map = featmap[indices] + elif channel_reduction == 'squeeze_mean': + feat_map = torch.mean(featmap, dim=0) + else: + feat_map = torch.max(featmap, dim=0)[0] + return convert_overlay_heatmap(feat_map, overlaid_image, alpha) + elif topk <= 0: + featmap_channel = featmap.shape[0] + assert featmap_channel in [ + 1, 3 + ], ('The input tensor channel dimension must be 1 or 3 ' + 'when topk is less than 1, but the channel ' + f'dimension you input is {featmap_channel}, you can use the' + ' channel_reduction parameter or set topk greater than ' + '0 to solve the error') + return convert_overlay_heatmap(featmap, overlaid_image, alpha) + else: + row, col = arrangement + channel, height, width = featmap.shape + assert row * col >= topk, 'The product of row and col in ' \ + 'the `arrangement` is less than ' \ + 'topk, please set the ' \ + '`arrangement` correctly' + + # Extract the feature map of topk + topk = min(channel, topk) + sum_channel_featmap = torch.sum(featmap, dim=(1, 2)) + _, indices = torch.topk(sum_channel_featmap, topk) + topk_featmap = featmap[indices] + + fig = plt.figure(frameon=False) + # Set the window layout + fig.subplots_adjust( + left=0, right=1, bottom=0, top=1, wspace=0, hspace=0) + dpi = fig.get_dpi() + fig.set_size_inches((width * col + 1e-2) / dpi, + (height * row + 1e-2) / dpi) + for i in range(topk): + axes = fig.add_subplot(row, col, i + 1) + axes.axis('off') + axes.text(2, 15, f'channel: {indices[i]}', fontsize=10) + axes.imshow( + convert_overlay_heatmap(topk_featmap[i], overlaid_image, + alpha)) + image = img_from_canvas(fig.canvas) + plt.close(fig) + return image diff --git a/cv/distiller/CWD/mmrazor/model-index.yml b/cv/distiller/CWD/mmrazor/model-index.yml new file mode 100755 index 000000000..6204bceae --- /dev/null +++ b/cv/distiller/CWD/mmrazor/model-index.yml @@ -0,0 +1,31 @@ +Import: + - configs/distill/mmseg/cwd/metafile.yml + - configs/distill/mmdet/cwd/metafile.yml + - configs/distill/mmcls/wsld/metafile.yml + - configs/distill/mmcls/rkd/metafile.yml + - configs/distill/mmcls/abloss/metafile.yml + - configs/distill/mmcls/byot/metafile.yml + - configs/distill/mmcls/dafl/metafile.yml + - configs/distill/mmcls/dfad/metafile.yml + - configs/distill/mmcls/dkd/metafile.yml + - configs/distill/mmcls/fitnets/metafile.yml + - configs/distill/mmcls/kd/metafile.yml + - configs/distill/mmcls/zskt/metafile.yml + - configs/distill/mmdet/fbkd/metafile.yml + - configs/distill/mmcls/factor_transfer/metafile.yml + - configs/distill/mmcls/ofd/metafile.yml + - configs/nas/mmcls/spos/metafile.yml + - configs/nas/mmcls/autoslim/metafile.yml + - configs/nas/mmcls/darts/metafile.yml + - configs/nas/mmdet/detnas/metafile.yml + - configs/distill/mmdet/pkd/metafile.yml + - configs/distill/mmdet3d/pkd/metafile.yml + - configs/distill/mmcls/deit/metafile.yml + - configs/pruning/mmcls/group_fisher/mobilenet/metafile.yml + - configs/pruning/mmcls/group_fisher/resnet50/metafile.yml + - configs/pruning/mmdet/group_fisher/retinanet/metafile.yml + - configs/pruning/mmcls/l1-norm/metafile.yml + # - configs/pruning/mmcls/dmcp/metafile.yml + - configs/quantization/ptq/base/metafile.yml + - configs/quantization/qat/base/metafile.yml + - configs/quantization/qat/lsq/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/requirements.txt b/cv/distiller/CWD/mmrazor/requirements.txt new file mode 100755 index 000000000..6da5adea7 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/requirements.txt @@ -0,0 +1,3 @@ +-r requirements/optional.txt +-r requirements/runtime.txt +-r requirements/tests.txt diff --git a/cv/distiller/CWD/mmrazor/requirements/docs.txt b/cv/distiller/CWD/mmrazor/requirements/docs.txt new file mode 100755 index 000000000..6934d41bd --- /dev/null +++ b/cv/distiller/CWD/mmrazor/requirements/docs.txt @@ -0,0 +1,7 @@ +docutils==0.16.0 +m2r +myst-parser +git+https://github.com/open-mmlab/pytorch_sphinx_theme.git#egg=pytorch_sphinx_theme +sphinx==4.0.2 +sphinx-copybutton +sphinx_markdown_tables diff --git a/cv/distiller/CWD/mmrazor/requirements/mminstall.txt b/cv/distiller/CWD/mmrazor/requirements/mminstall.txt new file mode 100755 index 000000000..e9a81c435 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/requirements/mminstall.txt @@ -0,0 +1,2 @@ +mmcv>=2.0.0rc1 +mmengine>=0.1.0,<1.0.0 diff --git a/cv/distiller/CWD/mmrazor/requirements/optional.txt b/cv/distiller/CWD/mmrazor/requirements/optional.txt new file mode 100755 index 000000000..bb7173848 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/requirements/optional.txt @@ -0,0 +1,4 @@ +pydacefit +pySOT==0.2.3 +scipy +timm diff --git a/cv/distiller/CWD/mmrazor/requirements/readthedocs.txt b/cv/distiller/CWD/mmrazor/requirements/readthedocs.txt new file mode 100755 index 000000000..d1e7e86f5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/requirements/readthedocs.txt @@ -0,0 +1,4 @@ +mmcv>=1.3.8 +ordered_set +torch +torchvision diff --git a/cv/distiller/CWD/mmrazor/requirements/runtime.txt b/cv/distiller/CWD/mmrazor/requirements/runtime.txt new file mode 100755 index 000000000..67e2c66bf --- /dev/null +++ b/cv/distiller/CWD/mmrazor/requirements/runtime.txt @@ -0,0 +1,2 @@ +ordered_set +typing_extensions;python_version<"3.8" diff --git a/cv/distiller/CWD/mmrazor/requirements/tests.txt b/cv/distiller/CWD/mmrazor/requirements/tests.txt new file mode 100755 index 000000000..5980dc303 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/requirements/tests.txt @@ -0,0 +1,11 @@ +coverage +flake8 +interrogate +isort==4.3.21 +nbconvert +nbformat +numpy < 1.24.0 # A temporary solution for tests with mmdet. +onnx +pytest +xdoctest >= 0.10.0 +yapf diff --git a/cv/distiller/CWD/mmrazor/resources/design_and_implement.png b/cv/distiller/CWD/mmrazor/resources/design_and_implement.png new file mode 100755 index 0000000000000000000000000000000000000000..547559d4f33c5adfa4aea23bcc3ab3175abb9f13 GIT binary patch literal 126764 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%0DEgPndjo5*y87b?CrWt&A(;JgU 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�AppSOx;PB;cD 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 f?*Suv`2haEtjbZM^pnL#5i{l^gKY0@I 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�z}kBy(lpECAp?2$3?2Ce?C@=QTLjJV^{=f7xK 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 `>)#!#P|5Ci-PrOOx&3?kH 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

    BleOu!O-<4iCWZ(G;i3}JnJvDT7{oZRkt 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

    1*>=a5&H={)y-VSw4<4g%(qQgPf)0Dvi<^JD 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ֽUZ#?zv6#s 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

    m}*-{!hMw~oRHq*$GKAN8`xqhQKVVf+Gn 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 0.', + default=[4, 5]) + parser.add_argument( + '--resize-shape', + nargs='+', + type=int, + help='the shape to scale the feature map', + default=None) + parser.add_argument( + '--alpha', help='the transparency of featmap', default=0.5) + + parser.add_argument('--local_rank', type=int, default=0) + + args = parser.parse_args() + if 'LOCAL_RANK' not in os.environ: + os.environ['LOCAL_RANK'] = str(args.local_rank) + + return args + + +def norm(feat): + N, C, H, W = feat.shape + feat = feat.permute(1, 0, 2, 3).reshape(C, -1) + mean = feat.mean(dim=-1, keepdim=True) + std = feat.std(dim=-1, keepdim=True) + centered = (feat - mean) / (std + 1e-6) + centered = centered.reshape(C, N, H, W).permute(1, 0, 2, 3) + return centered + + +def main(args): + register_all_modules(False) + mod = import_modules_from_strings(f'{args.repo}.utils') + mod.register_all_modules() + + apis = import_modules_from_strings(f'{args.repo}.apis') + inference_model, init_model = None, None + for attr_name in dir(apis): + if 'inference_' in attr_name: + inference_model = getattr(apis, attr_name) + if 'init_' in attr_name: + init_model = getattr(apis, attr_name) + assert inference_model and init_model + + model1 = init_model(args.config1, args.checkpoint1, device=args.device) + # init visualizer + visualizer = VISUALIZERS.build(model1.cfg.visualizer) + visualizer.draw_featmap = modify + + model2 = init_model(args.config2, args.checkpoint2, device=args.device) + + visualization_cfg = Config.fromfile(args.vis_config) + recorder_cfg1 = visualization_cfg.recorders1 + mappings1 = visualization_cfg.mappings1 + recorder_cfg2 = visualization_cfg.recorders2 + mappings2 = visualization_cfg.mappings2 + + recorder_manager1 = RecorderManager(recorder_cfg1) + recorder_manager1.initialize(model1) + + recorder_manager2 = RecorderManager(recorder_cfg2) + recorder_manager2.initialize(model2) + + with recorder_manager1: + # test a single image + _ = inference_model(model1, args.img) + + with recorder_manager2: + # test a single image + _ = inference_model(model2, args.img) + + overlaid_image = mmcv.imread( + args.img, channel_order='rgb') if args.overlaid else None + + for name1, name2 in zip(mappings1.keys(), mappings2.keys()): + record1 = mappings1[name1] + recorder1 = recorder_manager1.get_recorder(record1.recorder) + record_idx = getattr(record1, 'record_idx', 0) + data_idx = getattr(record1, 'data_idx') + feats1 = recorder1.get_record_data(record_idx, data_idx) + if isinstance(feats1, torch.Tensor): + feats1 = (feats1, ) + + record2 = mappings2[name2] + recorder2 = recorder_manager2.get_recorder(record2.recorder) + record_idx = getattr(record2, 'record_idx', 0) + data_idx = getattr(record2, 'data_idx') + feats2 = recorder2.get_record_data(record_idx, data_idx) + if isinstance(feats2, torch.Tensor): + feats2 = (feats2, ) + + for i, (feat1, feat2) in enumerate(zip(feats1, feats2)): + diff = torch.abs(feat1 - feat2) + if args.use_norm: + diff = norm(diff) + drawn_img = visualizer.draw_featmap( + diff[0], + overlaid_image, + args.channel_reduction, + topk=args.topk, + arrangement=tuple(args.arrangement), + resize_shape=tuple(args.resize_shape) + if args.resize_shape else None, + alpha=args.alpha) + visualizer.add_datasample( + f'model1_{name1}_model2_{name2}_{i}', + drawn_img, + show=args.out_file is None, + wait_time=0.1, + out_file=args.out_file) + + +if __name__ == '__main__': + args = parse_args() + main(args) diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/feature_visualization.py b/cv/distiller/CWD/mmrazor/tools/visualizations/feature_visualization.py new file mode 100755 index 000000000..617f9d016 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/visualizations/feature_visualization.py @@ -0,0 +1,155 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import os + +import mmcv +import torch +from mmengine.config import Config, DictAction +from mmengine.registry import VISUALIZERS +from mmengine.utils import import_modules_from_strings + +from mmrazor.models.task_modules import RecorderManager +from mmrazor.utils import register_all_modules +from mmrazor.visualization.local_visualizer import modify + + +def parse_args(): + parser = argparse.ArgumentParser(description='Feature map visualization') + parser.add_argument('img', help='Image file') + parser.add_argument('config', help='train config file path') + parser.add_argument('vis_config', help='visualization config file path') + parser.add_argument('checkpoint', help='Checkpoint file') + parser.add_argument('--out-file', default=None, help='Path to output file') + parser.add_argument( + '--device', default='cpu', help='Device used for inference') + parser.add_argument('--repo', help='the corresponding repo name') + parser.add_argument( + '--use-norm', + action='store_true', + help='normalize the featmap before visualization') + parser.add_argument( + '--overlaid', action='store_true', help='overlaid image') + parser.add_argument( + '--channel-reduction', + help='Reduce multiple channels to a single channel. The optional value' + ' is \'squeeze_mean\', \'select_max\' or \'pixel_wise_max\'.', + default=None) + parser.add_argument( + '--topk', + type=int, + help='If channel_reduction is not None and topk > 0, it will select ' + 'topk channel to show by the sum of each channel. If topk <= 0, ' + 'tensor_chw is assert to be one or three.', + default=20) + parser.add_argument( + '--arrangement', + nargs='+', + type=int, + help='the arrangement of featmap when channel_reduction is not None ' + 'and topk > 0.', + default=[4, 5]) + parser.add_argument( + '--resize-shape', + nargs='+', + type=int, + help='the shape to scale the feature map', + default=None) + parser.add_argument( + '--alpha', help='the transparency of featmap', default=0.5) + parser.add_argument( + '--cfg-options', + nargs='+', + action=DictAction, + help='override some settings in the used config, the key-value pair ' + 'in xxx=yyy format will be merged into config file. If the value to ' + 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' + 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' + 'Note that the quotation marks are necessary and that no white space ' + 'is allowed.', + default={}) + + parser.add_argument('--local_rank', type=int, default=0) + + args = parser.parse_args() + if 'LOCAL_RANK' not in os.environ: + os.environ['LOCAL_RANK'] = str(args.local_rank) + + return args + + +def norm(feat): + N, C, H, W = feat.shape + feat = feat.permute(1, 0, 2, 3).reshape(C, -1) + mean = feat.mean(dim=-1, keepdim=True) + std = feat.std(dim=-1, keepdim=True) + centered = (feat - mean) / (std + 1e-6) + centered = centered.reshape(C, N, H, W).permute(1, 0, 2, 3) + return centered + + +def main(args): + register_all_modules(False) + mod = import_modules_from_strings(f'{args.repo}.utils') + mod.register_all_modules() + + apis = import_modules_from_strings(f'{args.repo}.apis') + inference_model, init_model = None, None + for attr_name in dir(apis): + if 'inference_' in attr_name: + inference_model = getattr(apis, attr_name) + if 'init_' in attr_name: + init_model = getattr(apis, attr_name) + assert inference_model and init_model + + model = init_model(args.config, args.checkpoint, device=args.device) + # init visualizer + visualizer = VISUALIZERS.build(model.cfg.visualizer) + visualizer.draw_featmap = modify + + visualization_cfg = Config.fromfile(args.vis_config) + recorder_cfg = visualization_cfg.recorders + mappings = visualization_cfg.mappings + recorder_manager = RecorderManager(recorder_cfg) + recorder_manager.initialize(model) + + with recorder_manager: + # test a single image + result = inference_model(model, args.img) + + overlaid_image = mmcv.imread( + args.img, channel_order='rgb') if args.overlaid else None + + for name, record in mappings.items(): + recorder = recorder_manager.get_recorder(record.recorder) + record_idx = getattr(record, 'record_idx', 0) + data_idx = getattr(record, 'data_idx') + feats = recorder.get_record_data(record_idx, data_idx) + if isinstance(feats, torch.Tensor): + feats = (feats, ) + + for i, feat in enumerate(feats): + if args.use_norm: + feat = norm(feat) + drawn_img = visualizer.draw_featmap( + feat[0], + overlaid_image, + args.channel_reduction, + topk=args.topk, + arrangement=tuple(args.arrangement), + resize_shape=tuple(args.resize_shape) + if args.resize_shape else None, + alpha=args.alpha) + visualizer.add_datasample( + f'{name}_{i}', + drawn_img, + data_sample=result, + draw_gt=False, + show=args.out_file is None, + wait_time=0.1, + out_file=args.out_file, + **args.cfg_options) + + +if __name__ == '__main__': + args = parse_args() + main(args) diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_diff_visualization.py b/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_diff_visualization.py new file mode 100755 index 000000000..7bc34d90a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_diff_visualization.py @@ -0,0 +1,18 @@ +# Copyright (c) OpenMMLab. All rights reserved. +# configs for the 1st model +recorders1 = dict( + backbone=dict(_scope_='mmrazor', type='ModuleOutputs', source='backbone')) +mappings1 = dict( + p3=dict(recorder='backbone', data_idx=0), + p4=dict(recorder='backbone', data_idx=1), + p5=dict(recorder='backbone', data_idx=2), + p6=dict(recorder='backbone', data_idx=3)) + +# configs for the 2nd model +recorders2 = dict( + backbone=dict(_scope_='mmrazor', type='ModuleOutputs', source='backbone')) +mappings2 = dict( + p3=dict(recorder='backbone', data_idx=0), + p4=dict(recorder='backbone', data_idx=1), + p5=dict(recorder='backbone', data_idx=2), + p6=dict(recorder='backbone', data_idx=3)) diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_visualization.py b/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_visualization.py new file mode 100755 index 000000000..1c8038dff --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_visualization.py @@ -0,0 +1,8 @@ +# Copyright (c) OpenMMLab. All rights reserved. +recorders = dict( + backbone=dict(_scope_='mmrazor', type='ModuleOutputs', source='backbone')) +mappings = dict( + p3=dict(recorder='backbone', data_idx=0), + p4=dict(recorder='backbone', data_idx=1), + p5=dict(recorder='backbone', data_idx=2), + p6=dict(recorder='backbone', data_idx=3)) diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_diff_visualization.py b/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_diff_visualization.py new file mode 100755 index 000000000..c6c172fb6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_diff_visualization.py @@ -0,0 +1,18 @@ +# Copyright (c) OpenMMLab. All rights reserved. +# configs for the 1st model +recorders1 = dict( + neck=dict(_scope_='mmrazor', type='ModuleOutputs', source='neck')) +mappings1 = dict( + p3=dict(recorder='neck', data_idx=0), + p4=dict(recorder='neck', data_idx=1), + p5=dict(recorder='neck', data_idx=2), + p6=dict(recorder='neck', data_idx=3)) + +# configs for the 2nd model +recorders2 = dict( + neck=dict(_scope_='mmrazor', type='ModuleOutputs', source='neck')) +mappings2 = dict( + p3=dict(recorder='neck', data_idx=0), + p4=dict(recorder='neck', data_idx=1), + p5=dict(recorder='neck', data_idx=2), + p6=dict(recorder='neck', data_idx=3)) diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_visualization.py b/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_visualization.py new file mode 100755 index 000000000..40b6b3f1b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_visualization.py @@ -0,0 +1,8 @@ +# Copyright (c) OpenMMLab. All rights reserved. +recorders = dict( + neck=dict(_scope_='mmrazor', type='ModuleOutputs', source='neck')) +mappings = dict( + p3=dict(recorder='neck', data_idx=0), + p4=dict(recorder='neck', data_idx=1), + p5=dict(recorder='neck', data_idx=2), + p6=dict(recorder='neck', data_idx=3)) diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/vis_scheduler.py b/cv/distiller/CWD/mmrazor/tools/visualizations/vis_scheduler.py new file mode 100755 index 000000000..c97bc6418 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/visualizations/vis_scheduler.py @@ -0,0 +1,262 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import json +import os.path as osp +import re +from pathlib import Path +from unittest.mock import MagicMock + +import matplotlib.pyplot as plt +import rich +import torch.nn as nn +from mmcls.utils import register_all_modules +from mmengine import Config, DictAction, Hook, Runner, Visualizer +from mmengine.model import BaseModel +from rich.progress import BarColumn, MofNCompleteColumn, Progress, TextColumn + + +class SimpleModel(BaseModel): + """simple model that do nothing in train_step.""" + + def __init__(self): + super(SimpleModel, self).__init__() + self.data_preprocessor = nn.Identity() + self.conv = nn.Conv2d(1, 1, 1) + + def forward(self, batch_inputs, data_samples, mode='tensor'): + pass + + def train_step(self, data, optim_wrapper): + pass + + +class ParamRecordHook(Hook): + + def __init__(self, by_epoch): + super().__init__() + self.by_epoch = by_epoch + self.lr_list = [] + self.momentum_list = [] + self.task_id = 0 + self.progress = Progress(BarColumn(), MofNCompleteColumn(), + TextColumn('{task.description}')) + + def before_train(self, runner): + if self.by_epoch: + total = runner.train_loop.max_epochs + self.task_id = self.progress.add_task( + 'epochs', start=True, total=total) + else: + total = runner.train_loop.max_iters + self.task_id = self.progress.add_task( + 'iters', start=True, total=total) + self.progress.start() + + def after_train_epoch(self, runner): + if self.by_epoch: + self.progress.update(self.task_id, advance=1) + + def after_train_iter(self, runner, batch_idx, data_batch, outputs): + if not self.by_epoch: + self.progress.update(self.task_id, advance=1) + self.lr_list.append(runner.optim_wrapper.get_lr()['lr'][0]) + self.momentum_list.append( + runner.optim_wrapper.get_momentum()['momentum'][0]) + + def after_train(self, runner): + self.progress.stop() + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Visualize a Dataset Pipeline') + parser.add_argument('config', help='config file path') + parser.add_argument( + '--param', + type=str, + default='lr', + choices=['lr', 'momentum'], + help='The param to visualize its change curve, choose from' + '"lr" and "momentum". Defaults to "lr".') + parser.add_argument( + '--dataset-size', + type=int, + help='The size of the dataset. If specify, `build_dataset` will ' + 'be skipped and use this size as the dataset size.') + parser.add_argument( + '--ngpus', + type=int, + default=1, + help='The number of GPUs used in training.') + parser.add_argument( + '--log-level', + default='WARNING', + help='The log level of the handler and logger. Defaults to ' + 'WARNING.') + parser.add_argument('--title', type=str, help='title of figure') + parser.add_argument( + '--style', type=str, default='whitegrid', help='style of plt') + parser.add_argument( + '--save-path', + type=Path, + help='The learning rate curve plot save path') + parser.add_argument('--not-show', default=False, action='store_true') + parser.add_argument( + '--window-size', + default='12*7', + help='Size of the window to display images, in format of "$W*$H".') + parser.add_argument( + '--cfg-options', + nargs='+', + action=DictAction, + help='override some settings in the used config, the key-value pair ' + 'in xxx=yyy format will be merged into config file. If the value to ' + 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' + 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' + 'Note that the quotation marks are necessary and that no white space ' + 'is allowed.') + args = parser.parse_args() + if args.window_size != '': + assert re.match(r'\d+\*\d+', args.window_size), \ + "'window-size' must be in format 'W*H'." + + return args + + +def plot_curve(lr_list, args, param_name, iters_per_epoch, by_epoch=True): + """Plot learning rate vs iter graph.""" + try: + import seaborn as sns + sns.set_style(args.style) + except ImportError: + pass + + wind_w, wind_h = args.window_size.split('*') + wind_w, wind_h = int(wind_w), int(wind_h) + plt.figure(figsize=(wind_w, wind_h)) + + ax: plt.Axes = plt.subplot() + ax.plot(lr_list, linewidth=1) + + if by_epoch: + ax.xaxis.tick_top() + ax.set_xlabel('Iters') + ax.xaxis.set_label_position('top') + sec_ax = ax.secondary_xaxis( + 'bottom', + functions=(lambda x: x / iters_per_epoch, + lambda y: y * iters_per_epoch)) + sec_ax.set_xlabel('Epochs') + else: + plt.xlabel('Iters') + plt.ylabel(param_name) + + if args.title is None: + plt.title(f'{osp.basename(args.config)} {param_name} curve') + else: + plt.title(args.title) + + +def simulate_train(data_loader, cfg, by_epoch): + model = SimpleModel() + param_record_hook = ParamRecordHook(by_epoch=by_epoch) + default_hooks = dict( + param_scheduler=cfg.default_hooks['param_scheduler'], + timer=None, + logger=None, + checkpoint=None, + sampler_seed=None, + param_record=param_record_hook) + + runner = Runner( + model=model, + work_dir=cfg.work_dir, + train_dataloader=data_loader, + train_cfg=cfg.train_cfg, + log_level=cfg.log_level, + optim_wrapper=cfg.optim_wrapper, + param_scheduler=cfg.param_scheduler, + default_scope=cfg.default_scope, + default_hooks=default_hooks, + visualizer=MagicMock(spec=Visualizer), + custom_hooks=cfg.get('custom_hooks', None)) + + runner.train() + + return param_record_hook.lr_list, param_record_hook.momentum_list + + +def main(): + args = parse_args() + cfg = Config.fromfile(args.config) + if args.cfg_options is not None: + cfg.merge_from_dict(args.cfg_options) + if cfg.get('work_dir', None) is None: + # use config filename as default work_dir if cfg.work_dir is None + cfg.work_dir = osp.join('./work_dirs', + osp.splitext(osp.basename(args.config))[0]) + + cfg.log_level = args.log_level + # register all modules in mmcls into the registries + register_all_modules() + + # make sure save_root exists + if args.save_path and not args.save_path.parent.exists(): + raise FileNotFoundError( + f'The save path is {args.save_path}, and directory ' + f"'{args.save_path.parent}' do not exist.") + + # init logger + print('Param_scheduler :') + rich.print_json(json.dumps(cfg.param_scheduler)) + + # prepare data loader + batch_size = cfg.train_dataloader.batch_size * args.ngpus + + if 'by_epoch' in cfg.train_cfg: + by_epoch = cfg.train_cfg.get('by_epoch') + elif 'type' in cfg.train_cfg: + by_epoch = cfg.train_cfg.get('type') == 'EpochBasedTrainLoop' + else: + raise ValueError('please set `train_cfg`.') + + if args.dataset_size is None and by_epoch: + from mmcls.datasets import build_dataset + dataset_size = len(build_dataset(cfg.train_dataloader.dataset)) + else: + dataset_size = args.dataset_size or batch_size + + class FakeDataloader(list): + dataset = MagicMock(metainfo=None) + + data_loader = FakeDataloader(range(dataset_size // batch_size)) + dataset_info = ( + f'\nDataset infos:' + f'\n - Dataset size: {dataset_size}' + f'\n - Batch size per GPU: {cfg.train_dataloader.batch_size}' + f'\n - Number of GPUs: {args.ngpus}' + f'\n - Total batch size: {batch_size}') + if by_epoch: + dataset_info += f'\n - Iterations per epoch: {len(data_loader)}' + rich.print(dataset_info + '\n') + + # simulation training process + lr_list, momentum_list = simulate_train(data_loader, cfg, by_epoch) + if args.param == 'lr': + param_list = lr_list + else: + param_list = momentum_list + + param_name = 'Learning Rate' if args.param == 'lr' else 'Momentum' + plot_curve(param_list, args, param_name, len(data_loader), by_epoch) + + if args.save_path: + plt.savefig(args.save_path) + print(f'\nThe {param_name} graph is saved at {args.save_path}') + + if not args.not_show: + plt.show() + + +if __name__ == '__main__': + main() -- Gitee From c93b0debbe9a4a5ddf7db60cb8d58dbb3aa6a56d Mon Sep 17 00:00:00 2001 From: "yongle.wu" Date: Mon, 22 May 2023 06:25:36 +0000 Subject: [PATCH 4/6] modified mmcv --- cv/distiller/CWD/mmcv/.circleci/config.yml | 32 - .../CWD/mmcv/.circleci/docker/Dockerfile | 15 - cv/distiller/CWD/mmcv/.circleci/test.yml | 270 --- .../mmcv/.dev_scripts/check_installation.py | 44 - cv/distiller/CWD/mmcv/.owners.yml | 14 - .../CWD/mmcv/.pre-commit-config-zh-cn.yaml | 72 - cv/distiller/CWD/mmcv/.pre-commit-config.yaml | 52 +- cv/distiller/CWD/mmcv/CONTRIBUTING.md | 2 +- cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md | 2 +- cv/distiller/CWD/mmcv/build_mmcv.sh | 0 cv/distiller/CWD/mmcv/clean_mmcv.sh | 0 cv/distiller/CWD/mmcv/compile.log | 229 --- .../mmcv/docs/en/community/contributing.md | 2 +- .../mmcv/docs/zh_cn/community/contributing.md | 2 +- cv/distiller/CWD/mmcv/install_mmcv.sh | 0 cv/distiller/CWD/mmcv/mmcv/ops/__init__.py | 3 +- .../ops/csrc/common/box_iou_rotated_utils.hpp | 7 +- .../csrc/common/cuda/carafe_cuda_kernel.cuh | 7 +- .../csrc/common/cuda/common_cuda_helper.hpp | 2 + .../common/cuda/convex_iou_cuda_kernel.cuh | 150 +- .../cuda/diff_iou_rotated_cuda_kernel.cuh | 2 +- .../csrc/common/cuda/iou3d_cuda_kernel.cuh | 2 +- .../common/cuda/min_area_polygons_cuda.cuh | 6 +- .../cuda/scatter_points_cuda_kernel.cuh | 1 + .../csrc/common/cuda/three_nn_cuda_kernel.cuh | 72 + .../mmcv/mmcv/ops/csrc/common/mps/MPSDevice.h | 64 + .../mmcv/ops/csrc/common/mps/MPSLibrary.h | 61 + .../mmcv/ops/csrc/common/mps/MPSLibrary.mm | 107 ++ .../mmcv/mmcv/ops/csrc/common/mps/MPSStream.h | 132 ++ .../mmcv/mmcv/ops/csrc/common/mps/MPSUtils.h | 51 + .../ops/csrc/common/parrots_cpp_helper.hpp | 4 +- .../ops/csrc/common/parrots_cuda_helper.hpp | 12 +- .../csrc/common/pytorch_device_registry.hpp | 2 +- .../ops/csrc/common/pytorch_npu_helper.hpp | 35 + .../csrc/parrots/active_rotated_filter.cpp | 28 + .../parrots/active_rotated_filter_parrots.cpp | 63 + .../parrots/active_rotated_filter_pytorch.h | 13 + .../ops/csrc/parrots/assign_score_withk.cpp | 42 + .../parrots/assign_score_withk_parrots.cpp | 89 + .../csrc/parrots/assign_score_withk_pytorch.h | 19 + .../ops/csrc/parrots/ball_query._parrots.cpp | 43 + .../mmcv/mmcv/ops/csrc/parrots/ball_query.cpp | 20 + .../ops/csrc/parrots/ball_query_pytorch.h | 11 + .../mmcv/ops/csrc/parrots/bbox_overlaps.cpp | 14 + .../csrc/parrots/bbox_overlaps_parrots.cpp | 40 + .../ops/csrc/parrots/bbox_overlaps_pytorch.h | 10 + .../mmcv/ops/csrc/parrots/border_align.cpp | 30 + .../ops/csrc/parrots/border_align_parrots.cpp | 53 + .../ops/csrc/parrots/border_align_pytorch.h | 17 + .../mmcv/ops/csrc/parrots/box_iou_rotated.cpp | 19 + .../csrc/parrots/box_iou_rotated_parrots.cpp | 61 + .../csrc/parrots/box_iou_rotated_pytorch.h | 15 + .../CWD/mmcv/mmcv/ops/csrc/parrots/carafe.cpp | 38 + .../mmcv/ops/csrc/parrots/carafe_naive.cpp | 32 + .../ops/csrc/parrots/carafe_naive_parrots.cpp | 74 + .../ops/csrc/parrots/carafe_naive_pytorch.h | 15 + .../mmcv/ops/csrc/parrots/carafe_parrots.cpp | 88 + .../mmcv/ops/csrc/parrots/carafe_pytorch.h | 16 + .../ops/csrc/parrots/chamfer_distance.cpp | 35 + .../csrc/parrots/chamfer_distance_parrots.cpp | 51 + .../csrc/parrots/chamfer_distance_pytorch.h | 16 + .../mmcv/ops/csrc/parrots/contour_expand.cpp | 111 ++ .../csrc/parrots/contour_expand_parrots.cpp | 43 + .../ops/csrc/parrots/contour_expand_pytorch.h | 12 + .../mmcv/mmcv/ops/csrc/parrots/convex_iou.cpp | 23 + .../ops/csrc/parrots/convex_iou_parrots.cpp | 40 + .../ops/csrc/parrots/convex_iou_pytorch.h | 11 + .../mmcv/ops/csrc/parrots/correlation.cpp | 47 + .../ops/csrc/parrots/correlation_parrots.cpp | 176 ++ .../ops/csrc/parrots/correlation_pytorch.h | 18 + .../mmcv/mmcv/ops/csrc/parrots/cudabind.cpp | 1677 +++++++++++++++++ .../mmcv/ops/csrc/parrots/deform_conv.cpp | 517 +++++ .../ops/csrc/parrots/deform_conv_parrots.cpp | 273 +++ .../ops/csrc/parrots/deform_conv_pytorch.h | 28 + .../mmcv/ops/csrc/parrots/deform_roi_pool.cpp | 42 + .../csrc/parrots/deform_roi_pool_parrots.cpp | 102 + .../csrc/parrots/deform_roi_pool_pytorch.h | 18 + .../ops/csrc/parrots/diff_iou_rotated.cpp | 14 + .../csrc/parrots/diff_iou_rotated_parrots.cpp | 28 + .../csrc/parrots/diff_iou_rotated_pytorch.h | 10 + .../mmcv/mmcv/ops/csrc/parrots/focal_loss.cpp | 53 + .../ops/csrc/parrots/focal_loss_parrots.cpp | 113 ++ .../ops/csrc/parrots/focal_loss_pytorch.h | 21 + .../csrc/parrots/furthest_point_sample.cpp | 34 + .../parrots/furthest_point_sample_parrots.cpp | 57 + .../parrots/furthest_point_sample_pytorch.h | 14 + .../ops/csrc/parrots/fused_bias_leakyrelu.cpp | 119 ++ .../ops/csrc/parrots/fused_bias_parrots.cpp | 41 + .../mmcv/ops/csrc/parrots/gather_points.cpp | 30 + .../csrc/parrots/gather_points_parrots.cpp | 71 + .../ops/csrc/parrots/gather_points_pytorch.h | 13 + .../mmcv/ops/csrc/parrots/group_points.cpp | 34 + .../ops/csrc/parrots/group_points_parrots.cpp | 72 + .../ops/csrc/parrots/group_points_pytorch.h | 15 + .../CWD/mmcv/mmcv/ops/csrc/parrots/info.cpp | 65 + .../CWD/mmcv/mmcv/ops/csrc/parrots/iou3d.cpp | 66 + .../mmcv/ops/csrc/parrots/iou3d_parrots.cpp | 70 + .../mmcv/ops/csrc/parrots/iou3d_pytorch.h | 16 + .../CWD/mmcv/mmcv/ops/csrc/parrots/knn.cpp | 17 + .../mmcv/ops/csrc/parrots/knn_parrots.cpp | 41 + .../mmcv/mmcv/ops/csrc/parrots/knn_pytorch.h | 9 + .../mmcv/ops/csrc/parrots/masked_conv2d.cpp | 33 + .../csrc/parrots/masked_conv2d_parrots.cpp | 72 + .../ops/csrc/parrots/masked_conv2d_pytorch.h | 15 + .../ops/csrc/parrots/min_area_polygons.cpp | 11 + .../parrots/min_area_polygons_parrots.cpp | 26 + .../csrc/parrots/min_area_polygons_pytorch.h | 9 + .../csrc/parrots/modulated_deform_conv.cpp | 237 +++ .../parrots/modulated_deform_conv_parrots.cpp | 199 ++ .../parrots/modulated_deform_conv_pytorch.h | 21 + .../mmcv/ops/csrc/parrots/ms_deform_attn.cpp | 60 + .../csrc/parrots/ms_deform_attn_parrots.cpp | 69 + .../CWD/mmcv/mmcv/ops/csrc/parrots/nms.cpp | 33 + .../mmcv/ops/csrc/parrots/nms_parrots.cpp | 140 ++ .../mmcv/mmcv/ops/csrc/parrots/nms_pytorch.h | 18 + .../mmcv/ops/csrc/parrots/nms_rotated.cpp | 32 + .../mmcv/ops/csrc/parrots/pixel_group.cpp | 26 + .../ops/csrc/parrots/pixel_group_parrots.cpp | 54 + .../ops/csrc/parrots/pixel_group_pytorch.h | 11 + .../mmcv/ops/csrc/parrots/points_in_boxes.cpp | 44 + .../csrc/parrots/points_in_boxes_parrots.cpp | 64 + .../csrc/parrots/points_in_boxes_pytorch.h | 16 + .../ops/csrc/parrots/points_in_polygons.cpp | 15 + .../parrots/points_in_polygons_parrots.cpp | 28 + .../csrc/parrots/points_in_polygons_pytorch.h | 9 + .../mmcv/mmcv/ops/csrc/parrots/prroi_pool.cpp | 47 + .../ops/csrc/parrots/prroi_pool_parrots.cpp | 97 + .../ops/csrc/parrots/prroi_pool_pytorch.h | 19 + .../mmcv/mmcv/ops/csrc/parrots/psamask.cpp | 41 + .../mmcv/ops/csrc/parrots/psamask_parrots.cpp | 129 ++ .../mmcv/ops/csrc/parrots/psamask_pytorch.h | 31 + .../ops/csrc/parrots/riroi_align_rotated.cpp | 42 + .../parrots/riroi_align_rotated_parrots.cpp | 86 + .../parrots/riroi_align_rotated_pytorch.h | 18 + .../mmcv/mmcv/ops/csrc/parrots/roi_align.cpp | 41 + .../ops/csrc/parrots/roi_align_parrots.cpp | 151 ++ .../mmcv/ops/csrc/parrots/roi_align_pytorch.h | 32 + .../ops/csrc/parrots/roi_align_rotated.cpp | 41 + .../parrots/roi_align_rotated_parrots.cpp | 147 ++ .../csrc/parrots/roi_align_rotated_pytorch.h | 31 + .../mmcv/mmcv/ops/csrc/parrots/roi_pool.cpp | 31 + .../ops/csrc/parrots/roi_pool_parrots.cpp | 67 + .../mmcv/ops/csrc/parrots/roi_pool_pytorch.h | 16 + .../mmcv/ops/csrc/parrots/roiaware_pool3d.cpp | 72 + .../csrc/parrots/roiaware_pool3d_parrots.cpp | 58 + .../csrc/parrots/roiaware_pool3d_pytorch.h | 14 + .../mmcv/ops/csrc/parrots/roipoint_pool3d.cpp | 39 + .../csrc/parrots/roipoint_pool3d_parrots.cpp | 31 + .../csrc/parrots/roipoint_pool3d_pytorch.h | 10 + .../csrc/parrots/rotated_feature_align.cpp | 39 + .../parrots/rotated_feature_align_parrots.cpp | 99 + .../parrots/rotated_feature_align_pytorch.h | 17 + .../mmcv/mmcv/ops/csrc/parrots/sync_bn.cpp | 69 + .../mmcv/ops/csrc/parrots/sync_bn_parrots.cpp | 111 ++ .../mmcv/ops/csrc/parrots/sync_bn_pytorch.h | 26 + .../ops/csrc/parrots/three_interpolate.cpp | 33 + .../parrots/three_interpolate_parrots.cpp | 74 + .../csrc/parrots/three_interpolate_pytorch.h | 14 + .../mmcv/mmcv/ops/csrc/parrots/three_nn.cpp | 18 + .../ops/csrc/parrots/three_nn_parrots.cpp | 35 + .../mmcv/ops/csrc/parrots/three_nn_pytorch.h | 10 + .../mmcv/mmcv/ops/csrc/parrots/tin_shift.cpp | 20 + .../ops/csrc/parrots/tin_shift_parrots.cpp | 39 + .../mmcv/ops/csrc/parrots/tin_shift_pytorch.h | 11 + .../mmcv/mmcv/ops/csrc/parrots/upfirdn2d.cpp | 118 ++ .../ops/csrc/parrots/upfirdn2d_parrots.cpp | 47 + .../mmcv/ops/csrc/parrots/voxelization.cpp | 74 + .../ops/csrc/parrots/voxelization_parrots.cpp | 113 ++ .../ops/csrc/parrots/voxelization_pytorch.h | 20 + .../mmcv/ops/csrc/pytorch/contour_expand.cpp | 0 .../mmcv/ops/csrc/pytorch/cuda/cudabind.cpp | 21 +- .../cuda/furthest_point_sample_cuda.cu | 5 +- .../ops/csrc/pytorch/cuda/three_nn_cuda.cu | 35 + .../ops/csrc/pytorch/mps/bbox_overlaps_mps.mm | 99 + .../ops/csrc/pytorch/npu/deform_roi_pool.cpp | 63 + .../ops/csrc/pytorch/npu/focal_loss_npu.cpp | 162 ++ .../pytorch/npu/fused_bias_leakyrelu_npu.cpp | 54 + .../mmcv/ops/csrc/pytorch/npu/nms_npu.cpp | 45 + .../ops/csrc/pytorch/npu/psa_mask_npu.cpp | 75 + .../ops/csrc/pytorch/npu/roi_pool_npu.cpp | 34 + .../mmcv/ops/csrc/pytorch/pixel_group.cpp | 0 .../CWD/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp | 14 +- .../mmcv/mmcv/ops/csrc/pytorch/three_nn.cpp | 18 + .../CWD/mmcv/mmcv/ops/points_in_polygons.py | 2 +- cv/distiller/CWD/mmcv/mmcv/ops/three_nn.py | 2 +- .../CWD/mmcv/tests/data/scripts/hello.py | 0 .../CWD/mmcv/tests/data/sparse_flow.png | Bin .../mmcv/tests/test_ops/test_ball_query.py | 6 +- .../mmcv/tests/test_ops/test_bezier_align.py | 2 +- .../test_ops/test_bilinear_grid_sample.py | 12 +- .../mmcv/tests/test_ops/test_border_align.py | 2 +- .../CWD/mmcv/tests/test_ops/test_carafe.py | 8 +- .../mmcv/tests/test_ops/test_convex_iou.py | 14 +- .../mmcv/tests/test_ops/test_correlation.py | 2 +- .../mmcv/tests/test_ops/test_deform_conv.py | 4 +- .../tests/test_ops/test_deform_roi_pool.py | 2 +- .../mmcv/tests/test_ops/test_group_points.py | 4 +- .../CWD/mmcv/tests/test_ops/test_info.py | 2 + .../CWD/mmcv/tests/test_ops/test_iou3d.py | 2 +- .../tests/test_ops/test_min_area_polygons.py | 2 +- .../test_ops/test_modulated_deform_conv.py | 4 +- .../tests/test_ops/test_ms_deformable_attn.py | 22 +- .../CWD/mmcv/tests/test_ops/test_onnx.py | 4 +- .../tests/test_ops/test_points_in_polygons.py | 6 +- .../CWD/mmcv/tests/test_ops/test_roi_align.py | 6 +- .../tests/test_ops/test_roi_align_rotated.py | 6 +- .../CWD/mmcv/tests/test_ops/test_roi_pool.py | 2 +- .../tests/test_ops/test_roiaware_pool3d.py | 4 +- .../tests/test_ops/test_roipoint_pool3d.py | 4 +- .../tests/test_ops/test_three_interpolate.py | 2 +- .../CWD/mmcv/tests/test_ops/test_tin_shift.py | 2 +- 211 files changed, 9950 insertions(+), 892 deletions(-) delete mode 100644 cv/distiller/CWD/mmcv/.circleci/config.yml delete mode 100644 cv/distiller/CWD/mmcv/.circleci/docker/Dockerfile delete mode 100644 cv/distiller/CWD/mmcv/.circleci/test.yml delete mode 100644 cv/distiller/CWD/mmcv/.dev_scripts/check_installation.py delete mode 100644 cv/distiller/CWD/mmcv/.owners.yml delete mode 100644 cv/distiller/CWD/mmcv/.pre-commit-config-zh-cn.yaml mode change 100644 => 100755 cv/distiller/CWD/mmcv/build_mmcv.sh mode change 100644 => 100755 cv/distiller/CWD/mmcv/clean_mmcv.sh delete mode 100644 cv/distiller/CWD/mmcv/compile.log mode change 100644 => 100755 cv/distiller/CWD/mmcv/install_mmcv.sh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/three_nn_cuda_kernel.cuh create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSDevice.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.mm create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSStream.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSUtils.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_npu_helper.hpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query._parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/cudabind.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_leakyrelu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/info.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_pytorch.h create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_parrots.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_pytorch.h mode change 100644 => 100755 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/contour_expand.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/three_nn_cuda.cu create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mps/bbox_overlaps_mps.mm create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/deform_roi_pool.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/focal_loss_npu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/fused_bias_leakyrelu_npu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/nms_npu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/psa_mask_npu.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/roi_pool_npu.cpp mode change 100644 => 100755 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pixel_group.cpp create mode 100644 cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/three_nn.cpp mode change 100644 => 100755 cv/distiller/CWD/mmcv/tests/data/scripts/hello.py mode change 100644 => 100755 cv/distiller/CWD/mmcv/tests/data/sparse_flow.png diff --git a/cv/distiller/CWD/mmcv/.circleci/config.yml b/cv/distiller/CWD/mmcv/.circleci/config.yml deleted file mode 100644 index e13eabe9c..000000000 --- a/cv/distiller/CWD/mmcv/.circleci/config.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: 2.1 - -# this allows you to use CircleCI's dynamic configuration feature -setup: true - -# the path-filtering orb is required to continue a pipeline based on -# the path of an updated fileset -orbs: - path-filtering: circleci/path-filtering@0.1.2 - -workflows: - # the always-run workflow is always triggered, regardless of the pipeline parameters. - always-run: - jobs: - # the path-filtering/filter job determines which pipeline - # parameters to update. - - path-filtering/filter: - name: check-updated-files - # 3-column, whitespace-delimited mapping. One mapping per - # line: - # - mapping: | - mmcv/.* lint_only false - requirements/.* lint_only false - tests/.* lint_only false - .circleci/.* lint_only false - base-revision: 2.x - # this is the path of the configuration we should trigger once - # path filtering and pipeline parameter value updates are - # complete. In this case, we are using the parent dynamic - # configuration itself. - config-path: .circleci/test.yml diff --git a/cv/distiller/CWD/mmcv/.circleci/docker/Dockerfile b/cv/distiller/CWD/mmcv/.circleci/docker/Dockerfile deleted file mode 100644 index db5ab86e3..000000000 --- a/cv/distiller/CWD/mmcv/.circleci/docker/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -ARG PYTORCH="1.8.1" -ARG CUDA="10.2" -ARG CUDNN="7" - -FROM pytorch/pytorch:${PYTORCH}-cuda${CUDA}-cudnn${CUDNN}-devel - -# Set MKL_THREADING_LAYER=GNU to fix issue: -# https://github.com/pytorch/pytorch/issues/37377 -ENV MKL_THREADING_LAYER GNU - -# To fix GPG key error when running apt-get update -RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub -RUN apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/7fa2af80.pub - -RUN apt-get update && apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx ffmpeg libturbojpeg git diff --git a/cv/distiller/CWD/mmcv/.circleci/test.yml b/cv/distiller/CWD/mmcv/.circleci/test.yml deleted file mode 100644 index 9150be69e..000000000 --- a/cv/distiller/CWD/mmcv/.circleci/test.yml +++ /dev/null @@ -1,270 +0,0 @@ -version: 2.1 - -# the default pipeline parameters, which will be updated according to -# the results of the path-filtering orb -parameters: - lint_only: - type: boolean - default: true - -jobs: - lint: - docker: - - image: cimg/python:3.7.4 - steps: - - checkout - - run: - name: Install pre-commit hook - command: | - pip install pre-commit - pre-commit install - - run: - name: Linting - command: pre-commit run --all-files - build_without_torch: - parameters: - # The python version must match available image tags in - # https://circleci.com/developer/images/image/cimg/python - python: - type: string - default: "3.7.4" - docker: - - image: cimg/python:<< parameters.python >> - resource_class: large - steps: - - checkout - - run: - name: Install Libraries - command: | - sudo apt-get update - sudo apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx libjpeg-dev zlib1g-dev libtinfo-dev libncurses5 ffmpeg libturbojpeg - - run: - name: Upgrade pip - command: | - pip install pip --upgrade - pip --version - - run: - name: Install MMEngine from main branch - command: pip install git+https://github.com/open-mmlab/mmengine.git@main - - run: - name: Build MMCV from source - command: pip install -e . -v - environment: - MMCV_WITH_OPS: 0 - - run: - name: Install unit tests dependencies - command: pip install -r requirements/test.txt - - run: - name: Run unit tests - command: pytest tests/test_image tests/test_transforms tests/test_video tests/test_arraymisc.py tests/test_visualization.py tests/test_utils/test_env.py --ignore=tests/test_image/test_io.py - build_without_ops: - parameters: - # The python version must match available image tags in - # https://circleci.com/developer/images/image/cimg/python - python: - type: string - default: "3.7.4" - torch: - type: string - torchvision: - type: string - docker: - - image: cimg/python:<< parameters.python >> - resource_class: large - steps: - - checkout - - run: - name: Install Libraries - command: | - sudo apt-get update - sudo apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx libjpeg-dev zlib1g-dev libtinfo-dev libncurses5 ffmpeg libturbojpeg - - run: - name: Configure Python & pip - command: | - pip install --upgrade pip - pip install wheel - - run: - name: Install PyTorch - command: pip install torch==<< parameters.torch >>+cpu torchvision==<< parameters.torchvision >>+cpu -f https://download.pytorch.org/whl/torch_stable.html - - run: - name: Install MMEngine from main branch - command: pip install git+https://github.com/open-mmlab/mmengine.git@main - - run: - name: Create sdist and untar - command: | - sed -i "s/os.getenv('MMCV_WITH_OPS', '1')/os.getenv('MMCV_WITH_OPS', '0')/g" setup.py - python setup.py sdist - tar zxvf dist/mmcv* -C /tmp - rm -r mmcv - - run: - name: Build and install from sdist - command: | - pushd /tmp/mmcv* - pip install -e . -v - popd - - run: - name: Install unit tests dependencies - command: pip install -r requirements/test.txt - - run: - name: Run unit tests - command: pytest tests --ignore=tests/test_ops - build_cpu: - parameters: - # The python version must match available image tags in - # https://circleci.com/developer/images/image/cimg/python - python: - type: string - torch: - type: string - torchvision: - type: string - docker: - - image: cimg/python:<< parameters.python >> - resource_class: large - steps: - - checkout - - run: - name: Install Libraries - command: | - sudo apt-get update - sudo apt-get install -y ninja-build libglib2.0-0 libsm6 libxrender-dev libxext6 libgl1-mesa-glx libjpeg-dev zlib1g-dev libtinfo-dev libncurses5 ffmpeg libturbojpeg - - run: - name: Configure Python & pip - command: | - pip install --upgrade pip - pip install wheel - - run: - name: Install PyTorch - command: pip install torch==<< parameters.torch >>+cpu torchvision==<< parameters.torchvision >>+cpu -f https://download.pytorch.org/whl/torch_stable.html - - run: - name: Install MMEngine from main branch - command: pip install git+https://github.com/open-mmlab/mmengine.git@main - - run: - name: Install ninja to speed the compilation - command: pip install ninja - - run: - name: Create sdist and untar - command: | - python setup.py sdist - tar zxvf dist/mmcv* -C /tmp - rm -r mmcv - - run: - name: Build and install from sdist - command: | - pushd /tmp/mmcv* - pip install -e . -v - popd - - run: - name: Install unit tests dependencies - command: pip install -r requirements/test.txt - - run: - name: Run unittests - command: | - coverage run --branch --source mmcv -m pytest tests/ - coverage xml - coverage report -m - build_cuda: - parameters: - torch: - type: string - cuda: - type: enum - enum: ["10.1", "10.2", "11.1"] - cudnn: - type: integer - default: 7 - machine: - image: ubuntu-2004-cuda-11.4:202110-01 - docker_layer_caching: true - resource_class: gpu.nvidia.small - steps: - - checkout - - run: - name: Build Docker image - command: | - docker build .circleci/docker -t mmcv:gpu --build-arg PYTORCH=<< parameters.torch >> --build-arg CUDA=<< parameters.cuda >> --build-arg CUDNN=<< parameters.cudnn >> - docker run --gpus all -t -d -v /home/circleci/project:/mmcv -w /mmcv --name mmcv mmcv:gpu - - run: - name: Install MMEngine from main branch - command: docker exec mmcv pip install git+https://github.com/open-mmlab/mmengine.git@main - - run: - name: Build MMCV from source - command: docker exec mmcv pip install -e . -v - - run: - name: Install unit tests dependencies - command: docker exec mmcv pip install -r requirements/test.txt - - run: - name: Run unittests - command: docker exec mmcv python -m pytest tests/ -workflows: - pr_stage_lint: - when: << pipeline.parameters.lint_only >> - jobs: - - lint: - name: lint - filters: - branches: - ignore: - - 2.x - pr_stage_test: - when: - not: - << pipeline.parameters.lint_only >> - jobs: - - lint: - name: lint - filters: - branches: - ignore: - - 2.x - - build_without_torch: - name: build_without_torch - requires: - - lint - - build_without_ops: - name: build_without_ops - torch: 1.6.0 - torchvision: 0.7.0 - requires: - - build_without_torch - - build_cpu: - name: minimum_version_cpu - torch: 1.6.0 - torchvision: 0.7.0 - python: 3.7.4 - requires: - - build_without_ops - - build_cpu: - name: maximum_version_cpu - torch: 1.13.0 - torchvision: 0.14.0 - python: 3.9.0 - requires: - - minimum_version_cpu - - hold: - type: approval - requires: - - maximum_version_cpu - - build_cuda: - name: mainstream_version_gpu - torch: 1.8.1 - # Use double quotation mark to explicitly specify its type - # as string instead of number - cuda: "10.2" - requires: - - hold - merge_stage_test: - when: - not: - << pipeline.parameters.lint_only >> - jobs: - - build_cuda: - name: minimum_version_gpu - torch: 1.6.0 - # Use double quotation mark to explicitly specify its type - # as string instead of number - cuda: "10.1" - filters: - branches: - only: - - 2.x diff --git a/cv/distiller/CWD/mmcv/.dev_scripts/check_installation.py b/cv/distiller/CWD/mmcv/.dev_scripts/check_installation.py deleted file mode 100644 index 739c1e110..000000000 --- a/cv/distiller/CWD/mmcv/.dev_scripts/check_installation.py +++ /dev/null @@ -1,44 +0,0 @@ -import numpy as np -import torch - -from mmcv.ops import box_iou_rotated -from mmcv.utils import collect_env - - -def check_installation(): - """Check whether mmcv has been installed successfully.""" - np_boxes1 = np.asarray( - [[1.0, 1.0, 3.0, 4.0, 0.5], [2.0, 2.0, 3.0, 4.0, 0.6], - [7.0, 7.0, 8.0, 8.0, 0.4]], - dtype=np.float32) - np_boxes2 = np.asarray( - [[0.0, 2.0, 2.0, 5.0, 0.3], [2.0, 1.0, 3.0, 3.0, 0.5], - [5.0, 5.0, 6.0, 7.0, 0.4]], - dtype=np.float32) - boxes1 = torch.from_numpy(np_boxes1) - boxes2 = torch.from_numpy(np_boxes2) - - # test mmcv with CPU ops - box_iou_rotated(boxes1, boxes2) - print('CPU ops were compiled successfully.') - - # test mmcv with both CPU and CUDA ops - if torch.cuda.is_available(): - boxes1 = boxes1.cuda() - boxes2 = boxes2.cuda() - box_iou_rotated(boxes1, boxes2) - print('CUDA ops were compiled successfully.') - else: - print('No CUDA runtime is found, skipping the checking of CUDA ops.') - - -if __name__ == '__main__': - print('Start checking the installation of mmcv ...') - check_installation() - print('mmcv has been installed successfully.\n') - - env_info_dict = collect_env() - env_info = '\n'.join([(f'{k}: {v}') for k, v in env_info_dict.items()]) - dash_line = '-' * 60 + '\n' - print('Environment information:') - print(dash_line + env_info + '\n' + dash_line) diff --git a/cv/distiller/CWD/mmcv/.owners.yml b/cv/distiller/CWD/mmcv/.owners.yml deleted file mode 100644 index 8f7057cb3..000000000 --- a/cv/distiller/CWD/mmcv/.owners.yml +++ /dev/null @@ -1,14 +0,0 @@ -assign: - strategy: - # random - daily-shift-based - scedule: - '*/1 * * * *' - assignees: - - zhouzaida - - ice-tong - - HAOCHENYE - - zhouzaida - - ice-tong - - HAOCHENYE - - zhouzaida diff --git a/cv/distiller/CWD/mmcv/.pre-commit-config-zh-cn.yaml b/cv/distiller/CWD/mmcv/.pre-commit-config-zh-cn.yaml deleted file mode 100644 index 73f0388fe..000000000 --- a/cv/distiller/CWD/mmcv/.pre-commit-config-zh-cn.yaml +++ /dev/null @@ -1,72 +0,0 @@ -exclude: ^tests/data/ -repos: - - repo: https://gitee.com/openmmlab/mirrors-flake8 - rev: 5.0.4 - hooks: - - id: flake8 - - repo: https://gitee.com/openmmlab/mirrors-isort - rev: 5.10.1 - hooks: - - id: isort - - repo: https://gitee.com/openmmlab/mirrors-yapf - rev: v0.32.0 - hooks: - - id: yapf - - repo: https://gitee.com/openmmlab/mirrors-pre-commit-hooks - rev: v4.3.0 - hooks: - - id: trailing-whitespace - - id: check-yaml - - id: end-of-file-fixer - - id: requirements-txt-fixer - - id: double-quote-string-fixer - - id: check-merge-conflict - - id: fix-encoding-pragma - args: ["--remove"] - - id: mixed-line-ending - args: ["--fix=lf"] - - repo: https://gitee.com/openmmlab/mirrors-codespell - rev: v2.2.1 - hooks: - - id: codespell - - repo: https://gitee.com/openmmlab/mirrors-mdformat - rev: 0.7.9 - hooks: - - id: mdformat - args: ["--number"] - additional_dependencies: - - mdformat-openmmlab - - mdformat_frontmatter - - linkify-it-py - - repo: https://gitee.com/openmmlab/mirrors-docformatter - rev: v1.3.1 - hooks: - - id: docformatter - args: ["--in-place", "--wrap-descriptions", "79"] - - repo: https://github.com/asottile/pyupgrade - rev: v3.0.0 - hooks: - - id: pyupgrade - args: ["--py36-plus"] - - repo: https://gitee.com/openmmlab/pre-commit-hooks - rev: v0.2.0 # Use the ref you want to point at - hooks: - - id: check-copyright - args: ["mmcv", "tests", "--excludes", "mmcv/ops"] - - repo: https://gitee.com/openmmlab/mirrors-mypy - rev: v0.812 - hooks: - - id: mypy - exclude: |- - (?x)( - ^test - | ^docs - ) - # - repo: local - # hooks: - # - id: clang-format - # name: clang-format - # description: Format files with ClangFormat - # entry: clang-format -style=google -i - # language: system - # files: \.(c|cc|cxx|cpp|cu|h|hpp|hxx|cuh|proto)$ diff --git a/cv/distiller/CWD/mmcv/.pre-commit-config.yaml b/cv/distiller/CWD/mmcv/.pre-commit-config.yaml index 2f7fdf013..19e9f8d48 100644 --- a/cv/distiller/CWD/mmcv/.pre-commit-config.yaml +++ b/cv/distiller/CWD/mmcv/.pre-commit-config.yaml @@ -1,19 +1,23 @@ exclude: ^tests/data/ repos: - - repo: https://github.com/PyCQA/flake8 - rev: 5.0.4 + - repo: https://gitlab.com/pycqa/flake8.git + rev: 3.8.3 hooks: - id: flake8 - - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + - repo: https://github.com/asottile/seed-isort-config + rev: v2.2.0 + hooks: + - id: seed-isort-config + - repo: https://github.com/timothycrosley/isort + rev: 4.3.21 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-yapf - rev: v0.32.0 + rev: v0.30.0 hooks: - id: yapf - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v3.1.0 hooks: - id: trailing-whitespace - id: check-yaml @@ -25,43 +29,21 @@ repos: args: ["--remove"] - id: mixed-line-ending args: ["--fix=lf"] + - repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 2.1.4 + hooks: + - id: markdownlint + args: ["-r", "~MD002,~MD013,~MD029,~MD033,~MD034", + "-t", "allow_different_nesting"] - repo: https://github.com/codespell-project/codespell - rev: v2.2.1 + rev: v2.1.0 hooks: - id: codespell - - repo: https://github.com/executablebooks/mdformat - rev: 0.7.9 - hooks: - - id: mdformat - args: ["--number"] - additional_dependencies: - - mdformat-openmmlab - - mdformat_frontmatter - - linkify-it-py - repo: https://github.com/myint/docformatter rev: v1.3.1 hooks: - id: docformatter args: ["--in-place", "--wrap-descriptions", "79"] - - repo: https://github.com/asottile/pyupgrade - rev: v3.0.0 - hooks: - - id: pyupgrade - args: ["--py36-plus"] - - repo: https://github.com/open-mmlab/pre-commit-hooks - rev: v0.2.0 # Use the ref you want to point at - hooks: - - id: check-copyright - args: ["mmcv", "tests", "--excludes", "mmcv/ops"] - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.812 - hooks: - - id: mypy - exclude: |- - (?x)( - ^test - | ^docs - ) # - repo: local # hooks: # - id: clang-format diff --git a/cv/distiller/CWD/mmcv/CONTRIBUTING.md b/cv/distiller/CWD/mmcv/CONTRIBUTING.md index a60cd9943..184a6bd2c 100644 --- a/cv/distiller/CWD/mmcv/CONTRIBUTING.md +++ b/cv/distiller/CWD/mmcv/CONTRIBUTING.md @@ -229,7 +229,7 @@ We use the following tools for linting and formatting: Style configurations of yapf and isort can be found in [setup.cfg](./setup.cfg). We use [pre-commit hook](https://pre-commit.com/) that checks and formats for `flake8`, `yapf`, `isort`, `trailing whitespaces`, `markdown files`, -fixes `end-of-files`, `double-quoted-strings`, `python-encoding-pragma`, `mixed-line-ending`, sorts `requirments.txt` automatically on every commit. +fixes `end-of-files`, `float-quoted-strings`, `python-encoding-pragma`, `mixed-line-ending`, sorts `requirments.txt` automatically on every commit. The config for a pre-commit hook is stored in [.pre-commit-config](./.pre-commit-config.yaml). #### C++ and CUDA diff --git a/cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md b/cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md index 00622031d..52cc1ab5b 100644 --- a/cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md +++ b/cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md @@ -239,7 +239,7 @@ make html yapf å’Œ isort çš„é…ç½®å¯ä»¥åœ¨ [setup.cfg](./setup.cfg) 找到 通过é…ç½® [pre-commit hook](https://pre-commit.com/) ,我们å¯ä»¥åœ¨æäº¤ä»£ç æ—¶è‡ªåŠ¨æ£€æŸ¥å’Œæ ¼å¼åŒ– `flake8`ã€`yapf`ã€`isort`ã€`trailing whitespaces`ã€`markdown files`, -ä¿®å¤ `end-of-files`ã€`double-quoted-strings`ã€`python-encoding-pragma`ã€`mixed-line-ending`,调整 `requirments.txt` 的包顺åºã€‚ +ä¿®å¤ `end-of-files`ã€`float-quoted-strings`ã€`python-encoding-pragma`ã€`mixed-line-ending`,调整 `requirments.txt` 的包顺åºã€‚ pre-commit é’©å­çš„é…ç½®å¯ä»¥åœ¨ [.pre-commit-config](./.pre-commit-config.yaml) 找到。 pre-commit 具体的安装使用方å¼è§[拉å–请求](#2-é…ç½®-pre-commit)。 diff --git a/cv/distiller/CWD/mmcv/build_mmcv.sh b/cv/distiller/CWD/mmcv/build_mmcv.sh old mode 100644 new mode 100755 diff --git a/cv/distiller/CWD/mmcv/clean_mmcv.sh b/cv/distiller/CWD/mmcv/clean_mmcv.sh old mode 100644 new mode 100755 diff --git a/cv/distiller/CWD/mmcv/compile.log b/cv/distiller/CWD/mmcv/compile.log deleted file mode 100644 index a35e8435b..000000000 --- a/cv/distiller/CWD/mmcv/compile.log +++ /dev/null @@ -1,229 +0,0 @@ -running build -running build_py -running egg_info -writing mmcv.egg-info/PKG-INFO -writing dependency_links to mmcv.egg-info/dependency_links.txt -writing requirements to mmcv.egg-info/requires.txt -writing top-level names to mmcv.egg-info/top_level.txt -reading manifest file 'mmcv.egg-info/SOURCES.txt' -reading manifest template 'MANIFEST.in' -warning: no files found matching 'mmcv/ops/csrc/parrots/*.h' -warning: no files found matching 'mmcv/ops/csrc/parrots/*.cpp' -warning: no files found matching 'mmcv/ops/csrc/pytorch/mps/*.mm' -warning: no files found matching 'mmcv/ops/csrc/common/mps/*.h' -warning: no files found matching 'mmcv/ops/csrc/common/mps/*.mm' -warning: no files found matching '*.h' under directory 'mmcv/ops/csrc/' -warning: no files found matching '*.mm' under directory 'mmcv/ops/csrc/' -adding license file 'LICENSE' -adding license file 'LICENSES.md' -writing manifest file 'mmcv.egg-info/SOURCES.txt' -copying mmcv/ops/csrc/pytorch/pybind.cpp -> build/lib.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch -copying mmcv/ops/csrc/pytorch/cuda/cudabind.cpp -> build/lib.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch/cuda -running build_ext -building 'mmcv._ext' extension -/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.common' as data is deprecated, please list it in `packages`. - !! - - - ############################ - # Package would be ignored # - ############################ - Python recognizes 'mmcv.ops.csrc.common' as an importable package, - but it is not listed in the `packages` configuration of setuptools. - - 'mmcv.ops.csrc.common' has been automatically added to the distribution only - because it may contain data files, but this behavior is likely to change - in future versions of setuptools (and therefore is considered deprecated). - - Please make sure that 'mmcv.ops.csrc.common' is included as a package by using - the `packages` configuration field or the proper discovery methods - (for example by using `find_namespace_packages(...)`/`find_namespace:` - instead of `find_packages(...)`/`find:`). - - You can read more about "package discovery" and "data files" on setuptools - documentation page. - - -!! - - check.warn(importable) -/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.common.cuda' as data is deprecated, please list it in `packages`. - !! - - - ############################ - # Package would be ignored # - ############################ - Python recognizes 'mmcv.ops.csrc.common.cuda' as an importable package, - but it is not listed in the `packages` configuration of setuptools. - - 'mmcv.ops.csrc.common.cuda' has been automatically added to the distribution only - because it may contain data files, but this behavior is likely to change - in future versions of setuptools (and therefore is considered deprecated). - - Please make sure that 'mmcv.ops.csrc.common.cuda' is included as a package by using - the `packages` configuration field or the proper discovery methods - (for example by using `find_namespace_packages(...)`/`find_namespace:` - instead of `find_packages(...)`/`find:`). - - You can read more about "package discovery" and "data files" on setuptools - documentation page. - - -!! - - check.warn(importable) -/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.common.mlu' as data is deprecated, please list it in `packages`. - !! - - - ############################ - # Package would be ignored # - ############################ - Python recognizes 'mmcv.ops.csrc.common.mlu' as an importable package, - but it is not listed in the `packages` configuration of setuptools. - - 'mmcv.ops.csrc.common.mlu' has been automatically added to the distribution only - because it may contain data files, but this behavior is likely to change - in future versions of setuptools (and therefore is considered deprecated). - - Please make sure that 'mmcv.ops.csrc.common.mlu' is included as a package by using - the `packages` configuration field or the proper discovery methods - (for example by using `find_namespace_packages(...)`/`find_namespace:` - instead of `find_packages(...)`/`find:`). - - You can read more about "package discovery" and "data files" on setuptools - documentation page. - - -!! - - check.warn(importable) -/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.pytorch' as data is deprecated, please list it in `packages`. - !! - - - ############################ - # Package would be ignored # - ############################ - Python recognizes 'mmcv.ops.csrc.pytorch' as an importable package, - but it is not listed in the `packages` configuration of setuptools. - - 'mmcv.ops.csrc.pytorch' has been automatically added to the distribution only - because it may contain data files, but this behavior is likely to change - in future versions of setuptools (and therefore is considered deprecated). - - Please make sure that 'mmcv.ops.csrc.pytorch' is included as a package by using - the `packages` configuration field or the proper discovery methods - (for example by using `find_namespace_packages(...)`/`find_namespace:` - instead of `find_packages(...)`/`find:`). - - You can read more about "package discovery" and "data files" on setuptools - documentation page. - - -!! - - check.warn(importable) -/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.pytorch.cpu' as data is deprecated, please list it in `packages`. - !! - - - ############################ - # Package would be ignored # - ############################ - Python recognizes 'mmcv.ops.csrc.pytorch.cpu' as an importable package, - but it is not listed in the `packages` configuration of setuptools. - - 'mmcv.ops.csrc.pytorch.cpu' has been automatically added to the distribution only - because it may contain data files, but this behavior is likely to change - in future versions of setuptools (and therefore is considered deprecated). - - Please make sure that 'mmcv.ops.csrc.pytorch.cpu' is included as a package by using - the `packages` configuration field or the proper discovery methods - (for example by using `find_namespace_packages(...)`/`find_namespace:` - instead of `find_packages(...)`/`find:`). - - You can read more about "package discovery" and "data files" on setuptools - documentation page. - - -!! - - check.warn(importable) -/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.pytorch.cuda' as data is deprecated, please list it in `packages`. - !! - - - ############################ - # Package would be ignored # - ############################ - Python recognizes 'mmcv.ops.csrc.pytorch.cuda' as an importable package, - but it is not listed in the `packages` configuration of setuptools. - - 'mmcv.ops.csrc.pytorch.cuda' has been automatically added to the distribution only - because it may contain data files, but this behavior is likely to change - in future versions of setuptools (and therefore is considered deprecated). - - Please make sure that 'mmcv.ops.csrc.pytorch.cuda' is included as a package by using - the `packages` configuration field or the proper discovery methods - (for example by using `find_namespace_packages(...)`/`find_namespace:` - instead of `find_packages(...)`/`find:`). - - You can read more about "package discovery" and "data files" on setuptools - documentation page. - - -!! - - check.warn(importable) -/opt/apps/local/lib64/python3/dist-packages/setuptools/command/build_py.py:202: SetuptoolsDeprecationWarning: Installing 'mmcv.ops.csrc.pytorch.mlu' as data is deprecated, please list it in `packages`. - !! - - - ############################ - # Package would be ignored # - ############################ - Python recognizes 'mmcv.ops.csrc.pytorch.mlu' as an importable package, - but it is not listed in the `packages` configuration of setuptools. - - 'mmcv.ops.csrc.pytorch.mlu' has been automatically added to the distribution only - because it may contain data files, but this behavior is likely to change - in future versions of setuptools (and therefore is considered deprecated). - - Please make sure that 'mmcv.ops.csrc.pytorch.mlu' is included as a package by using - the `packages` configuration field or the proper discovery methods - (for example by using `find_namespace_packages(...)`/`find_namespace:` - instead of `find_packages(...)`/`find:`). - - You can read more about "package discovery" and "data files" on setuptools - documentation page. - - -!! - - check.warn(importable) -/opt/apps/local/lib64/python3/dist-packages/torch/utils/cpp_extension.py:344: UserWarning: - - !! WARNING !! - -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -Your compiler (c++) is not compatible with the compiler Pytorch was -built with for this platform, which is g++ on linux. Please -use g++ to to compile your extension. Alternatively, you may -compile PyTorch from source using c++, and then you can also use -c++ to compile your extension. - -See https://github.com/pytorch/pytorch/blob/master/CONTRIBUTING.md for help -with compiling PyTorch from source. -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - !! WARNING !! - - platform=sys.platform)) -Emitting ninja build file /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/build.ninja... -Compiling objects... -Using envvar MAX_JOBS (256) as the number of workers... -[1/2] c++ -MMD -MF /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch/cuda/cudabind.o.d -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -DMMCV_WITH_CUDA -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/pytorch -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/common -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/common/cuda -I/opt/apps/local/lib64/python3/dist-packages/torch/include -I/opt/apps/local/lib64/python3/dist-packages/torch/include/torch/csrc/api/include -I/opt/apps/local/lib64/python3/dist-packages/torch/include/TH -I/opt/apps/local/lib64/python3/dist-packages/torch/include/THC -I/opt/sw_home/local/cuda/include -I/usr/local/include/python3.7m -c -c /home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp -o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch/cuda/cudabind.o -std=c++14 -DTORCH_API_INCLUDE_EXTENSION_H '-DPYBIND11_COMPILER_TYPE="_gcc"' '-DPYBIND11_STDLIB="_libstdcpp"' '-DPYBIND11_BUILD_ABI="_cxxabi1013"' -DTORCH_EXTENSION_NAME=_ext -D_GLIBCXX_USE_CXX11_ABI=0 -[2/2] c++ -MMD -MF /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch/pybind.o.d -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -DMMCV_WITH_CUDA -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/pytorch -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/common -I/home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/common/cuda -I/opt/apps/local/lib64/python3/dist-packages/torch/include -I/opt/apps/local/lib64/python3/dist-packages/torch/include/torch/csrc/api/include -I/opt/apps/local/lib64/python3/dist-packages/torch/include/TH -I/opt/apps/local/lib64/python3/dist-packages/torch/include/THC -I/opt/sw_home/local/cuda/include -I/usr/local/include/python3.7m -c -c /home/yongle.wu/study/mmrazor-tools/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp -o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/mmcv/ops/csrc/pytorch/pybind.o -std=c++14 -DTORCH_API_INCLUDE_EXTENSION_H '-DPYBIND11_COMPILER_TYPE="_gcc"' '-DPYBIND11_STDLIB="_libstdcpp"' '-DPYBIND11_BUILD_ABI="_cxxabi1013"' -DTORCH_EXTENSION_NAME=_ext -D_GLIBCXX_USE_CXX11_ABI=0 -g++ -pthread -shared /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/active_rotated_filter.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/assign_score_withk.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/ball_query.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/bbox_overlaps.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/bezier_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/border_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/box_iou_quadri.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/box_iou_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/carafe.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/carafe_naive.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/chamfer_distance.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/contour_expand.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/convex_iou.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/correlation.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/active_rotated_filter.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/bezier_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/box_iou_quadri.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/box_iou_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/deform_conv.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/modulated_deform_conv.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/nms.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/nms_quadri.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/nms_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/pixel_group.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/points_in_boxes.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/psamask.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/roi_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/roi_align_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/rotated_feature_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cpu/voxelization.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/active_rotated_filter_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/assign_score_withk_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/ball_query_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/bbox_overlaps_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/bezier_align_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/border_align_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/box_iou_quadri_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/box_iou_rotated_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/carafe_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/carafe_naive_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/chamfer_distance_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/convex_iou.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/correlation_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/cudabind.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/deform_conv_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/deform_roi_pool_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/diff_iou_rotated_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/focal_loss_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/fused_bias_leakyrelu_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/gather_points_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/group_points_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/iou3d_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/knn_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/masked_conv2d_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/min_area_polygons.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/modulated_deform_conv_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/ms_deform_attn_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/nms_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/nms_quadri_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/nms_rotated_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/points_in_boxes_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/points_in_polygons_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/prroi_pool_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/psamask_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/riroi_align_rotated_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/roi_align_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/roi_align_rotated_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/roi_pool_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/roiaware_pool3d_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/roipoint_pool3d_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/rotated_feature_align_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/scatter_points_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/stack_ball_query_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/stack_group_points_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/sync_bn_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/three_interpolate_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/tin_shift_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/upfirdn2d_kernel.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/cuda/voxelization_cuda.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/deform_conv.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/deform_roi_pool.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/diff_iou_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/focal_loss.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/furthest_point_sample.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/fused_bias_leakyrelu.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/fused_spconv_ops.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/gather_points.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/group_points.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/info.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/iou3d.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/knn.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/masked_conv2d.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/min_area_polygons.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/modulated_deform_conv.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/ms_deform_attn.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/nms.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/nms_quadri.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/nms_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/pixel_group.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/points_in_boxes.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/points_in_polygons.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/prroi_pool.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/psamask.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/pybind.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/riroi_align_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/roi_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/roi_align_rotated.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/roi_pool.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/roiaware_pool3d.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/roipoint_pool3d.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/rotated_feature_align.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/scatter_points.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/sync_bn.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/three_interpolate.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/tin_shift.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/upfirdn2d.o /home/yongle.wu/study/mmrazor-tools/mmcv/build/temp.linux-x86_64-cpython-37/./mmcv/ops/csrc/pytorch/voxelization.o -L/opt/apps/local/lib64/python3/dist-packages/torch/lib -L/opt/sw_home/local/cuda/lib64 -L/usr/local/lib -lc10 -ltorch -ltorch_cpu -ltorch_python -lcudart -lc10_cuda -ltorch_cuda -o build/lib.linux-x86_64-cpython-37/mmcv/_ext.cpython-37m-x86_64-linux-gnu.so diff --git a/cv/distiller/CWD/mmcv/docs/en/community/contributing.md b/cv/distiller/CWD/mmcv/docs/en/community/contributing.md index e33993577..5ac699302 100644 --- a/cv/distiller/CWD/mmcv/docs/en/community/contributing.md +++ b/cv/distiller/CWD/mmcv/docs/en/community/contributing.md @@ -238,7 +238,7 @@ We use the following tools for linting and formatting: Style configurations of yapf and isort can be found in [setup.cfg](./setup.cfg). We use [pre-commit hook](https://pre-commit.com/) that checks and formats for `flake8`, `yapf`, `isort`, `trailing whitespaces`, `markdown files`, -fixes `end-of-files`, `double-quoted-strings`, `python-encoding-pragma`, `mixed-line-ending`, sorts `requirments.txt` automatically on every commit. +fixes `end-of-files`, `float-quoted-strings`, `python-encoding-pragma`, `mixed-line-ending`, sorts `requirments.txt` automatically on every commit. The config for a pre-commit hook is stored in [.pre-commit-config](./.pre-commit-config.yaml). #### C++ and CUDA diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/community/contributing.md b/cv/distiller/CWD/mmcv/docs/zh_cn/community/contributing.md index e3aa781a5..a53dc3cb4 100644 --- a/cv/distiller/CWD/mmcv/docs/zh_cn/community/contributing.md +++ b/cv/distiller/CWD/mmcv/docs/zh_cn/community/contributing.md @@ -243,7 +243,7 @@ make html yapf å’Œ isort çš„é…ç½®å¯ä»¥åœ¨ [setup.cfg](./setup.cfg) 找到 通过é…ç½® [pre-commit hook](https://pre-commit.com/) ,我们å¯ä»¥åœ¨æäº¤ä»£ç æ—¶è‡ªåŠ¨æ£€æŸ¥å’Œæ ¼å¼åŒ– `flake8`ã€`yapf`ã€`isort`ã€`trailing whitespaces`ã€`markdown files`, -ä¿®å¤ `end-of-files`ã€`double-quoted-strings`ã€`python-encoding-pragma`ã€`mixed-line-ending`,调整 `requirments.txt` 的包顺åºã€‚ +ä¿®å¤ `end-of-files`ã€`float-quoted-strings`ã€`python-encoding-pragma`ã€`mixed-line-ending`,调整 `requirments.txt` 的包顺åºã€‚ pre-commit é’©å­çš„é…ç½®å¯ä»¥åœ¨ [.pre-commit-config](./.pre-commit-config.yaml) 找到。 pre-commit 具体的安装使用方å¼è§[拉å–请求](#2-é…ç½®-pre-commit)。 diff --git a/cv/distiller/CWD/mmcv/install_mmcv.sh b/cv/distiller/CWD/mmcv/install_mmcv.sh old mode 100644 new mode 100755 diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/__init__.py b/cv/distiller/CWD/mmcv/mmcv/ops/__init__.py index e3cb6fc60..b4081ed33 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/__init__.py +++ b/cv/distiller/CWD/mmcv/mmcv/ops/__init__.py @@ -95,8 +95,7 @@ __all__ = [ 'furthest_point_sample_with_dist', 'PointsSampler', 'Correlation', 'boxes_iou3d', 'boxes_iou_bev', 'boxes_overlap_bev', 'nms_bev', 'nms_normal_bev', 'nms3d', 'nms3d_normal', 'Voxelization', 'voxelization', - 'dynamic_scatter', 'DynamicScatter', 'RoIAwarePool3d', - 'points_in_boxes_part', + 'dynamic_scatter', 'DynamicScatter', 'RoIAwarePool3d', 'points_in_boxes_part', 'points_in_boxes_cpu', 'points_in_boxes_all', 'points_in_polygons', 'min_area_polygons', 'active_rotated_filter', 'convex_iou', 'convex_giou', 'diff_iou_rotated_2d', 'diff_iou_rotated_3d', 'chamfer_distance', diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp index a8453eaa8..e92ff5d68 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp @@ -56,9 +56,14 @@ template HOST_DEVICE_INLINE void get_rotated_vertices(const RotatedBox& box, Point (&pts)[4]) { // M_PI / 180. == 0.01745329251 - // double theta = box.a * 0.01745329251; + // float theta = box.a * 0.01745329251; // MODIFIED + // float theta = box.a; +#if defined(__ILUVATAR__) + float theta = box.a; +#else double theta = box.a; +#endif T cosTheta2 = (T)cos(theta) * 0.5f; T sinTheta2 = (T)sin(theta) * 0.5f; diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/carafe_cuda_kernel.cuh b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/carafe_cuda_kernel.cuh index f4bb12954..88f70f5ed 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/carafe_cuda_kernel.cuh +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/carafe_cuda_kernel.cuh @@ -8,7 +8,8 @@ #include "pytorch_cuda_helper.hpp" #endif -#ifdef MMCV_WITH_HIP +// #ifdef MMCV_WITH_HIP +#if defined(MMCV_WITH_HIP) || defined(__ILUVATAR__) #define WARP_SIZE 64 #else #define WARP_SIZE 32 @@ -29,8 +30,7 @@ __device__ inline int Loc2Index(const int n, const int c, const int h, int index = w + (h + (c + n * channel_num) * height) * width; return index; } -// #ifndef MMCV_WITH_HIP -#if defined(MMCV_WITH_HIP) || defined(__ILUVATAR__) +#ifndef MMCV_WITH_HIP /* TODO: move this to a common place */ template __device__ inline scalar_t min(scalar_t a, scalar_t b) { @@ -317,6 +317,7 @@ __global__ void CARAFEBackward_Mask(const int num_kernels, output_val += top_diff[top_id] * bottom_data[bottom_id]; } } +// #ifdef MMCV_WITH_HIP #if defined(MMCV_WITH_HIP) || defined(__ILUVATAR__) __syncthreads(); #else diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/common_cuda_helper.hpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/common_cuda_helper.hpp index e18036bac..9e544c79b 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/common_cuda_helper.hpp +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/common_cuda_helper.hpp @@ -2,6 +2,8 @@ #define COMMON_CUDA_HELPER #include +#include +using namespace std; #define CUDA_1D_KERNEL_LOOP(i, n) \ for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < (n); \ diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/convex_iou_cuda_kernel.cuh b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/convex_iou_cuda_kernel.cuh index 2af96f796..9dc42bad6 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/convex_iou_cuda_kernel.cuh +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/convex_iou_cuda_kernel.cuh @@ -10,14 +10,14 @@ #define MAXN 100 #define NMAX 512 -__device__ const double EPS = 1E-8; +__device__ const float EPS = 1E-8; -__device__ inline int sig(double d) { return (d > EPS) - (d < -EPS); } +__device__ inline int sig(float d) { return (d > EPS) - (d < -EPS); } struct Point { - double x, y; + float x, y; __device__ Point() {} - __device__ Point(double x, double y) : x(x), y(y) {} + __device__ Point(float x, float y) : x(x), y(y) {} }; __device__ inline bool point_same(Point& a, Point& b) { @@ -44,27 +44,27 @@ __device__ inline void reverse1(Point* a, const int n) { } } -__device__ inline double cross(Point o, Point a, Point b) { +__device__ inline float cross(Point o, Point a, Point b) { return (a.x - o.x) * (b.y - o.y) - (b.x - o.x) * (a.y - o.y); } -__device__ inline double dis(Point a, Point b) { +__device__ inline float dis(Point a, Point b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); } -__device__ inline double area(Point* ps, int n) { +__device__ inline float area(Point* ps, int n) { ps[n] = ps[0]; - double res = 0; + float res = 0; for (int i = 0; i < n; i++) { res += ps[i].x * ps[i + 1].y - ps[i].y * ps[i + 1].x; } return res / 2.0; } -__device__ inline double polygon_area_grad(Point* ps, int n, +__device__ inline float polygon_area_grad(Point* ps, int n, int* polygon_to_pred_index, - int n_pred, double* grad_C) { + int n_pred, float* grad_C) { ps[n] = ps[0]; - double partion_grad[4 * 30 + 2]; - double res = 0; + float partion_grad[4 * 30 + 2]; + float res = 0; for (int i = 0; i < n; i++) { res += ps[i].x * ps[i + 1].y - ps[i].y * ps[i + 1].x; partion_grad[i * 4 + 2] = ps[i + 1].y; @@ -98,11 +98,11 @@ __device__ inline double polygon_area_grad(Point* ps, int n, } __device__ inline int lineCross(Point a, Point b, Point c, Point d, Point& p, - double* cut_grad, int m, int n, int i) { - double s1, s2; - double s2_s1_2; - double ds1_dxc, ds1_dyc, ds2_dxd, ds2_dyd; - double dxp_dxc, dxp_dyc, dxp_dxd, dxp_dyd, dyp_dxc, dyp_dyc, dyp_dxd, dyp_dyd; + float* cut_grad, int m, int n, int i) { + float s1, s2; + float s2_s1_2; + float ds1_dxc, ds1_dyc, ds2_dxd, ds2_dyd; + float dxp_dxc, dxp_dyc, dxp_dxd, dxp_dyd, dyp_dxc, dyp_dyc, dyp_dxd, dyp_dyd; s1 = cross(a, b, c); s2 = cross(a, b, d); @@ -166,9 +166,9 @@ __device__ inline int lineCross(Point a, Point b, Point c, Point d, Point& p, return 1; } __device__ inline void polygon_cut(Point* p, int& n, Point a, Point b, - double* cut_grad) { + float* cut_grad) { Point pp[MAXN]; - double ccur_grad[MAXN] = {}; + float ccur_grad[MAXN] = {}; int m = 0; p[n] = p[0]; int k = n; @@ -199,8 +199,8 @@ __device__ inline void polygon_cut(Point* p, int& n, Point a, Point b, while (n > 1 && point_same(p[n - 1], p[0])) n--; } -__device__ inline double intersectArea(Point a, Point b, Point c, Point d, - double* grad_AB, int order, +__device__ inline float intersectArea(Point a, Point b, Point c, Point d, + float* grad_AB, int order, int convex_n) { Point o(0, 0); int res_flag = 0; @@ -220,15 +220,15 @@ __device__ inline double intersectArea(Point a, Point b, Point c, Point d, } Point p[10] = {o, a, b}; int n = 3, n0 = 3, n1, n2, n3; - double cut_grad1[MAXN] = {}; - double cut_grad2[MAXN] = {}; - double cut_grad3[MAXN] = {}; - double p1_p_grad[10][10] = {}; - double p2_p1_grad[10][10] = {}; - double p3_p2_grad[10][10] = {}; + float cut_grad1[MAXN] = {}; + float cut_grad2[MAXN] = {}; + float cut_grad3[MAXN] = {}; + float p1_p_grad[10][10] = {}; + float p2_p1_grad[10][10] = {}; + float p3_p2_grad[10][10] = {}; - double p3_p1_grad[10][10] = {}; - double p3_p_grad[10][10] = {}; + float p3_p1_grad[10][10] = {}; + float p3_p_grad[10][10] = {}; // 1 polygon_cut(p, n, o, c, cut_grad1); @@ -272,7 +272,7 @@ __device__ inline double intersectArea(Point a, Point b, Point c, Point d, // p3_p2(n3 * n2) * p2_p1(n2 * n1) = p3_p1 (n3 * n1) for (int i = 0; i < 2 * n3; i++) { for (int j = 0; j < 2 * n1; j++) { - double sum = 0.0; + float sum = 0.0; for (int m = 0; m < 2 * n2; m++) { sum = sum + p3_p2_grad[i][m] * p2_p1_grad[m][j]; } @@ -283,7 +283,7 @@ __device__ inline double intersectArea(Point a, Point b, Point c, Point d, // p3_p1 (n3 * n1) * p1_p (n1 * n0) = p3_p (n3 * n0) for (int i = 0; i < 2 * n3; i++) { for (int j = 0; j < 2 * n0; j++) { - double sum = 0.0; + float sum = 0.0; for (int m = 0; m < 2 * n1; m++) { sum = sum + p3_p1_grad[i][m] * p1_p_grad[m][j]; } @@ -293,20 +293,20 @@ __device__ inline double intersectArea(Point a, Point b, Point c, Point d, // calculate S_grad int polygon_index_box_index[20]; - double grad_polygon[20]; - double S_grad[6]; + float grad_polygon[20]; + float S_grad[6]; for (int i = 0; i < n3; i++) { polygon_index_box_index[i] = i; polygon_index_box_index[i + n3] = i; } - double res = + float res = polygon_area_grad(p, n3, polygon_index_box_index, n3, grad_polygon); if (s1 * s2 == -1) { for (int j = 0; j < 2 * 3; j++) { - double sum = 0.0; + float sum = 0.0; for (int m = 0; m < 2 * n3; m++) { sum = sum - grad_polygon[m] * p3_p_grad[m][j]; } @@ -343,7 +343,7 @@ __device__ inline double intersectArea(Point a, Point b, Point c, Point d, res = -res; } else { for (int j = 0; j < 2 * 3; j++) { - double sum = 0.0; + float sum = 0.0; for (int m = 0; m < 2 * n3; m++) { sum = sum + grad_polygon[m] * p3_p_grad[m][j]; } @@ -379,13 +379,13 @@ __device__ inline double intersectArea(Point a, Point b, Point c, Point d, return res; } -__device__ inline double intersectAreaO(Point* ps1, int n1, Point* ps2, int n2, - double* grad_AB) { +__device__ inline float intersectAreaO(Point* ps1, int n1, Point* ps2, int n2, + float* grad_AB) { if (area(ps1, n1) < 0) reverse1(ps1, n1); if (area(ps2, n2) < 0) reverse1(ps2, n2); ps1[n1] = ps1[0]; ps2[n2] = ps2[0]; - double res = 0; + float res = 0; for (int i = 0; i < n1; i++) { for (int j = 0; j < n2; j++) { res += @@ -399,7 +399,7 @@ __device__ inline void Jarvis(Point* in_poly, int& n_poly) { Point p_max, p_k; int max_index, k_index; int Stack[NMAX] = {}, top1, top2; - double sign; + float sign; Point right_point[10], left_point[10]; for (int i = 0; i < n_poly; i++) { @@ -470,8 +470,8 @@ __device__ inline void Jarvis(Point* in_poly, int& n_poly) { n_poly = top1 + top2; } -__device__ inline double intersectAreaPoly(Point* ps1, int n1, Point* ps2, - int n2, double* grad_C) { +__device__ inline float intersectAreaPoly(Point* ps1, int n1, Point* ps2, + int n2, float* grad_C) { Point polygon[MAXN]; int n = n1 + n2, n_poly = 0; for (int i = 0; i < n1; i++) { @@ -510,13 +510,13 @@ __device__ inline double intersectAreaPoly(Point* ps1, int n1, Point* ps2, } } if (n_pred == 0) { - double polygon_area = fabs(area(polygon, n_poly)); + float polygon_area = fabs(area(polygon, n_poly)); for (int i = 0; i < 18; i++) { grad_C[i] = 0.0; } return polygon_area; } else { - double polygon_area = + float polygon_area = polygon_area_grad(polygon, n_poly, polygon_to_pred_index, n1, grad_C); if (polygon_area < 0) { for (int i = 0; i < 18; i++) { @@ -539,7 +539,7 @@ __device__ inline void Jarvis_and_index(Point* in_poly, int& n_poly, Point p_max, p_k; int max_index, k_index; int Stack[20], top1, top2; - double sign; + float sign; Point right_point[10], left_point[10]; for (int i = 0; i < n_poly; i++) { @@ -629,8 +629,8 @@ __device__ inline float devrIoU(T const* const p, T const* const q, Point convex[MAXN]; for (int i = 0; i < 9; i++) { - convex[i].x = (double)p[i * 2]; - convex[i].y = (double)p[i * 2 + 1]; + convex[i].x = (float)p[i * 2]; + convex[i].y = (float)p[i * 2 + 1]; } int n_convex = 9; int points_to_convex_ind[9] = {-1, -1, -1, -1, -1, -1, -1, -1, -1}; @@ -640,13 +640,13 @@ __device__ inline float devrIoU(T const* const p, T const* const q, int n2 = 4; for (int i = 0; i < n1; i++) { - ps1[i].x = (double)convex[i].x; - ps1[i].y = (double)convex[i].y; + ps1[i].x = (float)convex[i].x; + ps1[i].y = (float)convex[i].y; } for (int i = 0; i < n2; i++) { - ps2[i].x = (double)q[i * 2]; - ps2[i].y = (double)q[i * 2 + 1]; + ps2[i].x = (float)q[i * 2]; + ps2[i].y = (float)q[i * 2 + 1]; } int polygon_index_box_index[18]; @@ -655,25 +655,25 @@ __device__ inline float devrIoU(T const* const p, T const* const q, polygon_index_box_index[i + n1] = i; } - double grad_A[18] = {}; - double grad_AB[18] = {}; - double grad_C[18] = {}; + float grad_A[18] = {}; + float grad_AB[18] = {}; + float grad_C[18] = {}; - double inter_area = intersectAreaO(ps1, n1, ps2, n2, grad_AB); - double S_pred = + float inter_area = intersectAreaO(ps1, n1, ps2, n2, grad_AB); + float S_pred = polygon_area_grad(ps1, n1, polygon_index_box_index, n1, grad_A); if (S_pred < 0) { for (int i = 0; i < n_convex * 2; i++) { grad_A[i] = -grad_A[i]; } } - double union_area = fabs(S_pred) + fabs(area(ps2, n2)) - inter_area; + float union_area = fabs(S_pred) + fabs(area(ps2, n2)) - inter_area; - double iou = inter_area / union_area; - double polygon_area = intersectAreaPoly(ps1, n1, ps2, n2, grad_C); + float iou = inter_area / union_area; + float polygon_area = intersectAreaPoly(ps1, n1, ps2, n2, grad_C); // printf("%d:live\n", idx); - double rot_giou = iou - (polygon_area - union_area) / polygon_area; + float rot_giou = iou - (polygon_area - union_area) / polygon_area; float grad_point_temp[18] = {}; @@ -714,7 +714,7 @@ __global__ void convex_giou_cuda_kernel(const int ex_n_boxes, } __device__ inline int lineCross(Point a, Point b, Point c, Point d, Point& p) { - double s1, s2; + float s1, s2; s1 = cross(a, b, c); s2 = cross(a, b, d); if (sig(s1) == 0 && sig(s2) == 0) return 2; @@ -749,7 +749,7 @@ __device__ inline void polygon_cut(Point* p, int& n, Point a, Point b) { while (n > 1 && point_same(p[n - 1], p[0])) n--; } -__device__ inline double intersectArea(Point a, Point b, Point c, Point d) { +__device__ inline float intersectArea(Point a, Point b, Point c, Point d) { Point o(0, 0); int s1 = sig(cross(o, a, b)); int s2 = sig(cross(o, c, d)); @@ -770,17 +770,17 @@ __device__ inline double intersectArea(Point a, Point b, Point c, Point d) { polygon_cut(p, n, o, c); polygon_cut(p, n, c, d); polygon_cut(p, n, d, o); - double res = area(p, n); + float res = area(p, n); if (s1 * s2 == -1) res = -res; return res; } -__device__ inline double intersectAreaO(Point* ps1, int n1, Point* ps2, +__device__ inline float intersectAreaO(Point* ps1, int n1, Point* ps2, int n2) { if (area(ps1, n1) < 0) reverse1(ps1, n1); if (area(ps2, n2) < 0) reverse1(ps2, n2); ps1[n1] = ps1[0]; ps2[n2] = ps2[0]; - double res = 0; + float res = 0; for (int i = 0; i < n1; i++) { for (int j = 0; j < n2; j++) { res += intersectArea(ps1[i], ps1[i + 1], ps2[j], ps2[j + 1]); @@ -794,26 +794,26 @@ __device__ inline float devrIoU(T const* const p, T const* const q) { Point ps1[MAXN], ps2[MAXN]; Point convex[MAXN]; for (int i = 0; i < 9; i++) { - convex[i].x = (double)p[i * 2]; - convex[i].y = (double)p[i * 2 + 1]; + convex[i].x = (float)p[i * 2]; + convex[i].y = (float)p[i * 2 + 1]; } int n_convex = 9; int points_to_convex_ind[9] = {-1, -1, -1, -1, -1, -1, -1, -1, -1}; Jarvis_and_index(convex, n_convex, points_to_convex_ind); int n1 = n_convex; for (int i = 0; i < n1; i++) { - ps1[i].x = (double)convex[i].x; - ps1[i].y = (double)convex[i].y; + ps1[i].x = (float)convex[i].x; + ps1[i].y = (float)convex[i].y; } int n2 = 4; for (int i = 0; i < n2; i++) { - ps2[i].x = (double)q[i * 2]; - ps2[i].y = (double)q[i * 2 + 1]; + ps2[i].x = (float)q[i * 2]; + ps2[i].y = (float)q[i * 2 + 1]; } - double inter_area = intersectAreaO(ps1, n1, ps2, n2); - double S_pred = area(ps1, n1); - double union_area = fabs(S_pred) + fabs(area(ps2, n2)) - inter_area; - double iou = inter_area / union_area; + float inter_area = intersectAreaO(ps1, n1, ps2, n2); + float S_pred = area(ps1, n1); + float union_area = fabs(S_pred) + fabs(area(ps2, n2)) - inter_area; + float iou = inter_area / union_area; return (float)iou; } diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/diff_iou_rotated_cuda_kernel.cuh b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/diff_iou_rotated_cuda_kernel.cuh index b2b071bc8..d30a1a734 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/diff_iou_rotated_cuda_kernel.cuh +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/diff_iou_rotated_cuda_kernel.cuh @@ -12,7 +12,7 @@ #define EPSILON 1e-8 inline int opt_n_thread(int work_size) { - const int pow_2 = std::log(static_cast(work_size)) / std::log(2.0); + const int pow_2 = std::log(static_cast(work_size)) / std::log(2.0); return std::max(std::min(1 << pow_2, THREADS_PER_BLOCK), 1); } diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/iou3d_cuda_kernel.cuh b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/iou3d_cuda_kernel.cuh index 9ebdcad15..46e7c7d0a 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/iou3d_cuda_kernel.cuh +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/iou3d_cuda_kernel.cuh @@ -15,7 +15,7 @@ __device__ const float EPS = 1e-8; struct Point { float x, y; __device__ Point() {} - __device__ Point(double _x, double _y) { x = _x, y = _y; } + __device__ Point(float _x, float _y) { x = _x, y = _y; } __device__ void set(float _x, float _y) { x = _x; diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/min_area_polygons_cuda.cuh b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/min_area_polygons_cuda.cuh index df56e7436..b8e3b426d 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/min_area_polygons_cuda.cuh +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/min_area_polygons_cuda.cuh @@ -56,9 +56,9 @@ __device__ inline void minBoundingRect(Point *ps, int n_points, float *minbox) { edges[i].y = ps[i + 1].y - ps[i].y; } for (int i = 0; i < n_edges; i++) { - edges_angles[i] = atan2((double)edges[i].y, (double)edges[i].x); + edges_angles[i] = atan2((float)edges[i].y, (float)edges[i].x); if (edges_angles[i] >= 0) { - edges_angles[i] = fmod((double)edges_angles[i], (double)PI / 2); + edges_angles[i] = fmod((float)edges_angles[i], (float)PI / 2); } else { edges_angles[i] = edges_angles[i] - (int)(edges_angles[i] / (PI / 2) - 1) * (PI / 2); @@ -169,7 +169,7 @@ __device__ inline void Jarvis(Point *in_poly, int &n_poly) { int max_index, k_index; int Stack[20], top1, top2; // float sign; - double sign; + float sign; Point right_point[10], left_point[10]; for (int i = 0; i < n_poly; i++) { diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/scatter_points_cuda_kernel.cuh b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/scatter_points_cuda_kernel.cuh index 7a018553c..bc2f7a587 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/scatter_points_cuda_kernel.cuh +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/scatter_points_cuda_kernel.cuh @@ -36,6 +36,7 @@ __device__ __forceinline__ static void reduceMax(double *address, double val) { // get rid of meaningless warnings when compiling host code // #ifdef MMCV_WITH_HIP #if defined(MMCV_WITH_HIP) || defined(__ILUVATAR__) + __device__ __forceinline__ static void reduceAdd(float *address, float val) { atomicAdd(address, val); } diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/three_nn_cuda_kernel.cuh b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/three_nn_cuda_kernel.cuh new file mode 100644 index 000000000..f6b91f9c2 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/three_nn_cuda_kernel.cuh @@ -0,0 +1,72 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef THREE_NN_CUDA_KERNEL_CUH +#define THREE_NN_CUDA_KERNEL_CUH + +#ifdef MMCV_USE_PARROTS +#include "parrots_cuda_helper.hpp" +#else +#include "pytorch_cuda_helper.hpp" +#endif + +template +__global__ void three_nn_forward_cuda_kernel(int b, int n, int m, + const T *unknown, const T *known, + T *dist2, int *__restrict__ idx) { + // unknown: (B, N, 3) + // known: (B, M, 3) + // output: + // dist2: (B, N, 3) + // idx: (B, N, 3) + + int bs_idx = blockIdx.y; + CUDA_1D_KERNEL_LOOP(pt_idx, n) { + if (bs_idx >= b) return; + + unknown += bs_idx * n * 3 + pt_idx * 3; + known += bs_idx * m * 3; + dist2 += bs_idx * n * 3 + pt_idx * 3; + idx += bs_idx * n * 3 + pt_idx * 3; + + T ux = unknown[0]; + T uy = unknown[1]; + T uz = unknown[2]; +#if defined(__ILUVATAR__) + //float max: 3.4e38 + float best1 = 3e38, best2 = 3e38, best3 = 3e38; +#else + float best1 = 1e40, best2 = 1e40, best3 = 1e40; +#endif + + int besti1 = 0, besti2 = 0, besti3 = 0; + for (int k = 0; k < m; ++k) { + T x = known[k * 3 + 0]; + T y = known[k * 3 + 1]; + T z = known[k * 3 + 2]; + T d = (ux - x) * (ux - x) + (uy - y) * (uy - y) + (uz - z) * (uz - z); + if (d < best1) { + best3 = best2; + besti3 = besti2; + best2 = best1; + besti2 = besti1; + best1 = d; + besti1 = k; + } else if (d < best2) { + best3 = best2; + besti3 = besti2; + best2 = d; + besti2 = k; + } else if (d < best3) { + best3 = d; + besti3 = k; + } + } + dist2[0] = best1; + dist2[1] = best2; + dist2[2] = best3; + idx[0] = besti1; + idx[1] = besti2; + idx[2] = besti3; + } +} + +#endif // THREE_NN_CUDA_KERNEL_CUH diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSDevice.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSDevice.h new file mode 100644 index 000000000..e1d9d4961 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSDevice.h @@ -0,0 +1,64 @@ +// Copyright © 2022 Apple Inc. + +// This file is modify from: +// https://github.com/pytorch/pytorch/blob/a85d1f0bcdd02cf18d3b0517337458cb51a18cdb/aten/src/ATen/mps/MPSDevice.h + +#pragma once +#include +#include +#include + +#ifdef __OBJC__ +#include +#include +#include +typedef id MTLDevice_t; +#else +typedef void* MTLDevice; +typedef void* MTLDevice_t; +#endif + +using namespace std; + +namespace at { +namespace mps { + +//----------------------------------------------------------------- +// MPSDevice +// +// MPSDevice is a singleton class that returns the default device +//----------------------------------------------------------------- + +class TORCH_API MPSDevice { + public: + /** + * MPSDevice should not be cloneable. + */ + MPSDevice(MPSDevice& other) = delete; + /** + * MPSDevice should not be assignable. + */ + void operator=(const MPSDevice&) = delete; + /** + * Gets single instance of the Device. + */ + static MPSDevice* getInstance(); + /** + * Returns the single device. + */ + MTLDevice_t device() { return _mtl_device; } + + ~MPSDevice(); + + private: + static MPSDevice* _device; + MTLDevice_t _mtl_device; + MPSDevice(); +}; + +TORCH_API bool is_available(); + +TORCH_API at::Allocator* GetMPSAllocator(bool useSharedAllocator = false); + +} // namespace mps +} // namespace at diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.h new file mode 100644 index 000000000..41c33fba8 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.h @@ -0,0 +1,61 @@ +#ifndef _MPS_LIBRARY_H_ +#define _MPS_LIBRARY_H_ + +#include +#include + +#ifdef __OBJC__ +#include +#include +#include + +typedef id MTLComputePipelineState_t; +typedef id MTLLibrary_t; +#else +typedef void* MTLComputePipelineState; +typedef void* MTLComputePipelineState_t; +typedef void* MTLLibrary; +typedef void* MTLLibrary_t; +#endif + +class MPSLibrary { + public: + // disable constructor for singleton + static MPSLibrary* createFromUrl(const std::string& library_url); + static MPSLibrary* createFromSource(const std::string& source); + ~MPSLibrary(); + + MTLLibrary_t library() { return _library; } + + MTLComputePipelineState_t getComputePipelineState( + const std::string& function_name); + + private: + MTLLibrary_t _library; + std::unordered_map _pso_map; +}; + +class MPSLibraryManager { + public: + // disable constructor for singleton + MPSLibraryManager(const MPSLibraryManager&) = delete; + MPSLibraryManager& operator=(const MPSLibraryManager&) = delete; + MPSLibraryManager(MPSLibraryManager&&) = delete; + MPSLibraryManager& operator=(MPSLibraryManager&&) = delete; + + static MPSLibraryManager* getInstance(); + + bool hasLibrary(const std::string& name); + + MPSLibrary* getLibrary(const std::string& library_url); + + MPSLibrary* createLibraryFromSouce(const std::string& name, + const std::string& sources); + + ~MPSLibraryManager(); + + private: + MPSLibraryManager(); + std::unordered_map> _library_map; +}; +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.mm b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.mm new file mode 100644 index 000000000..99addc7e2 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.mm @@ -0,0 +1,107 @@ +#include "MPSLibrary.h" +#include "MPSDevice.h" + +static std::unique_ptr mps_library_manager=nullptr; + +MPSLibraryManager* MPSLibraryManager::getInstance() { + if(!mps_library_manager) + mps_library_manager = std::unique_ptr(new MPSLibraryManager()); + return mps_library_manager.get(); +} + +MPSLibraryManager::~MPSLibraryManager() {} + +MPSLibraryManager::MPSLibraryManager() {} + +bool MPSLibraryManager::hasLibrary(const std::string& name) { + return _library_map.find(name) != _library_map.end(); +} + +MPSLibrary* MPSLibraryManager::getLibrary(const std::string& library_url) { + if (_library_map.find(library_url) != _library_map.end()) { + return _library_map[library_url].get(); + } + _library_map.emplace(std::make_pair( + library_url, std::unique_ptr(MPSLibrary::createFromUrl(library_url)))); + return _library_map[library_url].get(); +} + +MPSLibrary* MPSLibraryManager::createLibraryFromSouce(const std::string& name, + const std::string& source) { + NSString* ns_name = [NSString stringWithCString:name.c_str()]; + if (_library_map.find(name) != _library_map.end()) { + NSLog(@"Library %@ already exist.", ns_name); + return nullptr; + } + + _library_map.emplace( + std::make_pair(name, std::unique_ptr(MPSLibrary::createFromSource(source)))); + return _library_map[name].get(); +} + +MPSLibrary* MPSLibrary::createFromUrl(const std::string& library_url) { + MPSLibrary* library = new MPSLibrary(); + @autoreleasepool { + NSError* error = nil; + + // load library and func + NSString* utl_str = [NSString stringWithCString:library_url.c_str()]; + NSURL* metal_url = [NSURL fileURLWithPath:utl_str]; + library->_library = [at::mps::MPSDevice::getInstance()->device() newLibraryWithURL:metal_url + error:&error]; + if (library->_library == nil) { + NSLog(@"Failed to find library, error %@.", error); + exit(1); + } + } + + return library; +} + +MPSLibrary* MPSLibrary::createFromSource(const std::string& sources) { + MPSLibrary* library = new MPSLibrary(); + @autoreleasepool { + NSError* error = nil; + + // load library and func + NSString* code_str = [NSString stringWithCString:sources.c_str()]; + library->_library = [at::mps::MPSDevice::getInstance()->device() newLibraryWithSource:code_str + options:nil + error:&error]; + if (library->_library == nil) { + NSLog(@"Failed to find library, error %@.", error); + exit(1); + } + } + + return library; +} + +MPSLibrary::~MPSLibrary() { + [_library release]; + _library = nil; +} + +MTLComputePipelineState_t MPSLibrary::getComputePipelineState(const std::string& function_name) { + if (_pso_map.find(function_name) != _pso_map.end()) { + return _pso_map[function_name]; + } + + MTLComputePipelineState_t pso; + @autoreleasepool { + NSError* error = nil; + + // create function + NSString* function_name_str = [NSString stringWithCString:function_name.c_str()]; + id func = [_library newFunctionWithName:function_name_str]; + if (func == nil) { + NSLog(@"Failed to created pipeline state object, error %@.", error); + exit(1); + } + // create pipeline + pso = [at::mps::MPSDevice::getInstance()->device() newComputePipelineStateWithFunction:func + error:&error]; + _pso_map.emplace(std::make_pair(function_name, pso)); + } + return _pso_map[function_name]; +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSStream.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSStream.h new file mode 100644 index 000000000..54cd38849 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSStream.h @@ -0,0 +1,132 @@ +// Copyright © 2022 Apple Inc. + +// This file is modify from: +// https://github.com/pytorch/pytorch/blob/a85d1f0bcdd02cf18d3b0517337458cb51a18cdb/aten/src/ATen/mps/MPSStream.h + +#pragma once + +#include +#include + +#include +#include +#include +#include "MPSDevice.h" + +#ifdef __OBJC__ +#include +#include +#include +#include +typedef id MTLCommandQueue_t; +typedef id MTLCommandBuffer_t; +typedef id MTLSharedEvent_t; +typedef id MTLDevice_t; +#else +typedef void* MTLCommandQueue_t; +typedef void* MTLCommandQueue; +typedef void* MTLCommandBuffer_t; +typedef void* MTLCommandBuffer; +typedef void* MTLSharedEvent_t; +typedef void* dispatch_queue_t; +typedef void* MTLDevice_t; +#define nil NULL; +#endif + +namespace at { +namespace mps { + +//----------------------------------------------------------------- +// MPSStream +//----------------------------------------------------------------- + +class TORCH_API MPSStream { + public: + enum Unchecked { UNCHECKED }; + /// Construct a MPSStream from a Stream. This construction is checked, + /// and will raise an error if the Stream is not, in fact, a MPS stream. + explicit MPSStream(Stream stream); + + ~MPSStream(); + MTLCommandQueue_t commandQueue() const { return _commandQueue; }; + dispatch_queue_t queue() const { return _serialQueue; } + + MTLCommandBuffer_t commandBuffer(); + void commit(bool flush); + void commitAndWait(); + void synchronize(); + + void flush(); + + /// Get the MPS device index that this stream is associated with. + c10::DeviceIndex device_index() const { return _stream.device_index(); } + + MTLCommandQueue_t stream() const { return _commandQueue; }; + + MTLDevice_t device() const { return [_commandQueue device]; } + + /// Explicit conversion to Stream. + Stream unwrap() const { return _stream; } + + private: + Stream _stream; + MTLCommandQueue_t _commandQueue = nil; + MTLCommandBuffer_t _commandBuffer = nil; + void _flush(bool commitAndWait) const; + + dispatch_queue_t _serialQueue = nullptr; +}; + +/** + * Get the current MPS stream + */ +TORCH_API MPSStream* getCurrentMPSStream(); + +/** + * Get the default MPS stream + */ +TORCH_API MPSStream* getDefaultMPSStream(); + +//----------------------------------------------------------------- +// MPSStreamImpl +//----------------------------------------------------------------- + +class TORCH_API MPSStreamImpl { + public: + /** + * Gets single instance of the MPSStream. + */ + static MPSStream* getInstance(); + + private: + static MPSStream* _stream; + MPSStreamImpl(); +}; + +//----------------------------------------------------------------- +// MPSEvent +//----------------------------------------------------------------- + +struct TORCH_API MPSEvent { + MPSEvent(); + // MPSEvent(id device); + + ~MPSEvent(); + MTLSharedEvent_t event() const { return _event; } + + void recordEvent(MPSStream* stream); + void waitForEvent(MPSStream* queue); // waits on the cpu + bool queryEvent(); + uint64_t getCurrentValue() { return _currentValue; } + void setCurrentValue(uint64_t currValue) { _currentValue = currValue; } + + private: + bool _isRecorded = false; + uint64_t _currentValue = 0; + MTLSharedEvent_t _event; +}; + +typedef MPSEvent* mpsEvent_t; + +} // namespace mps +} // namespace at diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSUtils.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSUtils.h new file mode 100644 index 000000000..2a4ce6d79 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSUtils.h @@ -0,0 +1,51 @@ +#ifndef _MPS_UTILS_H_ +#define _MPS_UTILS_H_ +#include +#ifdef __OBJC__ +#include +#include +#include + +typedef id MTLBuffer_t; +typedef id MTLComputeCommandEncoder_t; +#else +typedef void* MTLBuffer; +typedef void* MTLBuffer_t; +typedef void* MTLComputeCommandEncoder; +typedef void* MTLComputeCommandEncoder_t; +#endif + +// utils +static inline MTLBuffer_t getMTLBufferStorage(const at::Tensor& tensor) { + return __builtin_bit_cast(MTLBuffer_t, tensor.storage().data()); +} + +template , at::Tensor>::value, bool> = true> +void setMTLArg(MTLComputeCommandEncoder_t encoder, int index, T&& t); + +template , at::Tensor>::value, bool> = true> +void setMTLArg(MTLComputeCommandEncoder_t encoder, int index, T&& t) { + [encoder setBuffer:getMTLBufferStorage(t) offset:0 atIndex:index]; +} + +template , at::Tensor>::value, bool>> +void setMTLArg(MTLComputeCommandEncoder_t encoder, int index, T&& t) { + [encoder setBytes:&t length:sizeof(t) atIndex:index]; +} + +inline void setMTLArgsImpl(MTLComputeCommandEncoder_t, int) {} + +template +void setMTLArgsImpl(MTLComputeCommandEncoder_t encoder, int index, T&& t, Args&&... args) { + setMTLArg(encoder, index, std::forward(t)); + setMTLArgsImpl(encoder, index + 1, std::forward(args)...); +} + +template +void setMTLArgs(MTLComputeCommandEncoder_t encoder, MTLComputePipelineState_t pso, Args&&... args) { + [encoder setComputePipelineState:pso]; + setMTLArgsImpl(encoder, 0, std::forward(args)...); +} +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cpp_helper.hpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cpp_helper.hpp index 72701890d..d95d7221b 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cpp_helper.hpp +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cpp_helper.hpp @@ -18,7 +18,7 @@ using namespace parrots; [&] { \ const auto& the_type = TYPE; \ switch (the_type) { \ - PARROTS_PRIVATE_CASE_TYPE(Prim::Float64, double, __VA_ARGS__) \ + PARROTS_PRIVATE_CASE_TYPE(Prim::Float64, float, __VA_ARGS__) \ PARROTS_PRIVATE_CASE_TYPE(Prim::Float32, float, __VA_ARGS__) \ default: \ PARROTS_NOTSUPPORTED; \ @@ -29,7 +29,7 @@ using namespace parrots; [&] { \ const auto& the_type = TYPE; \ switch (the_type) { \ - PARROTS_PRIVATE_CASE_TYPE(Prim::Float64, double, __VA_ARGS__) \ + PARROTS_PRIVATE_CASE_TYPE(Prim::Float64, float, __VA_ARGS__) \ PARROTS_PRIVATE_CASE_TYPE(Prim::Float32, float, __VA_ARGS__) \ PARROTS_PRIVATE_CASE_TYPE(Prim::Float16, float16, __VA_ARGS__) \ default: \ diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cuda_helper.hpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cuda_helper.hpp index 539009c3f..45aea02eb 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cuda_helper.hpp +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cuda_helper.hpp @@ -40,7 +40,7 @@ using phalf = float16; [&] { \ const auto& the_type = TYPE; \ switch (the_type) { \ - PARROTS_PRIVATE_CASE_TYPE(Prim::Float64, double, __VA_ARGS__) \ + PARROTS_PRIVATE_CASE_TYPE(Prim::Float64, float, __VA_ARGS__) \ PARROTS_PRIVATE_CASE_TYPE(Prim::Float32, float, __VA_ARGS__) \ default: \ PARROTS_NOTSUPPORTED; \ @@ -51,7 +51,7 @@ using phalf = float16; [&] { \ const auto& the_type = TYPE; \ switch (the_type) { \ - PARROTS_PRIVATE_CASE_TYPE(Prim::Float64, double, __VA_ARGS__) \ + PARROTS_PRIVATE_CASE_TYPE(Prim::Float64, float, __VA_ARGS__) \ PARROTS_PRIVATE_CASE_TYPE(Prim::Float32, float, __VA_ARGS__) \ PARROTS_PRIVATE_CASE_TYPE(Prim::Float16, float16, __VA_ARGS__) \ default: \ @@ -62,16 +62,16 @@ using phalf = float16; /** atomicAdd **/ #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 600 -static __inline__ __device__ double atomicAdd(double* address, double val) { +static __inline__ __device__ float atomicAdd(float* address, float val) { unsigned long long int* address_as_ull = (unsigned long long int*)address; unsigned long long int old = *address_as_ull, assumed; - if (val == 0.0) return __longlong_as_double(old); + if (val == 0.0) return __longlong_as_float(old); do { assumed = old; old = atomicCAS(address_as_ull, assumed, - __double_as_longlong(val + __longlong_as_double(assumed))); + __float_as_longlong(val + __longlong_as_float(assumed))); } while (assumed != old); - return __longlong_as_double(old); + return __longlong_as_float(old); } #endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_device_registry.hpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_device_registry.hpp index 7fb4fbd5d..2a32b7270 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_device_registry.hpp +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_device_registry.hpp @@ -138,4 +138,4 @@ auto Dispatch(const R& registry, const char* name, Args&&... args) { #define DISPATCH_DEVICE_IMPL(key, ...) \ Dispatch(DEVICE_REGISTRY(key), #key, __VA_ARGS__) -#endif // PYTORCH_DEVICE_REGISTRY \ No newline at end of file +#endif // PYTORCH_DEVICE_REGISTRY diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_npu_helper.hpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_npu_helper.hpp new file mode 100644 index 000000000..88607d23b --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_npu_helper.hpp @@ -0,0 +1,35 @@ +/****************************************************************************** + * Copyright (c) 2022 Huawei Technologies Co., Ltd + * All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ + +#ifndef PYTORCH_NPU_HELPER_HPP_ +#define PYTORCH_NPU_HELPER_HPP_ + +#include +#include +#include + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +#define NPU_NAME_SPACE at_npu::native + +#define REGISTER_NPU_IMPL(key, value) REGISTER_DEVICE_IMPL(key, XLA, value) + +#define CHECK_NPU(x) \ + TORCH_CHECK(x.device().type() == at::kXLA, #x " must be a NPU tensor") + +#endif // PYTORCH_NPU_HELPER_HPP_ diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter.cpp new file mode 100644 index 000000000..e1ead1f8e --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter.cpp @@ -0,0 +1,28 @@ +// Copyright (c) OpenMMLab. All rights reserved. +// Modified from +// https://github.com/csuhan/s2anet/blob/master/mmdet/ops/orn/src/ActiveRotatingFilter.h + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void active_rotated_filter_forward_impl(const Tensor input, + const Tensor indices, Tensor output) { + DISPATCH_DEVICE_IMPL(active_rotated_filter_forward_impl, input, indices, + output); +} + +void active_rotated_filter_backward_impl(const Tensor grad_out, + const Tensor indices, Tensor grad_in) { + DISPATCH_DEVICE_IMPL(active_rotated_filter_backward_impl, grad_out, indices, + grad_in); +} + +void active_rotated_filter_forward(const Tensor input, const Tensor indices, + Tensor output) { + active_rotated_filter_forward_impl(input, indices, output); +} + +void active_rotated_filter_backward(const Tensor grad_out, const Tensor indices, + Tensor grad_in) { + active_rotated_filter_backward_impl(grad_out, indices, grad_in); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_parrots.cpp new file mode 100644 index 000000000..9097f7e0a --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_parrots.cpp @@ -0,0 +1,63 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "active_rotated_filter_pytorch.h" +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void active_rotated_filter_forward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto input = buildATensor(ctx, ins[0]); + auto indices = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + active_rotated_filter_forward(input, indices, output); +} + +void active_rotated_filter_backward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto grad_out = buildATensor(ctx, ins[0]); + auto indices = buildATensor(ctx, ins[1]); + auto grad_in = buildATensor(ctx, outs[0]); + active_rotated_filter_backward(grad_out, indices, grad_in); +} +#endif + +void active_rotated_filter_forward_cpu_parrots( + HostContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto input = buildATensor(ctx, ins[0]); + auto indices = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + active_rotated_filter_forward(input, indices, output); +} + +void active_rotated_filter_backward_cpu_parrots( + HostContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto grad_out = buildATensor(ctx, ins[0]); + auto indices = buildATensor(ctx, ins[1]); + auto grad_in = buildATensor(ctx, outs[0]); + active_rotated_filter_backward(grad_out, indices, grad_in); +} + +PARROTS_EXTENSION_REGISTER(active_rotated_filter_forward) + .input(2) + .output(1) + .apply(active_rotated_filter_forward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(active_rotated_filter_forward_cuda_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(active_rotated_filter_backward) + .input(2) + .output(1) + .apply(active_rotated_filter_backward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(active_rotated_filter_backward_cuda_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_pytorch.h new file mode 100644 index 000000000..9a4d2ce96 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_pytorch.h @@ -0,0 +1,13 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef ACTIVE_ROTATED_FILTER_PYTORCH_H +#define ACTIVE_ROTATED_FILTER_PYTORCH_H +#include +using namespace at; + +void active_rotated_filter_forward(const Tensor input, const Tensor indices, + Tensor output); + +void active_rotated_filter_backward(const Tensor grad_out, const Tensor indices, + Tensor grad_in); + +#endif // ACTIVE_ROTATED_FILTER_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk.cpp new file mode 100644 index 000000000..907627718 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk.cpp @@ -0,0 +1,42 @@ +// Modified from +// https://github.com/CVMI-Lab/PAConv/tree/main/scene_seg/lib/paconv_lib/src/gpu +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void assign_score_withk_forward_impl(int B, int N0, int N1, int M, int K, int O, + int aggregate, const Tensor& points, + const Tensor& centers, + const Tensor& scores, + const Tensor& knn_idx, Tensor& output) { + DISPATCH_DEVICE_IMPL(assign_score_withk_forward_impl, B, N0, N1, M, K, O, + aggregate, points, centers, scores, knn_idx, output); +} + +void assign_score_withk_backward_impl( + int B, int N0, int N1, int M, int K, int O, int aggregate, + const Tensor& grad_out, const Tensor& points, const Tensor& centers, + const Tensor& scores, const Tensor& knn_idx, Tensor& grad_points, + Tensor& grad_centers, Tensor& grad_scores) { + DISPATCH_DEVICE_IMPL(assign_score_withk_backward_impl, B, N0, N1, M, K, O, + aggregate, grad_out, points, centers, scores, knn_idx, + grad_points, grad_centers, grad_scores); +} + +void assign_score_withk_forward(const Tensor& points, const Tensor& centers, + const Tensor& scores, const Tensor& knn_idx, + Tensor& output, int B, int N0, int N1, int M, + int K, int O, int aggregate) { + assign_score_withk_forward_impl(B, N0, N1, M, K, O, aggregate, points, + centers, scores, knn_idx, output); +} + +void assign_score_withk_backward(const Tensor& grad_out, const Tensor& points, + const Tensor& centers, const Tensor& scores, + const Tensor& knn_idx, Tensor& grad_points, + Tensor& grad_centers, Tensor& grad_scores, + int B, int N0, int N1, int M, int K, int O, + int aggregate) { + assign_score_withk_backward_impl(B, N0, N1, M, K, O, aggregate, grad_out, + points, centers, scores, knn_idx, + grad_points, grad_centers, grad_scores); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_parrots.cpp new file mode 100644 index 000000000..5729c7163 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_parrots.cpp @@ -0,0 +1,89 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "assign_score_withk_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void assign_score_withk_forward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int B, N0, N1, M, K, O, aggregate; + SSAttrs(attr) + .get("B", B) + .get("N0", N0) + .get("N1", N1) + .get("M", M) + .get("K", K) + .get("O", O) + .get("aggregate", aggregate) + .done(); + + const auto& points = buildATensor(ctx, ins[0]); + const auto& centers = buildATensor(ctx, ins[1]); + const auto& scores = buildATensor(ctx, ins[2]); + const auto& knn_idx = buildATensor(ctx, ins[3]); + + auto output = buildATensor(ctx, outs[0]); + assign_score_withk_forward(points, centers, scores, knn_idx, output, B, N0, + N1, M, K, O, aggregate); +} + +void assign_score_withk_backward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int B, N0, N1, M, K, O, aggregate; + SSAttrs(attr) + .get("B", B) + .get("N0", N0) + .get("N1", N1) + .get("M", M) + .get("K", K) + .get("O", O) + .get("aggregate", aggregate) + .done(); + + const auto& grad_out = buildATensor(ctx, ins[0]); + const auto& points = buildATensor(ctx, ins[1]); + const auto& centers = buildATensor(ctx, ins[2]); + const auto& scores = buildATensor(ctx, ins[3]); + const auto& knn_idx = buildATensor(ctx, ins[4]); + + auto grad_points = buildATensor(ctx, outs[0]); + auto grad_centers = buildATensor(ctx, outs[1]); + auto grad_scores = buildATensor(ctx, outs[2]); + assign_score_withk_backward(grad_out, points, centers, scores, knn_idx, + grad_points, grad_centers, grad_scores, B, N0, N1, + M, K, O, aggregate); +} + +PARROTS_EXTENSION_REGISTER(assign_score_withk_forward) + .attr("B") + .attr("N0") + .attr("N1") + .attr("M") + .attr("K") + .attr("O") + .attr("aggregate") + .input(4) + .output(1) + .apply(assign_score_withk_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(assign_score_withk_backward) + .attr("B") + .attr("N0") + .attr("N1") + .attr("M") + .attr("K") + .attr("O") + .attr("aggregate") + .input(5) + .output(3) + .apply(assign_score_withk_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_pytorch.h new file mode 100644 index 000000000..660594fee --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_pytorch.h @@ -0,0 +1,19 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef ASSIGN_SCORE_WITHK_PYTORCH_H +#define ASSIGN_SCORE_WITHK_PYTORCH_H +#include +using namespace at; + +void assign_score_withk_forward(const Tensor& points, const Tensor& centers, + const Tensor& scores, const Tensor& knn_idx, + Tensor& output, int B, int N0, int N1, int M, + int K, int O, int aggregate); + +void assign_score_withk_backward(const Tensor& grad_out, const Tensor& points, + const Tensor& centers, const Tensor& scores, + const Tensor& knn_idx, Tensor& grad_points, + Tensor& grad_centers, Tensor& grad_scores, + int B, int N0, int N1, int M, int K, int O, + int aggregate); + +#endif // ASSIGN_SCORE_WITHK_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query._parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query._parrots.cpp new file mode 100644 index 000000000..01ab9739b --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query._parrots.cpp @@ -0,0 +1,43 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "ball_query_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void ball_query_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int b, n, m, nsample; + float min_radius, max_radius; + SSAttrs(attr) + .get("b", b) + .get("n", n) + .get("m", m) + .get("nsample", nsample) + .get("min_radius", min_radius) + .get("max_radius", max_radius) + .done(); + + const auto& center_xyz = buildATensor(ctx, ins[0]); + const auto& xyz = buildATensor(ctx, ins[1]); + auto idx = buildATensor(ctx, outs[0]); + ball_query_forward(center_xyz, xyz, idx, b, n, m, min_radius, max_radius, + nsample); +} + +PARROTS_EXTENSION_REGISTER(ball_query_forward) + .attr("b") + .attr("n") + .attr("m") + .attr("nsample") + .attr("min_radius") + .attr("max_radius") + .input(2) + .output(1) + .apply(ball_query_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query.cpp new file mode 100644 index 000000000..1c9e7a207 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query.cpp @@ -0,0 +1,20 @@ +// Modified from +// https://github.com/sshaoshuai/Pointnet2.PyTorch/tree/master/pointnet2/src/ball_query.cpp + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void ball_query_forward_impl(int b, int n, int m, float min_radius, + float max_radius, int nsample, + const Tensor new_xyz, const Tensor xyz, + Tensor idx) { + DISPATCH_DEVICE_IMPL(ball_query_forward_impl, b, n, m, min_radius, max_radius, + nsample, new_xyz, xyz, idx); +} + +void ball_query_forward(Tensor new_xyz_tensor, Tensor xyz_tensor, + Tensor idx_tensor, int b, int n, int m, + float min_radius, float max_radius, int nsample) { + ball_query_forward_impl(b, n, m, min_radius, max_radius, nsample, + new_xyz_tensor, xyz_tensor, idx_tensor); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query_pytorch.h new file mode 100644 index 000000000..70026f315 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query_pytorch.h @@ -0,0 +1,11 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef BALL_QUERY_PYTORCH_H +#define BALL_QUERY_PYTORCH_H +#include +using namespace at; + +void ball_query_forward(const Tensor new_xyz, const Tensor xyz, Tensor idx, + int b, int n, int m, float min_radius, float max_radius, + int nsample); + +#endif // BALL_QUERY_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps.cpp new file mode 100644 index 000000000..187216fb0 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps.cpp @@ -0,0 +1,14 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void bbox_overlaps_impl(const Tensor bboxes1, const Tensor bboxes2, Tensor ious, + const int mode, const bool aligned, const int offset) { + DISPATCH_DEVICE_IMPL(bbox_overlaps_impl, bboxes1, bboxes2, ious, mode, + aligned, offset); +} + +void bbox_overlaps(const Tensor bboxes1, const Tensor bboxes2, Tensor ious, + const int mode, const bool aligned, const int offset) { + bbox_overlaps_impl(bboxes1, bboxes2, ious, mode, aligned, offset); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_parrots.cpp new file mode 100644 index 000000000..5f6264d3c --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_parrots.cpp @@ -0,0 +1,40 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "bbox_overlaps_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +/* + * void bbox_overlaps_cuda(const Tensor bboxes1, const Tensor bboxes2, Tensor + * ious, const int mode, const bool aligned, const int offset); + */ +void bbox_overlaps_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int mode, offset; + bool aligned; + SSAttrs(attr) + .get("mode", mode) + .get("aligned", aligned) + .get("offset", offset) + .done(); + + const auto& bboxes1 = buildATensor(ctx, ins[0]); + const auto& bboxes2 = buildATensor(ctx, ins[1]); + auto ious = buildATensor(ctx, outs[0]); + bbox_overlaps_cuda(bboxes1, bboxes2, ious, mode, aligned, offset); +} + +PARROTS_EXTENSION_REGISTER(bbox_overlaps) + .attr("mode") + .attr("aligned") + .attr("offset") + .input(2) + .output(1) + .apply(bbox_overlaps_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_pytorch.h new file mode 100644 index 000000000..4f68aa339 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_pytorch.h @@ -0,0 +1,10 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef BBOX_OVERLAPS_PYTORCH_H +#define BBOX_OVERLAPS_PYTORCH_H +#include +using namespace at; + +void bbox_overlaps_cuda(const Tensor bboxes1, const Tensor bboxes2, Tensor ious, + const int mode, const bool aligned, const int offset); + +#endif // BBOX_OVERLAPS_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align.cpp new file mode 100644 index 000000000..565de6899 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align.cpp @@ -0,0 +1,30 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void border_align_forward_impl(const Tensor &input, const Tensor &boxes, + Tensor output, Tensor argmax_idx, + const int pool_size) { + DISPATCH_DEVICE_IMPL(border_align_forward_impl, input, boxes, output, + argmax_idx, pool_size); +} + +void border_align_backward_impl(const Tensor &grad_output, const Tensor &boxes, + const Tensor &argmax_idx, Tensor grad_input, + const int pool_size) { + DISPATCH_DEVICE_IMPL(border_align_backward_impl, grad_output, boxes, + argmax_idx, grad_input, pool_size); +} + +void border_align_forward(const Tensor &input, const Tensor &boxes, + Tensor output, Tensor argmax_idx, + const int pool_size) { + border_align_forward_impl(input, boxes, output, argmax_idx, pool_size); +} + +void border_align_backward(const Tensor &grad_output, const Tensor &boxes, + const Tensor &argmax_idx, Tensor grad_input, + const int pool_size) { + border_align_backward_impl(grad_output, boxes, argmax_idx, grad_input, + pool_size); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_parrots.cpp new file mode 100644 index 000000000..8c3bea58c --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_parrots.cpp @@ -0,0 +1,53 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "border_align_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void border_align_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pool_size; + SSAttrs(attr).get("pool_size", pool_size).done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& boxes = buildATensor(ctx, ins[1]); + + auto output = buildATensor(ctx, outs[0]); + auto argmax_idx = buildATensor(ctx, outs[1]); + border_align_forward_cuda(input, boxes, output, argmax_idx, pool_size); +} + +void border_align_backward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pool_size; + SSAttrs(attr).get("pool_size", pool_size).done(); + + const auto& top_grad = buildATensor(ctx, ins[0]); + const auto& boxes = buildATensor(ctx, ins[1]); + const auto& argmax_idx = buildATensor(ctx, ins[2]); + + auto bottom_grad = buildATensor(ctx, outs[0]); + border_align_backward_cuda(top_grad, boxes, argmax_idx, bottom_grad, + pool_size); +} + +PARROTS_EXTENSION_REGISTER(border_align_forward) + .attr("pool_size") + .input(2) + .output(2) + .apply(border_align_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(border_align_backward) + .attr("pool_size") + .input(3) + .output(1) + .apply(border_align_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_pytorch.h new file mode 100644 index 000000000..cb031e572 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_pytorch.h @@ -0,0 +1,17 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef BORDER_ALIGN_PYTORCH_H +#define BORDER_ALIGN_PYTORCH_H +#include +using namespace at; + +#ifdef MMCV_WITH_CUDA +void border_align_forward_cuda(const Tensor &input, const Tensor &boxes, + Tensor output, Tensor argmax_idx, + const int pool_size); + +void border_align_backward_cuda(const Tensor &grad_output, const Tensor &boxes, + const Tensor &argmax_idx, Tensor grad_input, + const int pool_size); +#endif + +#endif // BORDER_ALIGN_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated.cpp new file mode 100644 index 000000000..a2a4e0953 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated.cpp @@ -0,0 +1,19 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +// modified from +// https://github.com/facebookresearch/detectron2/blob/master/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated.h +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void box_iou_rotated_impl(const Tensor boxes1, const Tensor boxes2, Tensor ious, + const int mode_flag, const bool aligned) { + DISPATCH_DEVICE_IMPL(box_iou_rotated_impl, boxes1, boxes2, ious, mode_flag, + aligned); +} + +// Interface for Python +// inline is needed to prevent multiple function definitions when this header is +// included by different cpps +void box_iou_rotated(const Tensor boxes1, const Tensor boxes2, Tensor ious, + const int mode_flag, const bool aligned) { + box_iou_rotated_impl(boxes1, boxes2, ious, mode_flag, aligned); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_parrots.cpp new file mode 100644 index 000000000..a90d64045 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_parrots.cpp @@ -0,0 +1,61 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "box_iou_rotated_pytorch.h" + +using namespace parrots; + +/* + * void box_iou_rotated_cpu(const Tensor boxes1, const Tensor boxes2, Tensor + * ious, const int mode_flag, const bool aligned); + */ +void box_iou_rotated_cpu_parrots(HostContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + bool aligned; + int mode_flag; + SSAttrs(attr) + .get("aligned", aligned) + .get("mode_flag", mode_flag) + .done(); + + const auto& boxes1 = buildATensor(ctx, ins[0]); + const auto& boxes2 = buildATensor(ctx, ins[1]); + auto ious = buildATensor(ctx, outs[0]); + box_iou_rotated_cpu(boxes1, boxes2, ious, mode_flag, aligned); +} + +#ifdef MMCV_WITH_CUDA +/* + * void box_iou_rotated_cuda(const Tensor boxes1, const Tensor boxes2, Tensor + * ious, const int mode_flag, const bool aligned); + */ +void box_iou_rotated_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + bool aligned; + int mode_flag; + SSAttrs(attr) + .get("aligned", aligned) + .get("mode_flag", mode_flag) + .done(); + + const auto& boxes1 = buildATensor(ctx, ins[0]); + const auto& boxes2 = buildATensor(ctx, ins[1]); + auto ious = buildATensor(ctx, outs[0]); + box_iou_rotated_cuda(boxes1, boxes2, ious, mode_flag, aligned); +} +#endif + +PARROTS_EXTENSION_REGISTER(box_iou_rotated) + .attr("aligned") + .attr("mode_flag") + .input(2) + .output(1) + .apply(box_iou_rotated_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(box_iou_rotated_cuda_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_pytorch.h new file mode 100644 index 000000000..afab70318 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_pytorch.h @@ -0,0 +1,15 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef BOX_IOU_ROTATED_PYTORCH_H +#define BOX_IOU_ROTATED_PYTORCH_H +#include +using namespace at; + +void box_iou_rotated_cpu(const Tensor boxes1, const Tensor boxes2, Tensor ious, + const int mode_flag, const bool aligned); + +#ifdef MMCV_WITH_CUDA +void box_iou_rotated_cuda(const Tensor boxes1, const Tensor boxes2, Tensor ious, + const int mode_flag, const bool aligned); +#endif + +#endif // BOX_IOU_ROTATED_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe.cpp new file mode 100644 index 000000000..a563aed94 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe.cpp @@ -0,0 +1,38 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void carafe_forward_impl(Tensor features, Tensor masks, Tensor rfeatures, + Tensor routput, Tensor rmasks, Tensor output, + int kernel_size, int group_size, int scale_factor) { + DISPATCH_DEVICE_IMPL(carafe_forward_impl, features, masks, rfeatures, routput, + rmasks, output, kernel_size, group_size, scale_factor); +} + +void carafe_backward_impl(Tensor top_grad, Tensor rfeatures, Tensor masks, + Tensor rtop_grad, Tensor rbottom_grad_hs, + Tensor rbottom_grad, Tensor rmask_grad, + Tensor bottom_grad, Tensor mask_grad, int kernel_size, + int group_size, int scale_factor) { + DISPATCH_DEVICE_IMPL(carafe_backward_impl, top_grad, rfeatures, masks, + rtop_grad, rbottom_grad_hs, rbottom_grad, rmask_grad, + bottom_grad, mask_grad, kernel_size, group_size, + scale_factor); +} + +void carafe_forward(Tensor features, Tensor masks, Tensor rfeatures, + Tensor routput, Tensor rmasks, Tensor output, + int kernel_size, int group_size, int scale_factor) { + carafe_forward_impl(features, masks, rfeatures, routput, rmasks, output, + kernel_size, group_size, scale_factor); +} + +void carafe_backward(Tensor top_grad, Tensor rfeatures, Tensor masks, + Tensor rtop_grad, Tensor rbottom_grad_hs, + Tensor rbottom_grad, Tensor rmask_grad, Tensor bottom_grad, + Tensor mask_grad, int kernel_size, int group_size, + int scale_factor) { + carafe_backward_impl(top_grad, rfeatures, masks, rtop_grad, rbottom_grad_hs, + rbottom_grad, rmask_grad, bottom_grad, mask_grad, + kernel_size, group_size, scale_factor); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive.cpp new file mode 100644 index 000000000..6e8917a61 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive.cpp @@ -0,0 +1,32 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void carafe_naive_forward_impl(Tensor features, Tensor masks, Tensor output, + int kernel_size, int group_size, + int scale_factor) { + DISPATCH_DEVICE_IMPL(carafe_naive_forward_impl, features, masks, output, + kernel_size, group_size, scale_factor); +} + +void carafe_naive_backward_impl(Tensor top_grad, Tensor features, Tensor masks, + Tensor bottom_grad, Tensor mask_grad, + int kernel_size, int group_size, + int scale_factor) { + DISPATCH_DEVICE_IMPL(carafe_naive_backward_impl, top_grad, features, masks, + bottom_grad, mask_grad, kernel_size, group_size, + scale_factor); +} + +void carafe_naive_forward(Tensor features, Tensor masks, Tensor output, + int kernel_size, int group_size, int scale_factor) { + carafe_naive_forward_impl(features, masks, output, kernel_size, group_size, + scale_factor); +} + +void carafe_naive_backward(Tensor top_grad, Tensor features, Tensor masks, + Tensor bottom_grad, Tensor mask_grad, + int kernel_size, int group_size, int scale_factor) { + carafe_naive_backward_impl(top_grad, features, masks, bottom_grad, mask_grad, + kernel_size, group_size, scale_factor); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_parrots.cpp new file mode 100644 index 000000000..9c16a3707 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_parrots.cpp @@ -0,0 +1,74 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "carafe_naive_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +/*void carafe_naive_forward_cuda(Tensor features, Tensor masks, Tensor output, + * int kernel_size, int group_size, + * int scale_factor) + */ +void carafe_naive_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kernel_size, group_size, scale_factor; + SSAttrs(attr) + .get("kernel_size", kernel_size) + .get("group_size", group_size) + .get("scale_factor", scale_factor) + .done(); + + const auto& features = buildATensor(ctx, ins[0]); + const auto& masks = buildATensor(ctx, ins[1]); + + auto output = buildATensor(ctx, outs[0]); + carafe_naive_forward_cuda(features, masks, output, kernel_size, group_size, + scale_factor); +} + +/*void carafe_naive_backward_cuda(Tensor top_grad, Tensor features, Tensor + * masks, Tensor bottom_grad, Tensor mask_grad, int kernel_size, int group_size, + * int scale_factor); + */ +void carafe_naive_backward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kernel_size, group_size, scale_factor; + SSAttrs(attr) + .get("kernel_size", kernel_size) + .get("group_size", group_size) + .get("scale_factor", scale_factor) + .done(); + + const auto& top_grad = buildATensor(ctx, ins[0]); + const auto& features = buildATensor(ctx, ins[1]); + const auto& masks = buildATensor(ctx, ins[2]); + + auto bottom_grad = buildATensor(ctx, outs[0]); + auto mask_grad = buildATensor(ctx, outs[1]); + carafe_naive_backward_cuda(top_grad, features, masks, bottom_grad, mask_grad, + kernel_size, group_size, scale_factor); +} + +PARROTS_EXTENSION_REGISTER(carafe_naive_forward) + .attr("kernel_size") + .attr("group_size") + .attr("scale_factor") + .input(2) + .output(1) + .apply(carafe_naive_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(carafe_naive_backward) + .attr("kernel_size") + .attr("group_size") + .attr("scale_factor") + .input(3) + .output(2) + .apply(carafe_naive_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_pytorch.h new file mode 100644 index 000000000..6df9b88c2 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_pytorch.h @@ -0,0 +1,15 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef CARAFE_NAIVE_PYTORCH_H +#define CARAFE_NAIVE_PYTORCH_H +#include +using namespace at; + +void carafe_naive_forward_cuda(Tensor features, Tensor masks, Tensor output, + int kernel_size, int group_size, + int scale_factor); + +void carafe_naive_backward_cuda(Tensor top_grad, Tensor features, Tensor masks, + Tensor bottom_grad, Tensor mask_grad, + int kernel_size, int group_size, + int scale_factor); +#endif // CARAFE_NAIVE_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_parrots.cpp new file mode 100644 index 000000000..e99f59ef2 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_parrots.cpp @@ -0,0 +1,88 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "carafe_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +/* + * void carafe_forward_cuda(Tensor features, Tensor masks, Tensor rfeatures, + * Tensor routput, Tensor rmasks, Tensor output, + * int kernel_size, int group_size, int scale_factor); + */ +void carafe_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kernel_size, group_size, scale_factor; + SSAttrs(attr) + .get("kernel_size", kernel_size) + .get("group_size", group_size) + .get("scale_factor", scale_factor) + .done(); + + const auto& features = buildATensor(ctx, ins[0]); + const auto& masks = buildATensor(ctx, ins[1]); + + auto rfeatures = buildATensor(ctx, outs[0]); + auto routput = buildATensor(ctx, outs[1]); + auto rmasks = buildATensor(ctx, outs[2]); + auto output = buildATensor(ctx, outs[3]); + + carafe_forward_cuda(features, masks, rfeatures, routput, rmasks, output, + kernel_size, group_size, scale_factor); +} + +/* + * void carafe_backward_cuda(Tensor top_grad, Tensor rfeatures, Tensor masks, + * Tensor rtop_grad, Tensor rbottom_grad_hs, + * Tensor rbottom_grad, Tensor rmask_grad, + * Tensor bottom_grad, Tensor mask_grad, int + * kernel_size, int group_size, int scale_factor); + */ +void carafe_backward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kernel_size, group_size, scale_factor; + SSAttrs(attr) + .get("kernel_size", kernel_size) + .get("group_size", group_size) + .get("scale_factor", scale_factor) + .done(); + + const auto& top_grad = buildATensor(ctx, ins[0]); + const auto& rfeatures = buildATensor(ctx, ins[1]); + const auto& masks = buildATensor(ctx, ins[2]); + + auto rtop_grad = buildATensor(ctx, outs[0]); + auto rbottom_grad_hs = buildATensor(ctx, outs[1]); + auto rbottom_grad = buildATensor(ctx, outs[2]); + auto rmask_grad = buildATensor(ctx, outs[3]); + auto bottom_grad = buildATensor(ctx, outs[4]); + auto mask_grad = buildATensor(ctx, outs[5]); + + carafe_backward_cuda(top_grad, rfeatures, masks, rtop_grad, rbottom_grad_hs, + rbottom_grad, rmask_grad, bottom_grad, mask_grad, + kernel_size, group_size, scale_factor); +} + +PARROTS_EXTENSION_REGISTER(carafe_forward) + .attr("kernel_size") + .attr("group_size") + .attr("scale_factor") + .input(2) + .output(4) + .apply(carafe_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(carafe_backward) + .attr("kernel_size") + .attr("group_size") + .attr("scale_factor") + .input(3) + .output(6) + .apply(carafe_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_pytorch.h new file mode 100644 index 000000000..2b94d44d3 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_pytorch.h @@ -0,0 +1,16 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef CARAFE_PYTORCH_H +#define CARAFE_PYTORCH_H +#include +using namespace at; + +void carafe_forward_cuda(Tensor features, Tensor masks, Tensor rfeatures, + Tensor routput, Tensor rmasks, Tensor output, + int kernel_size, int group_size, int scale_factor); + +void carafe_backward_cuda(Tensor top_grad, Tensor rfeatures, Tensor masks, + Tensor rtop_grad, Tensor rbottom_grad_hs, + Tensor rbottom_grad, Tensor rmask_grad, + Tensor bottom_grad, Tensor mask_grad, int kernel_size, + int group_size, int scale_factor); +#endif // CARAFE_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance.cpp new file mode 100644 index 000000000..dcff69893 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance.cpp @@ -0,0 +1,35 @@ +// Copyright (c) OpenMMLab. All rights reserved. +// Modified from +// https://github.com/chrdiller/pyTorchChamferDistance/blob/master/chamfer_distance/chamfer_distance.cpp + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void chamfer_distance_forward_impl(const Tensor xyz1, const Tensor xyz2, + const Tensor dist1, const Tensor dist2, + const Tensor idx1, const Tensor idx2) { + DISPATCH_DEVICE_IMPL(chamfer_distance_forward_impl, xyz1, xyz2, dist1, dist2, + idx1, idx2); +} + +void chamfer_distance_backward_impl(const Tensor xyz1, const Tensor xyz2, + Tensor idx1, Tensor idx2, Tensor graddist1, + Tensor graddist2, Tensor gradxyz1, + Tensor gradxyz2) { + DISPATCH_DEVICE_IMPL(chamfer_distance_backward_impl, xyz1, xyz2, idx1, idx2, + graddist1, graddist2, gradxyz1, gradxyz2); +} + +void chamfer_distance_forward(const Tensor xyz1, const Tensor xyz2, + const Tensor dist1, const Tensor dist2, + const Tensor idx1, const Tensor idx2) { + chamfer_distance_forward_impl(xyz1, xyz2, dist1, dist2, idx1, idx2); +} + +void chamfer_distance_backward(const Tensor xyz1, const Tensor xyz2, + Tensor idx1, Tensor idx2, Tensor graddist1, + Tensor graddist2, Tensor gradxyz1, + Tensor gradxyz2) { + chamfer_distance_backward_impl(xyz1, xyz2, idx1, idx2, graddist1, graddist2, + gradxyz1, gradxyz2); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_parrots.cpp new file mode 100644 index 000000000..db8eff1d6 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_parrots.cpp @@ -0,0 +1,51 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "chamfer_distance_pytorch.h" +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void chamfer_distance_forward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto xyz1 = buildATensor(ctx, ins[0]); + auto xyz2 = buildATensor(ctx, ins[1]); + auto dist1 = buildATensor(ctx, outs[0]); + auto dist2 = buildATensor(ctx, outs[1]); + auto idx1 = buildATensor(ctx, outs[2]); + auto idx2 = buildATensor(ctx, outs[3]); + chamfer_distance_forward(xyz1, xyz2, dist1, dist2, idx1, idx2); +} + +void chamfer_distance_backward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto xyz1 = buildATensor(ctx, ins[0]); + auto xyz2 = buildATensor(ctx, ins[1]); + auto idx1 = buildATensor(ctx, ins[2]); + auto idx2 = buildATensor(ctx, ins[3]); + auto graddist1 = buildATensor(ctx, ins[4]); + auto graddist2 = buildATensor(ctx, ins[5]); + auto gradxyz1 = buildATensor(ctx, outs[0]); + auto gradxyz2 = buildATensor(ctx, outs[1]); + chamfer_distance_backward(xyz1, xyz2, idx1, idx2, graddist1, graddist2, + gradxyz1, gradxyz2); +} + +PARROTS_EXTENSION_REGISTER(chamfer_distance_forward) + .input(2) + .output(4) + .apply(chamfer_distance_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(chamfer_distance_backward) + .input(6) + .output(2) + .apply(chamfer_distance_backward_cuda_parrots) + .done(); + +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_pytorch.h new file mode 100644 index 000000000..6405526b0 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_pytorch.h @@ -0,0 +1,16 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef ACTIVE_CHAMFER_DISTANCE_PYTORCH_H +#define ACTIVE_CHAMFER_DISTANCE_PYTORCH_H +#include +using namespace at; + +void chamfer_distance_forward(const Tensor xyz1, const Tensor xyz2, + const Tensor dist1, const Tensor dist2, + const Tensor idx1, const Tensor idx); + +void chamfer_distance_backward(const Tensor xyz1, const Tensor xyz2, + Tensor idx1, Tensor idx2, Tensor graddist1, + Tensor graddist2, Tensor gradxyz1, + Tensor gradxyz2); + +#endif // ACTIVE_CHAMFER_DISTANCE_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand.cpp new file mode 100644 index 000000000..586c48ee4 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand.cpp @@ -0,0 +1,111 @@ +// Copyright (c) OpenMMLab. All rights reserved +// It is modified from https://github.com/whai362/PSENet +#include +#include + +#include "pytorch_cpp_helper.hpp" + +using namespace std; + +class Point2d { + public: + int x; + int y; + + Point2d() : x(0), y(0) {} + Point2d(int _x, int _y) : x(_x), y(_y) {} +}; + +void kernel_dilate(const uint8_t *data, IntArrayRef data_shape, + const int *label_map, int &label_num, int &min_area, + vector> &text_line) { + std::vector area(label_num + 1); + int kernel_num = data_shape[0]; + int height = data_shape[1]; + int width = data_shape[2]; + + for (int x = 0; x < height; ++x) { + for (int y = 0; y < width; ++y) { + int label = label_map[x * width + y]; + if (label == 0) continue; + area[label] += 1; + } + } + + queue queue, next_queue; + for (int x = 0; x < height; ++x) { + vector row(width); + for (int y = 0; y < width; ++y) { + int label = label_map[x * width + y]; + if (label == 0) continue; + if (area[label] < min_area) continue; + + Point2d point(x, y); + queue.push(point); + row[y] = label; + } + text_line.emplace_back(row); + } + + int dx[] = {-1, 1, 0, 0}; + int dy[] = {0, 0, -1, 1}; + vector kernel_step(kernel_num); + std::for_each(kernel_step.begin(), kernel_step.end(), + [=](int &k) { return k * height * width; }); + + for (int kernel_id = kernel_num - 2; kernel_id >= 0; --kernel_id) { + while (!queue.empty()) { + Point2d point = queue.front(); + queue.pop(); + int x = point.x; + int y = point.y; + int label = text_line[x][y]; + + bool is_edge = true; + for (int d = 0; d < 4; ++d) { + int tmp_x = x + dx[d]; + int tmp_y = y + dy[d]; + + if (tmp_x < 0 || tmp_x >= height) continue; + if (tmp_y < 0 || tmp_y >= width) continue; + int kernel_value = data[kernel_step[kernel_id] + tmp_x * width + tmp_y]; + if (kernel_value == 0) continue; + if (text_line[tmp_x][tmp_y] > 0) continue; + + Point2d point(tmp_x, tmp_y); + queue.push(point); + text_line[tmp_x][tmp_y] = label; + is_edge = false; + } + + if (is_edge) { + next_queue.push(point); + } + } + swap(queue, next_queue); + } +} + +std::vector> contour_expand(Tensor kernel_mask, + Tensor internal_kernel_label, + int min_kernel_area, + int kernel_num) { + kernel_mask = kernel_mask.contiguous(); + internal_kernel_label = internal_kernel_label.contiguous(); + assert(kernel_mask.dim() == 3); + assert(internal_kernel_label.dim() == 2); + assert(kernel_mask.size(1) == internal_kernel_label.size(0)); + assert(kernel_mask.size(2) == internal_kernel_label.size(1)); + CHECK_CPU_INPUT(kernel_mask); + CHECK_CPU_INPUT(internal_kernel_label); + auto ptr_data = kernel_mask.data_ptr(); + IntArrayRef data_shape = kernel_mask.sizes(); + + auto data_label_map = internal_kernel_label.data_ptr(); + vector> text_line; + + kernel_dilate(ptr_data, data_shape, data_label_map, kernel_num, + min_kernel_area, text_line); + + return text_line; +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_parrots.cpp new file mode 100644 index 000000000..1581fdc83 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_parrots.cpp @@ -0,0 +1,43 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "contour_expand_pytorch.h" + +using namespace parrots; +using namespace std; + +template +void contour_expand_parrots(T& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int min_kernel_area, kernel_num; + SSAttrs(attr) + .get("min_kernel_area", min_kernel_area) + .get("kernel_num", kernel_num) + .done(); + at::Tensor kernel_mask; + at::Tensor internal_kernel_label; + kernel_mask = buildATensor(ctx, ins[0]); + internal_kernel_label = buildATensor(ctx, ins[1]); + auto out = contour_expand(kernel_mask, internal_kernel_label, min_kernel_area, + kernel_num); + int n = out.size(), m = 0; + for (int i = 0; i < n; ++i) + if (m < out[i].size()) m = out[i].size(); + auto options = torch::TensorOptions().dtype(at::kInt); + auto tensor = torch::zeros({n, m}, options); + for (int i = 0; i < n; i++) + tensor.slice(0, i, i + 1) = + torch::from_blob(out[i].data(), {out[i].size()}, options); + updateDArray(ctx, tensor, outs[0]); +} + +PARROTS_EXTENSION_REGISTER(contour_expand) + .attr("min_kernel_area") + .attr("kernel_num") + .input(2) + .output(1) + .apply(contour_expand_parrots) + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_pytorch.h new file mode 100644 index 000000000..881bbac3c --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_pytorch.h @@ -0,0 +1,12 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef CONTOUR_EXPAND_PYTORCH_H +#define CONTOUR_EXPAND_PYTORCH_H +#include +using namespace at; + +std::vector> contour_expand(Tensor kernel_mask, + Tensor internal_kernel_label, + int min_kernel_area, + int kernel_num); + +#endif // CONTOUR_EXPAND_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou.cpp new file mode 100644 index 000000000..79f2028b5 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou.cpp @@ -0,0 +1,23 @@ +// Copyright (c) OpenMMLab. All rights reserved +// modified from +// https://github.com/SDL-GuoZonghao/BeyondBoundingBox/tree/main/mmdet/ops/iou/src +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void convex_iou_impl(const Tensor pointsets, const Tensor polygons, + Tensor ious) { + DISPATCH_DEVICE_IMPL(convex_iou_impl, pointsets, polygons, ious); +} + +void convex_iou(const Tensor pointsets, const Tensor polygons, Tensor ious) { + convex_iou_impl(pointsets, polygons, ious); +} + +void convex_giou_impl(const Tensor pointsets, const Tensor polygons, + Tensor output) { + DISPATCH_DEVICE_IMPL(convex_giou_impl, pointsets, polygons, output); +} + +void convex_giou(const Tensor pointsets, const Tensor polygons, Tensor output) { + convex_giou_impl(pointsets, polygons, output); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_parrots.cpp new file mode 100644 index 000000000..bf766542f --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_parrots.cpp @@ -0,0 +1,40 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "convex_iou_pytorch.h" +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void convex_iou_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto pointsets = buildATensor(ctx, ins[0]); + auto polygons = buildATensor(ctx, ins[1]); + auto ious = buildATensor(ctx, outs[0]); + convex_iou(pointsets, polygons, ious); +} + +void convex_giou_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto pointsets = buildATensor(ctx, ins[0]); + auto polygons = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + convex_giou(pointsets, polygons, output); +} + +PARROTS_EXTENSION_REGISTER(convex_iou) + .input(2) + .output(1) + .apply(convex_iou_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(convex_giou) + .input(2) + .output(1) + .apply(convex_giou_forward_cuda_parrots) + .done(); + +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_pytorch.h new file mode 100644 index 000000000..4f16a1ce4 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_pytorch.h @@ -0,0 +1,11 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef CONVEX_IOU_PYTORCH_H +#define CONVEX_IOU_PYTORCH_H +#include +using namespace at; + +void convex_iou(const Tensor pointsets, const Tensor polygons, Tensor ious); + +void convex_giou(const Tensor pointsets, const Tensor polygons, Tensor output); + +#endif // RIROI_ALIGN_ROTATED_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation.cpp new file mode 100644 index 000000000..f4adba2a0 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation.cpp @@ -0,0 +1,47 @@ +// Copyright (c) OpenMMLab. All rights reserved. +#include + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void correlation_forward_impl(Tensor input1, Tensor input2, Tensor output, + int kH, int kW, int patchH, int patchW, int padH, + int padW, int dilationH, int dilationW, + int dilation_patchH, int dilation_patchW, int dH, + int dW) { + DISPATCH_DEVICE_IMPL(correlation_forward_impl, input1, input2, output, kH, kW, + patchH, patchW, padH, padW, dilationH, dilationW, + dilation_patchH, dilation_patchW, dH, dW); +} + +void correlation_backward_impl(Tensor grad_output, Tensor input1, Tensor input2, + Tensor grad_input1, Tensor grad_input2, int kH, + int kW, int patchH, int patchW, int padH, + int padW, int dilationH, int dilationW, + int dilation_patchH, int dilation_patchW, int dH, + int dW) { + DISPATCH_DEVICE_IMPL(correlation_backward_impl, grad_output, input1, input2, + grad_input1, grad_input2, kH, kW, patchH, patchW, padH, + padW, dilationH, dilationW, dilation_patchH, + dilation_patchW, dH, dW); +} + +void correlation_forward(Tensor input1, Tensor input2, Tensor output, int kH, + int kW, int patchH, int patchW, int padH, int padW, + int dilationH, int dilationW, int dilation_patchH, + int dilation_patchW, int dH, int dW) { + correlation_forward_impl(input1, input2, output, kH, kW, patchH, patchW, padH, + padW, dilationH, dilationW, dilation_patchH, + dilation_patchW, dH, dW); +} + +void correlation_backward(Tensor grad_output, Tensor input1, Tensor input2, + Tensor grad_input1, Tensor grad_input2, int kH, + int kW, int patchH, int patchW, int padH, int padW, + int dilationH, int dilationW, int dilation_patchH, + int dilation_patchW, int dH, int dW) { + correlation_backward_impl(grad_output, input1, input2, grad_input1, + grad_input2, kH, kW, patchH, patchW, padH, padW, + dilationH, dilationW, dilation_patchH, + dilation_patchW, dH, dW); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_parrots.cpp new file mode 100644 index 000000000..b1e287d06 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_parrots.cpp @@ -0,0 +1,176 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "correlation_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void correlation_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kH, kW, patchH, patchW, padH, padW, dilationH, dilationW, dilation_patchH, + dilation_patchW, dH, dW; + SSAttrs(attr) + .get("kH", kH) + .get("kW", kW) + .get("patchH", patchH) + .get("patchW", patchW) + .get("padH", padH) + .get("padW", padW) + .get("dilationH", dilationH) + .get("dilationW", dilationW) + .get("dilation_patchH", dilation_patchH) + .get("dilation_patchW", dilation_patchW) + .get("dH", dH) + .get("dW", dW) + .done(); + + auto input1 = buildATensor(ctx, ins[0]); + auto input2 = buildATensor(ctx, ins[1]); + + auto output = buildATensor(ctx, outs[0]); + + correlation_forward(input1, input2, output, kH, kW, patchH, patchW, padH, + padW, dilationH, dilationW, dilation_patchH, + dilation_patchW, dH, dW); +} + +void correlation_backward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kH, kW, patchH, patchW, padH, padW, dilationH, dilationW, dilation_patchH, + dilation_patchW, dH, dW; + SSAttrs(attr) + .get("kH", kH) + .get("kW", kW) + .get("patchH", patchH) + .get("patchW", patchW) + .get("padH", padH) + .get("padW", padW) + .get("dilationH", dilationH) + .get("dilationW", dilationW) + .get("dilation_patchH", dilation_patchH) + .get("dilation_patchW", dilation_patchW) + .get("dH", dH) + .get("dW", dW) + .done(); + + auto grad_output = buildATensor(ctx, ins[0]); + auto input1 = buildATensor(ctx, ins[1]); + auto input2 = buildATensor(ctx, ins[2]); + + auto grad_input1 = buildATensor(ctx, outs[0]); + auto grad_input2 = buildATensor(ctx, outs[1]); + + correlation_backward(grad_output, input1, input2, grad_input1, grad_input2, + kH, kW, patchH, patchW, padH, padW, dilationH, dilationW, + dilation_patchH, dilation_patchW, dH, dW); +} +#endif + +void correlation_forward_cpu_parrots(HostContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kH, kW, patchH, patchW, padH, padW, dilationH, dilationW, dilation_patchH, + dilation_patchW, dH, dW; + SSAttrs(attr) + .get("kH", kH) + .get("kW", kW) + .get("patchH", patchH) + .get("patchW", patchW) + .get("padH", padH) + .get("padW", padW) + .get("dilationH", dilationH) + .get("dilationW", dilationW) + .get("dilation_patchH", dilation_patchH) + .get("dilation_patchW", dilation_patchW) + .get("dH", dH) + .get("dW", dW) + .done(); + + auto input1 = buildATensor(ctx, ins[0]); + auto input2 = buildATensor(ctx, ins[1]); + + auto output = buildATensor(ctx, outs[0]); + + correlation_forward(input1, input2, output, kH, kW, patchH, patchW, padH, + padW, dilationH, dilationW, dilation_patchH, + dilation_patchW, dH, dW); +} + +void correlation_backward_cpu_parrots(HostContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kH, kW, patchH, patchW, padH, padW, dilationH, dilationW, dilation_patchH, + dilation_patchW, dH, dW; + SSAttrs(attr) + .get("kH", kH) + .get("kW", kW) + .get("patchH", patchH) + .get("patchW", patchW) + .get("padH", padH) + .get("padW", padW) + .get("dilationH", dilationH) + .get("dilationW", dilationW) + .get("dilation_patchH", dilation_patchH) + .get("dilation_patchW", dilation_patchW) + .get("dH", dH) + .get("dW", dW) + .done(); + + auto grad_output = buildATensor(ctx, ins[0]); + auto input1 = buildATensor(ctx, ins[1]); + auto input2 = buildATensor(ctx, ins[2]); + + auto grad_input1 = buildATensor(ctx, outs[0]); + auto grad_input2 = buildATensor(ctx, outs[1]); + + correlation_backward(grad_output, input1, input2, grad_input1, grad_input2, + kH, kW, patchH, patchW, padH, padW, dilationH, dilationW, + dilation_patchH, dilation_patchW, dH, dW); +} + +PARROTS_EXTENSION_REGISTER(correlation_forward) + .attr("kH") + .attr("kW") + .attr("patchH") + .attr("patchW") + .attr("padH") + .attr("padW") + .attr("dilationH") + .attr("dilationW") + .attr("dilation_patchH") + .attr("dilation_patchW") + .attr("dH") + .attr("dW") + .input(2) + .output(1) + .apply(correlation_forward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(correlation_forward_cuda_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(correlation_backward) + .attr("kH") + .attr("kW") + .attr("patchH") + .attr("patchW") + .attr("padH") + .attr("padW") + .attr("dilationH") + .attr("dilationW") + .attr("dilation_patchH") + .attr("dilation_patchW") + .attr("dH") + .attr("dW") + .input(3) + .output(2) + .apply(correlation_backward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(correlation_backward_cuda_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_pytorch.h new file mode 100644 index 000000000..806fcaa71 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_pytorch.h @@ -0,0 +1,18 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef CORRELATION_PYTORCH_H +#define CORRELATION_PYTORCH_H +#include +using namespace at; + +void correlation_forward(Tensor input1, Tensor input2, Tensor output, int kH, + int kW, int patchH, int patchW, int padH, int padW, + int dilationH, int dilationW, int dilation_patchH, + int dilation_patchW, int dH, int dW); + +void correlation_backward(Tensor grad_output, Tensor input1, Tensor input2, + Tensor grad_input1, Tensor grad_input2, int kH, + int kW, int patchH, int patchW, int padH, int padW, + int dilationH, int dilationW, int dilation_patchH, + int dilation_patchW, int dH, int dW); + +#endif // CORRELATION_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/cudabind.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/cudabind.cpp new file mode 100644 index 000000000..9627e26f4 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/cudabind.cpp @@ -0,0 +1,1677 @@ +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void AssignScoreWithKForwardCUDAKernelLauncher( + int B, int N0, int N1, int M, int K, int O, int aggregate, + const Tensor& points, const Tensor& centers, const Tensor& scores, + const Tensor& knn_idx, Tensor& output); + +void AssignScoreWithKBackwardCUDAKernelLauncher( + int B, int N0, int N1, int M, int K, int O, int aggregate, + const Tensor& grad_out, const Tensor& points, const Tensor& centers, + const Tensor& scores, const Tensor& knn_idx, Tensor& grad_points, + Tensor& grad_centers, Tensor& grad_scores); + +void assign_score_withk_forward_cuda(int B, int N0, int N1, int M, int K, int O, + int aggregate, const Tensor& points, + const Tensor& centers, + const Tensor& scores, + const Tensor& knn_idx, Tensor& output) { + AssignScoreWithKForwardCUDAKernelLauncher( + B, N0, N1, M, K, O, aggregate, points, centers, scores, knn_idx, output); +}; + +void assign_score_withk_backward_cuda( + int B, int N0, int N1, int M, int K, int O, int aggregate, + const Tensor& grad_out, const Tensor& points, const Tensor& centers, + const Tensor& scores, const Tensor& knn_idx, Tensor& grad_points, + Tensor& grad_centers, Tensor& grad_scores) { + AssignScoreWithKBackwardCUDAKernelLauncher( + B, N0, N1, M, K, O, aggregate, grad_out, points, centers, scores, knn_idx, + grad_points, grad_centers, grad_scores); +}; + +void assign_score_withk_forward_impl(int B, int N0, int N1, int M, int K, int O, + int aggregate, const Tensor& points, + const Tensor& centers, + const Tensor& scores, + const Tensor& knn_idx, Tensor& output); + +void assign_score_withk_backward_impl( + int B, int N0, int N1, int M, int K, int O, int aggregate, + const Tensor& grad_out, const Tensor& points, const Tensor& centers, + const Tensor& scores, const Tensor& knn_idx, Tensor& grad_points, + Tensor& grad_centers, Tensor& grad_scores); + +REGISTER_DEVICE_IMPL(assign_score_withk_forward_impl, CUDA, + assign_score_withk_forward_cuda); +REGISTER_DEVICE_IMPL(assign_score_withk_backward_impl, CUDA, + assign_score_withk_backward_cuda); + +void BallQueryForwardCUDAKernelLauncher(int b, int n, int m, float min_radius, + float max_radius, int nsample, + const Tensor new_xyz, const Tensor xyz, + Tensor idx); + +void ball_query_forward_cuda(int b, int n, int m, float min_radius, + float max_radius, int nsample, + const Tensor new_xyz, const Tensor xyz, + Tensor idx) { + BallQueryForwardCUDAKernelLauncher(b, n, m, min_radius, max_radius, nsample, + new_xyz, xyz, idx); +}; + +void ball_query_forward_impl(int b, int n, int m, float min_radius, + float max_radius, int nsample, + const Tensor new_xyz, const Tensor xyz, + Tensor idx); +REGISTER_DEVICE_IMPL(ball_query_forward_impl, CUDA, ball_query_forward_cuda); + +void BBoxOverlapsCUDAKernelLauncher(const Tensor bboxes1, const Tensor bboxes2, + Tensor ious, const int mode, + const bool aligned, const int offset); + +void bbox_overlaps_cuda(const Tensor bboxes1, const Tensor bboxes2, Tensor ious, + const int mode, const bool aligned, const int offset) { + BBoxOverlapsCUDAKernelLauncher(bboxes1, bboxes2, ious, mode, aligned, offset); +} + +void bbox_overlaps_impl(const Tensor bboxes1, const Tensor bboxes2, Tensor ious, + const int mode, const bool aligned, const int offset); +REGISTER_DEVICE_IMPL(bbox_overlaps_impl, CUDA, bbox_overlaps_cuda); + +void BorderAlignForwardCUDAKernelLauncher(const Tensor& input, + const Tensor& boxes, Tensor output, + Tensor argmax_idx, + const int pool_size); + +void BorderAlignBackwardCUDAKernelLauncher(const Tensor& grad_output, + const Tensor& boxes, + const Tensor& argmax_idx, + Tensor grad_input, + const int pool_size); + +void border_align_forward_cuda(const Tensor& input, const Tensor& boxes, + Tensor output, Tensor argmax_idx, + const int pool_size) { + BorderAlignForwardCUDAKernelLauncher(input, boxes, output, argmax_idx, + pool_size); +} + +void border_align_backward_cuda(const Tensor& grad_output, const Tensor& boxes, + const Tensor& argmax_idx, Tensor grad_input, + const int pool_size) { + BorderAlignBackwardCUDAKernelLauncher(grad_output, boxes, argmax_idx, + grad_input, pool_size); +} + +void border_align_forward_impl(const Tensor& input, const Tensor& boxes, + Tensor output, Tensor argmax_idx, + const int pool_size); + +void border_align_backward_impl(const Tensor& grad_output, const Tensor& boxes, + const Tensor& argmax_idx, Tensor grad_input, + const int pool_size); + +REGISTER_DEVICE_IMPL(border_align_forward_impl, CUDA, + border_align_forward_cuda); +REGISTER_DEVICE_IMPL(border_align_backward_impl, CUDA, + border_align_backward_cuda); + +void box_iou_rotated_cuda(const Tensor boxes1, const Tensor boxes2, Tensor ious, + const int mode_flag, const bool aligned); + +void box_iou_rotated_impl(const Tensor boxes1, const Tensor boxes2, Tensor ious, + const int mode_flag, const bool aligned); +REGISTER_DEVICE_IMPL(box_iou_rotated_impl, CUDA, box_iou_rotated_cuda); + +void CARAFEForwardCUDAKernelLauncher(const Tensor features, const Tensor masks, + Tensor rfeatures, Tensor routput, + Tensor rmasks, Tensor output, + const int kernel_size, + const int group_size, + const int scale_factor); + +void CARAFEBackwardCUDAKernelLauncher( + const Tensor top_grad, const Tensor rfeatures, const Tensor masks, + Tensor rtop_grad, Tensor rbottom_grad_hs, Tensor rbottom_grad, + Tensor rmask_grad, Tensor bottom_grad, Tensor mask_grad, + const int kernel_size, const int group_size, const int scale_factor); + +void carafe_forward_cuda(Tensor features, Tensor masks, Tensor rfeatures, + Tensor routput, Tensor rmasks, Tensor output, + int kernel_size, int group_size, int scale_factor) { + CARAFEForwardCUDAKernelLauncher(features, masks, rfeatures, routput, rmasks, + output, kernel_size, group_size, + scale_factor); +} + +void carafe_backward_cuda(Tensor top_grad, Tensor rfeatures, Tensor masks, + Tensor rtop_grad, Tensor rbottom_grad_hs, + Tensor rbottom_grad, Tensor rmask_grad, + Tensor bottom_grad, Tensor mask_grad, int kernel_size, + int group_size, int scale_factor) { + CARAFEBackwardCUDAKernelLauncher(top_grad, rfeatures, masks, rtop_grad, + rbottom_grad_hs, rbottom_grad, rmask_grad, + bottom_grad, mask_grad, kernel_size, + group_size, scale_factor); +} + +void carafe_forward_impl(Tensor features, Tensor masks, Tensor rfeatures, + Tensor routput, Tensor rmasks, Tensor output, + int kernel_size, int group_size, int scale_factor); + +void carafe_backward_impl(Tensor top_grad, Tensor rfeatures, Tensor masks, + Tensor rtop_grad, Tensor rbottom_grad_hs, + Tensor rbottom_grad, Tensor rmask_grad, + Tensor bottom_grad, Tensor mask_grad, int kernel_size, + int group_size, int scale_factor); + +REGISTER_DEVICE_IMPL(carafe_forward_impl, CUDA, carafe_forward_cuda); +REGISTER_DEVICE_IMPL(carafe_backward_impl, CUDA, carafe_backward_cuda); + +void CARAFENAIVEForwardCUDAKernelLauncher(const Tensor features, + const Tensor masks, Tensor output, + const int kernel_size, + const int group_size, + const int scale_factor); + +void CARAFENAIVEBackwardCUDAKernelLauncher( + const Tensor top_grad, const Tensor features, const Tensor masks, + Tensor bottom_grad, Tensor mask_grad, const int kernel_size, + const int group_size, const int scale_factor); + +void carafe_naive_forward_cuda(Tensor features, Tensor masks, Tensor output, + int kernel_size, int group_size, + int scale_factor) { + CARAFENAIVEForwardCUDAKernelLauncher(features, masks, output, kernel_size, + group_size, scale_factor); +} + +void carafe_naive_backward_cuda(Tensor top_grad, Tensor features, Tensor masks, + Tensor bottom_grad, Tensor mask_grad, + int kernel_size, int group_size, + int scale_factor) { + CARAFENAIVEBackwardCUDAKernelLauncher(top_grad, features, masks, bottom_grad, + mask_grad, kernel_size, group_size, + scale_factor); +} +void carafe_naive_forward_impl(Tensor features, Tensor masks, Tensor output, + int kernel_size, int group_size, + int scale_factor); + +void carafe_naive_backward_impl(Tensor top_grad, Tensor features, Tensor masks, + Tensor bottom_grad, Tensor mask_grad, + int kernel_size, int group_size, + int scale_factor); + +REGISTER_DEVICE_IMPL(carafe_naive_forward_impl, CUDA, + carafe_naive_forward_cuda); +REGISTER_DEVICE_IMPL(carafe_naive_backward_impl, CUDA, + carafe_naive_backward_cuda); + +void CorrelationForwardCUDAKernelLauncher(Tensor input1, Tensor input2, + Tensor output, int kH, int kW, + int patchH, int patchW, int padH, + int padW, int dilationH, + int dilationW, int dilation_patchH, + int dilation_patchW, int dH, int dW); + +void CorrelationBackwardCUDAKernelLauncher(Tensor grad_output, Tensor input1, + Tensor input2, Tensor grad_input1, + Tensor grad_input2, int kH, int kW, + int patchH, int patchW, int padH, + int padW, int dilationH, + int dilationW, int dilation_patchH, + int dilation_patchW, int dH, int dW); + +void correlation_forward_cuda(Tensor input1, Tensor input2, Tensor output, + int kH, int kW, int patchH, int patchW, int padH, + int padW, int dilationH, int dilationW, + int dilation_patchH, int dilation_patchW, int dH, + int dW) { + CorrelationForwardCUDAKernelLauncher( + input1, input2, output, kH, kW, patchH, patchW, padH, padW, dilationH, + dilationW, dilation_patchH, dilation_patchW, dH, dW); +} + +void correlation_backward_cuda(Tensor grad_output, Tensor input1, Tensor input2, + Tensor grad_input1, Tensor grad_input2, int kH, + int kW, int patchH, int patchW, int padH, + int padW, int dilationH, int dilationW, + int dilation_patchH, int dilation_patchW, int dH, + int dW) { + CorrelationBackwardCUDAKernelLauncher( + grad_output, input1, input2, grad_input1, grad_input2, kH, kW, patchH, + patchW, padH, padW, dilationH, dilationW, dilation_patchH, + dilation_patchW, dH, dW); +} + +void correlation_forward_impl(Tensor input1, Tensor input2, Tensor output, + int kH, int kW, int patchH, int patchW, int padH, + int padW, int dilationH, int dilationW, + int dilation_patchH, int dilation_patchW, int dH, + int dW); + +void correlation_backward_impl(Tensor grad_output, Tensor input1, Tensor input2, + Tensor grad_input1, Tensor grad_input2, int kH, + int kW, int patchH, int patchW, int padH, + int padW, int dilationH, int dilationW, + int dilation_patchH, int dilation_patchW, int dH, + int dW); + +REGISTER_DEVICE_IMPL(correlation_forward_impl, CUDA, correlation_forward_cuda); +REGISTER_DEVICE_IMPL(correlation_backward_impl, CUDA, + correlation_backward_cuda); + +void deformable_im2col_cuda(Tensor data_im, Tensor data_offset, + const int channels, const int height, + const int width, const int ksize_h, + const int ksize_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, + const int parallel_imgs, const int deformable_group, + Tensor data_col); + +void deformable_col2im_cuda(Tensor data_col, Tensor data_offset, + const int channels, const int height, + const int width, const int ksize_h, + const int ksize_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, + const int parallel_imgs, const int deformable_group, + Tensor grad_im); + +void deformable_col2im_coord_cuda( + Tensor data_col, Tensor data_im, Tensor data_offset, const int channels, + const int height, const int width, const int ksize_h, const int ksize_w, + const int pad_h, const int pad_w, const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, const int parallel_imgs, + const int deformable_group, Tensor grad_offset); + +void deformable_im2col_impl(Tensor data_im, Tensor data_offset, + const int channels, const int height, + const int width, const int ksize_h, + const int ksize_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, + const int parallel_imgs, const int deformable_group, + Tensor data_col); + +void deformable_col2im_impl(Tensor data_col, Tensor data_offset, + const int channels, const int height, + const int width, const int ksize_h, + const int ksize_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, + const int parallel_imgs, const int deformable_group, + Tensor grad_im); + +void deformable_col2im_coord_impl( + Tensor data_col, Tensor data_im, Tensor data_offset, const int channels, + const int height, const int width, const int ksize_h, const int ksize_w, + const int pad_h, const int pad_w, const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, const int parallel_imgs, + const int deformable_group, Tensor grad_offset); + +REGISTER_DEVICE_IMPL(deformable_im2col_impl, CUDA, deformable_im2col_cuda); +REGISTER_DEVICE_IMPL(deformable_col2im_impl, CUDA, deformable_col2im_cuda); +REGISTER_DEVICE_IMPL(deformable_col2im_coord_impl, CUDA, + deformable_col2im_coord_cuda); + +void DeformRoIPoolForwardCUDAKernelLauncher(Tensor input, Tensor rois, + Tensor offset, Tensor output, + int pooled_height, int pooled_width, + float spatial_scale, + int sampling_ratio, float gamma); + +void DeformRoIPoolBackwardCUDAKernelLauncher( + Tensor grad_output, Tensor input, Tensor rois, Tensor offset, + Tensor grad_input, Tensor grad_offset, int pooled_height, int pooled_width, + float spatial_scale, int sampling_ratio, float gamma); + +void deform_roi_pool_forward_cuda(Tensor input, Tensor rois, Tensor offset, + Tensor output, int pooled_height, + int pooled_width, float spatial_scale, + int sampling_ratio, float gamma) { + DeformRoIPoolForwardCUDAKernelLauncher(input, rois, offset, output, + pooled_height, pooled_width, + spatial_scale, sampling_ratio, gamma); +} + +void deform_roi_pool_backward_cuda(Tensor grad_output, Tensor input, + Tensor rois, Tensor offset, + Tensor grad_input, Tensor grad_offset, + int pooled_height, int pooled_width, + float spatial_scale, int sampling_ratio, + float gamma) { + DeformRoIPoolBackwardCUDAKernelLauncher( + grad_output, input, rois, offset, grad_input, grad_offset, pooled_height, + pooled_width, spatial_scale, sampling_ratio, gamma); +} + +void deform_roi_pool_forward_impl(Tensor input, Tensor rois, Tensor offset, + Tensor output, int pooled_height, + int pooled_width, float spatial_scale, + int sampling_ratio, float gamma); + +void deform_roi_pool_backward_impl(Tensor grad_output, Tensor input, + Tensor rois, Tensor offset, + Tensor grad_input, Tensor grad_offset, + int pooled_height, int pooled_width, + float spatial_scale, int sampling_ratio, + float gamma); + +REGISTER_DEVICE_IMPL(deform_roi_pool_forward_impl, CUDA, + deform_roi_pool_forward_cuda); +REGISTER_DEVICE_IMPL(deform_roi_pool_backward_impl, CUDA, + deform_roi_pool_backward_cuda); + +void SigmoidFocalLossForwardCUDAKernelLauncher(Tensor input, Tensor target, + Tensor weight, Tensor output, + const float gamma, + const float alpha); + +void SigmoidFocalLossBackwardCUDAKernelLauncher(Tensor input, Tensor target, + Tensor weight, + Tensor grad_input, + const float gamma, + const float alpha); + +void SoftmaxFocalLossForwardCUDAKernelLauncher(Tensor softmax, Tensor target, + Tensor weight, Tensor output, + const float gamma, + const float alpha); + +void SoftmaxFocalLossBackwardCUDAKernelLauncher(Tensor softmax, Tensor target, + Tensor weight, Tensor buff, + Tensor grad_input, + const float gamma, + const float alpha); + +void sigmoid_focal_loss_forward_cuda(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha) { + SigmoidFocalLossForwardCUDAKernelLauncher(input, target, weight, output, + gamma, alpha); +} + +void sigmoid_focal_loss_backward_cuda(Tensor input, Tensor target, + Tensor weight, Tensor grad_input, + float gamma, float alpha) { + SigmoidFocalLossBackwardCUDAKernelLauncher(input, target, weight, grad_input, + gamma, alpha); +} + +void softmax_focal_loss_forward_cuda(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha) { + SoftmaxFocalLossForwardCUDAKernelLauncher(input, target, weight, output, + gamma, alpha); +} + +void softmax_focal_loss_backward_cuda(Tensor input, Tensor target, + Tensor weight, Tensor buff, + Tensor grad_input, float gamma, + float alpha) { + SoftmaxFocalLossBackwardCUDAKernelLauncher(input, target, weight, buff, + grad_input, gamma, alpha); +} + +void sigmoid_focal_loss_forward_impl(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha); + +void sigmoid_focal_loss_backward_impl(Tensor input, Tensor target, + Tensor weight, Tensor grad_input, + float gamma, float alpha); + +void softmax_focal_loss_forward_impl(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha); + +void softmax_focal_loss_backward_impl(Tensor input, Tensor target, + Tensor weight, Tensor buff, + Tensor grad_input, float gamma, + float alpha); + +REGISTER_DEVICE_IMPL(sigmoid_focal_loss_forward_impl, CUDA, + sigmoid_focal_loss_forward_cuda); +REGISTER_DEVICE_IMPL(sigmoid_focal_loss_backward_impl, CUDA, + sigmoid_focal_loss_backward_cuda); +REGISTER_DEVICE_IMPL(softmax_focal_loss_forward_impl, CUDA, + softmax_focal_loss_forward_cuda); +REGISTER_DEVICE_IMPL(softmax_focal_loss_backward_impl, CUDA, + softmax_focal_loss_backward_cuda); + +void FurthestPointSamplingForwardCUDAKernelLauncher(int b, int n, int m, + const float* dataset, + float* temp, int* idxs); + +void FurthestPointSamplingWithDistForwardCUDAKernelLauncher( + int b, int n, int m, const float* dataset, float* temp, int* idxs); + +void furthest_point_sampling_forward_cuda(Tensor points_tensor, + Tensor temp_tensor, Tensor idx_tensor, + int b, int n, int m) { + const float* dataset = points_tensor.data_ptr(); + float* temp = temp_tensor.data_ptr(); + int* idxs = idx_tensor.data_ptr(); + FurthestPointSamplingForwardCUDAKernelLauncher(b, n, m, dataset, temp, idxs); +} + +void furthest_point_sampling_with_dist_forward_cuda(Tensor points_tensor, + Tensor temp_tensor, + Tensor idx_tensor, int b, + int n, int m) { + const float* dataset = points_tensor.data_ptr(); + float* temp = temp_tensor.data_ptr(); + int* idxs = idx_tensor.data_ptr(); + FurthestPointSamplingWithDistForwardCUDAKernelLauncher(b, n, m, dataset, temp, + idxs); +} + +void furthest_point_sampling_forward_impl(Tensor points_tensor, + Tensor temp_tensor, Tensor idx_tensor, + int b, int n, int m); + +void furthest_point_sampling_with_dist_forward_impl(Tensor points_tensor, + Tensor temp_tensor, + Tensor idx_tensor, int b, + int n, int m); + +REGISTER_DEVICE_IMPL(furthest_point_sampling_forward_impl, CUDA, + furthest_point_sampling_forward_cuda); +REGISTER_DEVICE_IMPL(furthest_point_sampling_with_dist_forward_impl, CUDA, + furthest_point_sampling_with_dist_forward_cuda); + +torch::Tensor fused_bias_leakyrelu_op(const torch::Tensor& input, + const torch::Tensor& bias, + const torch::Tensor& refer, int act, + int grad, float alpha, float scale); + +torch::Tensor fused_bias_leakyrelu_op_impl(const torch::Tensor& input, + const torch::Tensor& bias, + const torch::Tensor& refer, int act, + int grad, float alpha, float scale); +REGISTER_DEVICE_IMPL(fused_bias_leakyrelu_op_impl, CUDA, + fused_bias_leakyrelu_op); + +void GatherPointsForwardCUDAKernelLauncher(int b, int c, int n, int npoints, + const Tensor points, + const Tensor idx, Tensor out); + +void GatherPointsBackwardCUDAKernelLauncher(int b, int c, int n, int npoints, + const Tensor grad_out, + const Tensor idx, + Tensor grad_points); + +void gather_points_forward_cuda(int b, int c, int n, int npoints, + const Tensor points, const Tensor idx, + Tensor out) { + GatherPointsForwardCUDAKernelLauncher(b, c, n, npoints, points, idx, out); +}; + +void gather_points_backward_cuda(int b, int c, int n, int npoints, + const Tensor grad_out, const Tensor idx, + Tensor grad_points) { + GatherPointsBackwardCUDAKernelLauncher(b, c, n, npoints, grad_out, idx, + grad_points); +}; + +void gather_points_forward_impl(int b, int c, int n, int npoints, + const Tensor points, const Tensor idx, + Tensor out); + +void gather_points_backward_impl(int b, int c, int n, int npoints, + const Tensor grad_out, const Tensor idx, + Tensor grad_points); + +REGISTER_DEVICE_IMPL(gather_points_forward_impl, CUDA, + gather_points_forward_cuda); +REGISTER_DEVICE_IMPL(gather_points_backward_impl, CUDA, + gather_points_backward_cuda); + +void GroupPointsForwardCUDAKernelLauncher(int b, int c, int n, int npoints, + int nsample, const Tensor points, + const Tensor idx, Tensor out); + +void GroupPointsBackwardCUDAKernelLauncher(int b, int c, int n, int npoints, + int nsample, const Tensor grad_out, + const Tensor idx, + Tensor grad_points); + +void group_points_forward_cuda(int b, int c, int n, int npoints, int nsample, + const Tensor points, const Tensor idx, + Tensor out) { + GroupPointsForwardCUDAKernelLauncher(b, c, n, npoints, nsample, points, idx, + out); +}; + +void group_points_backward_cuda(int b, int c, int n, int npoints, int nsample, + const Tensor grad_out, const Tensor idx, + Tensor grad_points) { + GroupPointsBackwardCUDAKernelLauncher(b, c, n, npoints, nsample, grad_out, + idx, grad_points); +}; + +void group_points_forward_impl(int b, int c, int n, int npoints, int nsample, + const Tensor points, const Tensor idx, + Tensor out); + +void group_points_backward_impl(int b, int c, int n, int npoints, int nsample, + const Tensor grad_out, const Tensor idx, + Tensor grad_points); + +REGISTER_DEVICE_IMPL(group_points_forward_impl, CUDA, + group_points_forward_cuda); +REGISTER_DEVICE_IMPL(group_points_backward_impl, CUDA, + group_points_backward_cuda); + +void IoU3DBoxesOverlapBevForwardCUDAKernelLauncher(const int num_a, + const Tensor boxes_a, + const int num_b, + const Tensor boxes_b, + Tensor ans_overlap); + +void IoU3DNMS3DForwardCUDAKernelLauncher(const Tensor boxes, Tensor& keep, + Tensor& keep_num, + float nms_overlap_thresh); + +void IoU3DNMS3DNormalForwardCUDAKernelLauncher(const Tensor boxes, Tensor& keep, + Tensor& keep_num, + float nms_overlap_thresh); + +void iou3d_boxes_overlap_bev_forward_cuda(const int num_a, const Tensor boxes_a, + const int num_b, const Tensor boxes_b, + Tensor ans_overlap) { + IoU3DBoxesOverlapBevForwardCUDAKernelLauncher(num_a, boxes_a, num_b, boxes_b, + ans_overlap); +}; + +void iou3d_nms3d_forward_cuda(const Tensor boxes, Tensor& keep, + Tensor& keep_num, float nms_overlap_thresh) { + IoU3DNMS3DForwardCUDAKernelLauncher(boxes, keep, keep_num, + nms_overlap_thresh); +}; + +void iou3d_nms3d_normal_forward_cuda(const Tensor boxes, Tensor& keep, + Tensor& keep_num, + float nms_overlap_thresh) { + IoU3DNMS3DNormalForwardCUDAKernelLauncher(boxes, keep, keep_num, + nms_overlap_thresh); +}; + +void iou3d_boxes_overlap_bev_forward_impl(const int num_a, const Tensor boxes_a, + const int num_b, const Tensor boxes_b, + Tensor ans_overlap); + +void iou3d_nms3d_forward_impl(const Tensor boxes, Tensor& keep, + Tensor& keep_num, float nms_overlap_thresh); + +void iou3d_nms3d_normal_forward_impl(const Tensor boxes, Tensor& keep, + Tensor& keep_num, + float nms_overlap_thresh); + +REGISTER_DEVICE_IMPL(iou3d_boxes_overlap_bev_forward_impl, CUDA, + iou3d_boxes_overlap_bev_forward_cuda); +REGISTER_DEVICE_IMPL(iou3d_nms3d_forward_impl, CUDA, iou3d_nms3d_forward_cuda); +REGISTER_DEVICE_IMPL(iou3d_nms3d_normal_forward_impl, CUDA, + iou3d_nms3d_normal_forward_cuda); + +void KNNForwardCUDAKernelLauncher(int b, int n, int m, int nsample, + const Tensor xyz, const Tensor new_xyz, + Tensor idx, Tensor dist2); + +void knn_forward_cuda(int b, int n, int m, int nsample, const Tensor xyz, + const Tensor new_xyz, Tensor idx, Tensor dist2) { + KNNForwardCUDAKernelLauncher(b, n, m, nsample, xyz, new_xyz, idx, dist2); +} + +void knn_forward_impl(int b, int n, int m, int nsample, const Tensor xyz, + const Tensor new_xyz, Tensor idx, Tensor dist2); +REGISTER_DEVICE_IMPL(knn_forward_impl, CUDA, knn_forward_cuda); + +void MaskedIm2colForwardCUDAKernelLauncher(const Tensor bottom_data, + const Tensor mask_h_idx, + const Tensor mask_w_idx, + Tensor top_data, const int kernel_h, + const int kernel_w, const int pad_h, + const int pad_w); + +void MaskedCol2imForwardCUDAKernelLauncher(const Tensor bottom_data, + const Tensor mask_h_idx, + const Tensor mask_w_idx, + Tensor top_data, const int height, + const int width, const int channels); + +void masked_im2col_forward_cuda(const Tensor im, const Tensor mask_h_idx, + const Tensor mask_w_idx, Tensor col, + const int kernel_h, const int kernel_w, + const int pad_h, const int pad_w) { + // im: (n, ic, h, w), kernel size (kh, kw) + // kernel: (oc, ic * kh * kw), col: (kh * kw * ic, ow * oh) + MaskedIm2colForwardCUDAKernelLauncher(im, mask_h_idx, mask_w_idx, col, + kernel_h, kernel_w, pad_h, pad_w); +} + +void masked_col2im_forward_cuda(const Tensor col, const Tensor mask_h_idx, + const Tensor mask_w_idx, Tensor im, int height, + int width, int channels) { + // im: (n, ic, h, w), kernel size (kh, kw) + // kernel: (oc, ic * kh * kh), col: (kh * kw * ic, ow * oh) + MaskedCol2imForwardCUDAKernelLauncher(col, mask_h_idx, mask_w_idx, im, height, + width, channels); +} + +void masked_im2col_forward_impl(const Tensor im, const Tensor mask_h_idx, + const Tensor mask_w_idx, Tensor col, + const int kernel_h, const int kernel_w, + const int pad_h, const int pad_w); + +void masked_col2im_forward_impl(const Tensor col, const Tensor mask_h_idx, + const Tensor mask_w_idx, Tensor im, int height, + int width, int channels); + +REGISTER_DEVICE_IMPL(masked_im2col_forward_impl, CUDA, + masked_im2col_forward_cuda); +REGISTER_DEVICE_IMPL(masked_col2im_forward_impl, CUDA, + masked_col2im_forward_cuda); + +void modulated_deformable_im2col_cuda( + const Tensor data_im, const Tensor data_offset, const Tensor data_mask, + const int batch_size, const int channels, const int height_im, + const int width_im, const int height_col, const int width_col, + const int kernel_h, const int kernel_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, const int dilation_h, + const int dilation_w, const int deformable_group, Tensor data_col); + +void modulated_deformable_col2im_cuda( + const Tensor data_col, const Tensor data_offset, const Tensor data_mask, + const int batch_size, const int channels, const int height_im, + const int width_im, const int height_col, const int width_col, + const int kernel_h, const int kernel_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, const int dilation_h, + const int dilation_w, const int deformable_group, Tensor grad_im); + +void modulated_deformable_col2im_coord_cuda( + const Tensor data_col, const Tensor data_im, const Tensor data_offset, + const Tensor data_mask, const int batch_size, const int channels, + const int height_im, const int width_im, const int height_col, + const int width_col, const int kernel_h, const int kernel_w, + const int pad_h, const int pad_w, const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, const int deformable_group, + Tensor grad_offset, Tensor grad_mask); + +void modulated_deformable_im2col_impl( + const Tensor data_im, const Tensor data_offset, const Tensor data_mask, + const int batch_size, const int channels, const int height_im, + const int width_im, const int height_col, const int width_col, + const int kernel_h, const int kernel_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, const int dilation_h, + const int dilation_w, const int deformable_group, Tensor data_col); + +void modulated_deformable_col2im_impl( + const Tensor data_col, const Tensor data_offset, const Tensor data_mask, + const int batch_size, const int channels, const int height_im, + const int width_im, const int height_col, const int width_col, + const int kernel_h, const int kernel_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, const int dilation_h, + const int dilation_w, const int deformable_group, Tensor grad_im); + +void modulated_deformable_col2im_coord_impl( + const Tensor data_col, const Tensor data_im, const Tensor data_offset, + const Tensor data_mask, const int batch_size, const int channels, + const int height_im, const int width_im, const int height_col, + const int width_col, const int kernel_h, const int kernel_w, + const int pad_h, const int pad_w, const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, const int deformable_group, + Tensor grad_offset, Tensor grad_mask); + +REGISTER_DEVICE_IMPL(modulated_deformable_im2col_impl, CUDA, + modulated_deformable_im2col_cuda); +REGISTER_DEVICE_IMPL(modulated_deformable_col2im_impl, CUDA, + modulated_deformable_col2im_cuda); +REGISTER_DEVICE_IMPL(modulated_deformable_col2im_coord_impl, CUDA, + modulated_deformable_col2im_coord_cuda); + +Tensor ms_deform_attn_cuda_forward(const Tensor& value, + const Tensor& spatial_shapes, + const Tensor& level_start_index, + const Tensor& sampling_loc, + const Tensor& attn_weight, + const int im2col_step); + +void ms_deform_attn_cuda_backward( + const Tensor& value, const Tensor& spatial_shapes, + const Tensor& level_start_index, const Tensor& sampling_loc, + const Tensor& attn_weight, const Tensor& grad_output, Tensor& grad_value, + Tensor& grad_sampling_loc, Tensor& grad_attn_weight, const int im2col_step); + +Tensor ms_deform_attn_impl_forward(const Tensor& value, + const Tensor& spatial_shapes, + const Tensor& level_start_index, + const Tensor& sampling_loc, + const Tensor& attn_weight, + const int im2col_step); + +void ms_deform_attn_impl_backward( + const Tensor& value, const Tensor& spatial_shapes, + const Tensor& level_start_index, const Tensor& sampling_loc, + const Tensor& attn_weight, const Tensor& grad_output, Tensor& grad_value, + Tensor& grad_sampling_loc, Tensor& grad_attn_weight, const int im2col_step); + +REGISTER_DEVICE_IMPL(ms_deform_attn_impl_forward, CUDA, + ms_deform_attn_cuda_forward); +REGISTER_DEVICE_IMPL(ms_deform_attn_impl_backward, CUDA, + ms_deform_attn_cuda_backward); + +Tensor NMSCUDAKernelLauncher(Tensor boxes, Tensor scores, float iou_threshold, + int offset); + +Tensor nms_cuda(Tensor boxes, Tensor scores, float iou_threshold, int offset) { + return NMSCUDAKernelLauncher(boxes, scores, iou_threshold, offset); +} + +Tensor nms_impl(Tensor boxes, Tensor scores, float iou_threshold, int offset); +REGISTER_DEVICE_IMPL(nms_impl, CUDA, nms_cuda); + +void PointsInBoxesPartForwardCUDAKernelLauncher(int batch_size, int boxes_num, + int pts_num, const Tensor boxes, + const Tensor pts, + Tensor box_idx_of_points); + +void PointsInBoxesAllForwardCUDAKernelLauncher(int batch_size, int boxes_num, + int pts_num, const Tensor boxes, + const Tensor pts, + Tensor box_idx_of_points); + +void points_in_boxes_part_forward_cuda(int batch_size, int boxes_num, + int pts_num, const Tensor boxes, + const Tensor pts, + Tensor box_idx_of_points) { + PointsInBoxesPartForwardCUDAKernelLauncher(batch_size, boxes_num, pts_num, + boxes, pts, box_idx_of_points); +}; + +void points_in_boxes_all_forward_cuda(int batch_size, int boxes_num, + int pts_num, const Tensor boxes, + const Tensor pts, + Tensor box_idx_of_points) { + PointsInBoxesAllForwardCUDAKernelLauncher(batch_size, boxes_num, pts_num, + boxes, pts, box_idx_of_points); +}; + +void points_in_boxes_part_forward_impl(int batch_size, int boxes_num, + int pts_num, const Tensor boxes, + const Tensor pts, + Tensor box_idx_of_points); + +void points_in_boxes_all_forward_impl(int batch_size, int boxes_num, + int pts_num, const Tensor boxes, + const Tensor pts, + Tensor box_idx_of_points); +REGISTER_DEVICE_IMPL(points_in_boxes_part_forward_impl, CUDA, + points_in_boxes_part_forward_cuda); +REGISTER_DEVICE_IMPL(points_in_boxes_all_forward_impl, CUDA, + points_in_boxes_all_forward_cuda); + +void PSAMaskForwardCUDAKernelLauncher(const int psa_type, const Tensor input, + Tensor output, const int num_, + const int h_feature, const int w_feature, + const int h_mask, const int w_mask, + const int half_h_mask, + const int half_w_mask); + +void PSAMaskBackwardCUDAKernelLauncher( + const int psa_type, const Tensor grad_output, Tensor grad_input, + const int num_, const int h_feature, const int w_feature, const int h_mask, + const int w_mask, const int half_h_mask, const int half_w_mask); + +void psamask_forward_cuda(const int psa_type, const Tensor input, Tensor output, + const int num_, const int h_feature, + const int w_feature, const int h_mask, + const int w_mask, const int half_h_mask, + const int half_w_mask) { + PSAMaskForwardCUDAKernelLauncher(psa_type, input, output, num_, h_feature, + w_feature, h_mask, w_mask, half_h_mask, + half_w_mask); +} + +void psamask_backward_cuda(const int psa_type, const Tensor grad_output, + Tensor grad_input, const int num_, + const int h_feature, const int w_feature, + const int h_mask, const int w_mask, + const int half_h_mask, const int half_w_mask) { + PSAMaskBackwardCUDAKernelLauncher(psa_type, grad_output, grad_input, num_, + h_feature, w_feature, h_mask, w_mask, + half_h_mask, half_w_mask); +} + +void psamask_forward_impl(const int psa_type, const Tensor input, Tensor output, + const int num_, const int h_feature, + const int w_feature, const int h_mask, + const int w_mask, const int half_h_mask, + const int half_w_mask); + +void psamask_backward_impl(const int psa_type, const Tensor grad_output, + Tensor grad_input, const int num_, + const int h_feature, const int w_feature, + const int h_mask, const int w_mask, + const int half_h_mask, const int half_w_mask); +REGISTER_DEVICE_IMPL(psamask_forward_impl, CUDA, psamask_forward_cuda); +REGISTER_DEVICE_IMPL(psamask_backward_impl, CUDA, psamask_backward_cuda); + +void ROIAlignForwardCUDAKernelLauncher(Tensor input, Tensor rois, Tensor output, + Tensor argmax_y, Tensor argmax_x, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned); + +void ROIAlignBackwardCUDAKernelLauncher(Tensor grad_output, Tensor rois, + Tensor argmax_y, Tensor argmax_x, + Tensor grad_input, int aligned_height, + int aligned_width, float spatial_scale, + int sampling_ratio, int pool_mode, + bool aligned); + +void roi_align_forward_cuda(Tensor input, Tensor rois, Tensor output, + Tensor argmax_y, Tensor argmax_x, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned) { + ROIAlignForwardCUDAKernelLauncher( + input, rois, output, argmax_y, argmax_x, aligned_height, aligned_width, + spatial_scale, sampling_ratio, pool_mode, aligned); +} + +void roi_align_backward_cuda(Tensor grad_output, Tensor rois, Tensor argmax_y, + Tensor argmax_x, Tensor grad_input, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned) { + ROIAlignBackwardCUDAKernelLauncher( + grad_output, rois, argmax_y, argmax_x, grad_input, aligned_height, + aligned_width, spatial_scale, sampling_ratio, pool_mode, aligned); +} + +void roi_align_forward_impl(Tensor input, Tensor rois, Tensor output, + Tensor argmax_y, Tensor argmax_x, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned); + +void roi_align_backward_impl(Tensor grad_output, Tensor rois, Tensor argmax_y, + Tensor argmax_x, Tensor grad_input, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned); + +REGISTER_DEVICE_IMPL(roi_align_forward_impl, CUDA, roi_align_forward_cuda); +REGISTER_DEVICE_IMPL(roi_align_backward_impl, CUDA, roi_align_backward_cuda); + +void ROIAlignRotatedForwardCUDAKernelLauncher( + const at::Tensor input, const at::Tensor rois, const float spatial_scale, + const int sampling_ratio, const bool aligned, const bool clockwise, + const int channels, const int height, const int width, const int num_rois, + const int pooled_height, const int pooled_width, at::Tensor output); + +void ROIAlignRotatedBackwardCUDAKernelLauncher( + const at::Tensor top_grad, const at::Tensor rois, const float spatial_scale, + const int sampling_ratio, const bool aligned, const bool clockwise, + const int channels, const int height, const int width, const int num_rois, + const int pooled_height, const int pooled_width, at::Tensor bottom_grad); + +void roi_align_rotated_forward_cuda(Tensor input, Tensor rois, Tensor output, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + bool aligned, bool clockwise) { + // Number of ROIs + int num_rois = rois.size(0); + int size_rois = rois.size(1); + + if (size_rois != 6) { + AT_ERROR("wrong roi size"); + } + + int num_channels = input.size(1); + int data_height = input.size(2); + int data_width = input.size(3); + ROIAlignRotatedForwardCUDAKernelLauncher( + input, rois, spatial_scale, sampling_ratio, aligned, clockwise, + num_channels, data_height, data_width, num_rois, aligned_height, + aligned_width, output); +} + +void roi_align_rotated_backward_cuda(Tensor top_grad, Tensor rois, + Tensor bottom_grad, int aligned_height, + int aligned_width, float spatial_scale, + int sampling_ratio, bool aligned, + bool clockwise) { + // Number of ROIs + int num_rois = rois.size(0); + int size_rois = rois.size(1); + if (size_rois != 6) { + AT_ERROR("wrong roi size"); + } + + int num_channels = bottom_grad.size(1); + int data_height = bottom_grad.size(2); + int data_width = bottom_grad.size(3); + ROIAlignRotatedBackwardCUDAKernelLauncher( + top_grad, rois, spatial_scale, sampling_ratio, aligned, clockwise, + num_channels, data_height, data_width, num_rois, aligned_height, + aligned_width, bottom_grad); +} + +void roi_align_rotated_forward_impl(Tensor input, Tensor rois, Tensor output, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + bool aligned, bool clockwise); + +void roi_align_rotated_backward_impl(Tensor top_grad, Tensor rois, + Tensor bottom_grad, int aligned_height, + int aligned_width, float spatial_scale, + int sampling_ratio, bool aligned, + bool clockwise); +REGISTER_DEVICE_IMPL(roi_align_rotated_forward_impl, CUDA, + roi_align_rotated_forward_cuda); +REGISTER_DEVICE_IMPL(roi_align_rotated_backward_impl, CUDA, + roi_align_rotated_backward_cuda); + +void RiROIAlignRotatedForwardCUDAKernelLauncher( + const at::Tensor features, const at::Tensor rois, const float spatial_scale, + const int num_samples, const bool clockwise, const int channels, + const int height, const int width, const int num_rois, + const int pooled_height, const int pooled_width, const int num_orientations, + at::Tensor output); + +void RiROIAlignRotatedBackwardCUDAKernelLauncher( + const at::Tensor top_grad, const at::Tensor rois, const float spatial_scale, + const int num_samples, const bool clockwise, const int channels, + const int height, const int width, const int num_rois, + const int pooled_height, const int pooled_width, const int num_orientations, + at::Tensor bottom_grad); + +void riroi_align_rotated_forward_cuda(Tensor features, Tensor rois, + Tensor output, int pooled_height, + int pooled_width, float spatial_scale, + int num_samples, int num_orientations, + bool clockwise) { + // Number of ROIs + int num_rois = rois.size(0); + int size_rois = rois.size(1); + if (size_rois != 6) { + AT_ERROR("wrong roi size"); + } + CHECK_CONTIGUOUS(features); + CHECK_CONTIGUOUS(rois); + int num_channels = features.size(1) / num_orientations; + int data_height = features.size(2); + int data_width = features.size(3); + RiROIAlignRotatedForwardCUDAKernelLauncher( + features, rois, spatial_scale, num_samples, clockwise, num_channels, + data_height, data_width, num_rois, pooled_height, pooled_width, + num_orientations, output); +} + +void riroi_align_rotated_backward_cuda(Tensor top_grad, Tensor rois, + Tensor bottom_grad, int pooled_height, + int pooled_width, float spatial_scale, + int num_samples, int num_orientations, + bool clockwise) { + // Number of ROIs + int num_rois = rois.size(0); + int size_rois = rois.size(1); + if (size_rois != 6) { + AT_ERROR("wrong roi size"); + } + CHECK_CONTIGUOUS(top_grad); + CHECK_CONTIGUOUS(rois); + int num_channels = bottom_grad.size(1) / num_orientations; + int data_height = bottom_grad.size(2); + int data_width = bottom_grad.size(3); + RiROIAlignRotatedBackwardCUDAKernelLauncher( + top_grad, rois, spatial_scale, num_samples, clockwise, num_channels, + data_height, data_width, num_rois, pooled_height, pooled_width, + num_orientations, bottom_grad); +} + +void riroi_align_rotated_forward_impl(Tensor features, Tensor rois, + Tensor output, int pooled_height, + int pooled_width, float spatial_scale, + int num_samples, int num_orientations, + bool clockwise); + +void riroi_align_rotated_backward_impl(Tensor top_grad, Tensor rois, + Tensor bottom_grad, int pooled_height, + int pooled_width, float spatial_scale, + int num_samples, int num_orientations, + bool clockwise); + +REGISTER_DEVICE_IMPL(riroi_align_rotated_forward_impl, CUDA, + riroi_align_rotated_forward_cuda); +REGISTER_DEVICE_IMPL(riroi_align_rotated_backward_impl, CUDA, + riroi_align_rotated_backward_cuda); + +void RoiawarePool3dForwardCUDAKernelLauncher( + int boxes_num, int pts_num, int channels, int max_pts_each_voxel, int out_x, + int out_y, int out_z, const Tensor rois, const Tensor pts, + const Tensor pts_feature, Tensor argmax, Tensor pts_idx_of_voxels, + Tensor pooled_features, int pool_method); + +void RoiawarePool3dBackwardCUDAKernelLauncher( + int boxes_num, int out_x, int out_y, int out_z, int channels, + int max_pts_each_voxel, const Tensor pts_idx_of_voxels, const Tensor argmax, + const Tensor grad_out, Tensor grad_in, int pool_method); + +void roiaware_pool3d_forward_cuda(int boxes_num, int pts_num, int channels, + int max_pts_each_voxel, int out_x, int out_y, + int out_z, const Tensor rois, + const Tensor pts, const Tensor pts_feature, + Tensor argmax, Tensor pts_idx_of_voxels, + Tensor pooled_features, int pool_method) { + RoiawarePool3dForwardCUDAKernelLauncher( + boxes_num, pts_num, channels, max_pts_each_voxel, out_x, out_y, out_z, + rois, pts, pts_feature, argmax, pts_idx_of_voxels, pooled_features, + pool_method); +}; + +void roiaware_pool3d_backward_cuda(int boxes_num, int out_x, int out_y, + int out_z, int channels, + int max_pts_each_voxel, + const Tensor pts_idx_of_voxels, + const Tensor argmax, const Tensor grad_out, + Tensor grad_in, int pool_method) { + RoiawarePool3dBackwardCUDAKernelLauncher( + boxes_num, out_x, out_y, out_z, channels, max_pts_each_voxel, + pts_idx_of_voxels, argmax, grad_out, grad_in, pool_method); +}; + +void roiaware_pool3d_forward_impl(int boxes_num, int pts_num, int channels, + int max_pts_each_voxel, int out_x, int out_y, + int out_z, const Tensor rois, + const Tensor pts, const Tensor pts_feature, + Tensor argmax, Tensor pts_idx_of_voxels, + Tensor pooled_features, int pool_method); + +void roiaware_pool3d_backward_impl(int boxes_num, int out_x, int out_y, + int out_z, int channels, + int max_pts_each_voxel, + const Tensor pts_idx_of_voxels, + const Tensor argmax, const Tensor grad_out, + Tensor grad_in, int pool_method); + +REGISTER_DEVICE_IMPL(roiaware_pool3d_forward_impl, CUDA, + roiaware_pool3d_forward_cuda); +REGISTER_DEVICE_IMPL(roiaware_pool3d_backward_impl, CUDA, + roiaware_pool3d_backward_cuda); + +void RoIPointPool3dForwardCUDAKernelLauncher( + int batch_size, int pts_num, int boxes_num, int feature_in_len, + int sampled_pts_num, const Tensor xyz, const Tensor boxes3d, + const Tensor pts_feature, Tensor pooled_features, Tensor pooled_empty_flag); + +void roipoint_pool3d_forward_cuda(int batch_size, int pts_num, int boxes_num, + int feature_in_len, int sampled_pts_num, + const Tensor xyz, const Tensor boxes3d, + const Tensor pts_feature, + Tensor pooled_features, + Tensor pooled_empty_flag) { + RoIPointPool3dForwardCUDAKernelLauncher( + batch_size, pts_num, boxes_num, feature_in_len, sampled_pts_num, xyz, + boxes3d, pts_feature, pooled_features, pooled_empty_flag); +}; + +void roipoint_pool3d_forward_impl(int batch_size, int pts_num, int boxes_num, + int feature_in_len, int sampled_pts_num, + const Tensor xyz, const Tensor boxes3d, + const Tensor pts_feature, + Tensor pooled_features, + Tensor pooled_empty_flag); +REGISTER_DEVICE_IMPL(roipoint_pool3d_forward_impl, CUDA, + roipoint_pool3d_forward_cuda); + +void ROIPoolForwardCUDAKernelLauncher(Tensor input, Tensor rois, Tensor output, + Tensor argmax, int pooled_height, + int pooled_width, float spatial_scale); + +void ROIPoolBackwardCUDAKernelLauncher(Tensor grad_output, Tensor rois, + Tensor argmax, Tensor grad_input, + int pooled_height, int pooled_width, + float spatial_scale); + +void roi_pool_forward_cuda(Tensor input, Tensor rois, Tensor output, + Tensor argmax, int pooled_height, int pooled_width, + float spatial_scale) { + ROIPoolForwardCUDAKernelLauncher(input, rois, output, argmax, pooled_height, + pooled_width, spatial_scale); +} + +void roi_pool_backward_cuda(Tensor grad_output, Tensor rois, Tensor argmax, + Tensor grad_input, int pooled_height, + int pooled_width, float spatial_scale) { + ROIPoolBackwardCUDAKernelLauncher(grad_output, rois, argmax, grad_input, + pooled_height, pooled_width, spatial_scale); +} + +void roi_pool_forward_impl(Tensor input, Tensor rois, Tensor output, + Tensor argmax, int pooled_height, int pooled_width, + float spatial_scale); +void roi_pool_backward_impl(Tensor grad_output, Tensor rois, Tensor argmax, + Tensor grad_input, int pooled_height, + int pooled_width, float spatial_scale); +REGISTER_DEVICE_IMPL(roi_pool_forward_impl, CUDA, roi_pool_forward_cuda); +REGISTER_DEVICE_IMPL(roi_pool_backward_impl, CUDA, roi_pool_backward_cuda); + +typedef enum { SUM = 0, MEAN = 1, MAX = 2 } reduce_t; + +std::vector DynamicPointToVoxelForwardCUDAKernelLauncher( + const at::Tensor& feats, const at::Tensor& coors, + const reduce_t reduce_type); + +void DynamicPointToVoxelBackwardCUDAKernelLauncher( + at::Tensor& grad_feats, const at::Tensor& grad_reduced_feats, + const at::Tensor& feats, const at::Tensor& reduced_feats, + const at::Tensor& coors_map, const at::Tensor& reduce_count, + const reduce_t reduce_type); + +std::vector dynamic_point_to_voxel_forward_cuda( + const torch::Tensor& feats, const torch::Tensor& coors, + const reduce_t reduce_type) { + return DynamicPointToVoxelForwardCUDAKernelLauncher(feats, coors, + reduce_type); +}; + +void dynamic_point_to_voxel_backward_cuda( + torch::Tensor& grad_feats, const torch::Tensor& grad_reduced_feats, + const torch::Tensor& feats, const torch::Tensor& reduced_feats, + const torch::Tensor& coors_idx, const torch::Tensor& reduce_count, + const reduce_t reduce_type) { + DynamicPointToVoxelBackwardCUDAKernelLauncher(grad_feats, grad_reduced_feats, + feats, reduced_feats, coors_idx, + reduce_count, reduce_type); +}; + +std::vector dynamic_point_to_voxel_forward_impl( + const torch::Tensor& feats, const torch::Tensor& coors, + const reduce_t reduce_type); + +void dynamic_point_to_voxel_backward_impl( + torch::Tensor& grad_feats, const torch::Tensor& grad_reduced_feats, + const torch::Tensor& feats, const torch::Tensor& reduced_feats, + const torch::Tensor& coors_idx, const torch::Tensor& reduce_count, + const reduce_t reduce_type); + +REGISTER_DEVICE_IMPL(dynamic_point_to_voxel_forward_impl, CUDA, + dynamic_point_to_voxel_forward_cuda); +REGISTER_DEVICE_IMPL(dynamic_point_to_voxel_backward_impl, CUDA, + dynamic_point_to_voxel_backward_cuda); + +void SyncBNForwardMeanCUDAKernelLauncher(const Tensor input, Tensor mean); + +void SyncBNForwardVarCUDAKernelLauncher(const Tensor input, const Tensor mean, + Tensor var); + +void SyncBNForwardOutputCUDAKernelLauncher( + const Tensor input, const Tensor mean, const Tensor var, + Tensor running_mean, Tensor running_var, const Tensor weight, + const Tensor bias, Tensor norm, Tensor std, Tensor output, float eps, + float momentum, int group_size); + +void SyncBNBackwardParamCUDAKernelLauncher(const Tensor grad_output, + const Tensor norm, + Tensor grad_weight, + Tensor grad_bias); + +void SyncBNBackwardDataCUDAKernelLauncher(const Tensor grad_output, + const Tensor weight, + const Tensor grad_weight, + const Tensor grad_bias, + const Tensor norm, const Tensor std, + Tensor grad_input); + +void sync_bn_forward_mean_cuda(const Tensor input, Tensor mean) { + SyncBNForwardMeanCUDAKernelLauncher(input, mean); +} + +void sync_bn_forward_var_cuda(const Tensor input, const Tensor mean, + Tensor var) { + SyncBNForwardVarCUDAKernelLauncher(input, mean, var); +} + +void sync_bn_forward_output_cuda(const Tensor input, const Tensor mean, + const Tensor var, Tensor running_mean, + Tensor running_var, const Tensor weight, + const Tensor bias, Tensor norm, Tensor std, + Tensor output, float eps, float momentum, + int group_size) { + SyncBNForwardOutputCUDAKernelLauncher(input, mean, var, running_mean, + running_var, weight, bias, norm, std, + output, eps, momentum, group_size); +} + +void sync_bn_backward_param_cuda(const Tensor grad_output, const Tensor norm, + Tensor grad_weight, Tensor grad_bias) { + SyncBNBackwardParamCUDAKernelLauncher(grad_output, norm, grad_weight, + grad_bias); +} + +void sync_bn_backward_data_cuda(const Tensor grad_output, const Tensor weight, + const Tensor grad_weight, + const Tensor grad_bias, const Tensor norm, + const Tensor std, Tensor grad_input) { + SyncBNBackwardDataCUDAKernelLauncher(grad_output, weight, grad_weight, + grad_bias, norm, std, grad_input); +} + +void sync_bn_forward_mean_impl(const Tensor input, Tensor mean); + +void sync_bn_forward_var_impl(const Tensor input, const Tensor mean, + Tensor var); + +void sync_bn_forward_output_impl(const Tensor input, const Tensor mean, + const Tensor var, Tensor running_mean, + Tensor running_var, const Tensor weight, + const Tensor bias, Tensor norm, Tensor std, + Tensor output, float eps, float momentum, + int group_size); + +void sync_bn_backward_param_impl(const Tensor grad_output, const Tensor norm, + Tensor grad_weight, Tensor grad_bias); + +void sync_bn_backward_data_impl(const Tensor grad_output, const Tensor weight, + const Tensor grad_weight, + const Tensor grad_bias, const Tensor norm, + const Tensor std, Tensor grad_input); + +REGISTER_DEVICE_IMPL(sync_bn_forward_mean_impl, CUDA, + sync_bn_forward_mean_cuda); +REGISTER_DEVICE_IMPL(sync_bn_forward_var_impl, CUDA, sync_bn_forward_var_cuda); +REGISTER_DEVICE_IMPL(sync_bn_forward_output_impl, CUDA, + sync_bn_forward_output_cuda); +REGISTER_DEVICE_IMPL(sync_bn_backward_param_impl, CUDA, + sync_bn_backward_param_cuda); +REGISTER_DEVICE_IMPL(sync_bn_backward_data_impl, CUDA, + sync_bn_backward_data_cuda); + +void ThreeInterpolateForwardCUDAKernelLauncher(int b, int c, int m, int n, + const Tensor points, + const Tensor idx, + const Tensor weight, Tensor out); + +void ThreeInterpolateBackwardCUDAKernelLauncher(int b, int c, int n, int m, + const Tensor grad_out, + const Tensor idx, + const Tensor weight, + Tensor grad_points); + +void three_interpolate_forward_cuda(int b, int c, int m, int n, + const Tensor points, const Tensor idx, + const Tensor weight, Tensor out) { + ThreeInterpolateForwardCUDAKernelLauncher(b, c, m, n, points, idx, weight, + out); +}; + +void three_interpolate_backward_cuda(int b, int c, int n, int m, + const Tensor grad_out, const Tensor idx, + const Tensor weight, Tensor grad_points) { + ThreeInterpolateBackwardCUDAKernelLauncher(b, c, n, m, grad_out, idx, weight, + grad_points); +}; + +void three_interpolate_forward_impl(int b, int c, int m, int n, + const Tensor points, const Tensor idx, + const Tensor weight, Tensor out); + +void three_interpolate_backward_impl(int b, int c, int n, int m, + const Tensor grad_out, const Tensor idx, + const Tensor weight, Tensor grad_points); +REGISTER_DEVICE_IMPL(three_interpolate_forward_impl, CUDA, + three_interpolate_forward_cuda); +REGISTER_DEVICE_IMPL(three_interpolate_backward_impl, CUDA, + three_interpolate_backward_cuda); + +void ThreeNNForwardCUDAKernelLauncher(int b, int n, int m, const Tensor unknown, + const Tensor known, Tensor dist2, + Tensor idx); + +void three_nn_forward_cuda(int b, int n, int m, const Tensor unknown, + const Tensor known, Tensor dist2, Tensor idx) { + ThreeNNForwardCUDAKernelLauncher(b, n, m, unknown, known, dist2, idx); +}; + +void three_nn_forward_impl(int b, int n, int m, const Tensor unknown, + const Tensor known, Tensor dist2, Tensor idx); +REGISTER_DEVICE_IMPL(three_nn_forward_impl, CUDA, three_nn_forward_cuda); + +void TINShiftForwardCUDAKernelLauncher(Tensor input, Tensor shift, + Tensor output); + +void TINShiftBackwardCUDAKernelLauncher(Tensor grad_output, Tensor shift, + Tensor grad_input); + +void tin_shift_forward_cuda(Tensor input, Tensor shift, Tensor output) { + TINShiftForwardCUDAKernelLauncher(input, shift, output); +} + +void tin_shift_backward_cuda(Tensor grad_output, Tensor shift, + Tensor grad_input) { + TINShiftBackwardCUDAKernelLauncher(grad_output, shift, grad_input); +} + +void tin_shift_forward_impl(Tensor input, Tensor shift, Tensor output); +void tin_shift_backward_impl(Tensor grad_output, Tensor shift, + Tensor grad_input); +REGISTER_DEVICE_IMPL(tin_shift_forward_impl, CUDA, tin_shift_forward_cuda); +REGISTER_DEVICE_IMPL(tin_shift_backward_impl, CUDA, tin_shift_backward_cuda); + +torch::Tensor upfirdn2d_op(const torch::Tensor& input, + const torch::Tensor& kernel, int up_x, int up_y, + int down_x, int down_y, int pad_x0, int pad_x1, + int pad_y0, int pad_y1); + +torch::Tensor upfirdn2d_op_impl(const torch::Tensor& input, + const torch::Tensor& kernel, int up_x, int up_y, + int down_x, int down_y, int pad_x0, int pad_x1, + int pad_y0, int pad_y1); +REGISTER_DEVICE_IMPL(upfirdn2d_op_impl, CUDA, upfirdn2d_op); + +int HardVoxelizeForwardCUDAKernelLauncher( + const at::Tensor& points, at::Tensor& voxels, at::Tensor& coors, + at::Tensor& num_points_per_voxel, const std::vector voxel_size, + const std::vector coors_range, const int max_points, + const int max_voxels, const int NDim = 3); + +int NondeterministicHardVoxelizeForwardCUDAKernelLauncher( + const at::Tensor& points, at::Tensor& voxels, at::Tensor& coors, + at::Tensor& num_points_per_voxel, const std::vector voxel_size, + const std::vector coors_range, const int max_points, + const int max_voxels, const int NDim = 3); + +void DynamicVoxelizeForwardCUDAKernelLauncher( + const at::Tensor& points, at::Tensor& coors, + const std::vector voxel_size, const std::vector coors_range, + const int NDim = 3); + +int hard_voxelize_forward_cuda(const at::Tensor& points, at::Tensor& voxels, + at::Tensor& coors, + at::Tensor& num_points_per_voxel, + const std::vector voxel_size, + const std::vector coors_range, + const int max_points, const int max_voxels, + const int NDim) { + return HardVoxelizeForwardCUDAKernelLauncher( + points, voxels, coors, num_points_per_voxel, voxel_size, coors_range, + max_points, max_voxels, NDim); +}; + +int nondeterministic_hard_voxelize_forward_cuda( + const at::Tensor& points, at::Tensor& voxels, at::Tensor& coors, + at::Tensor& num_points_per_voxel, const std::vector voxel_size, + const std::vector coors_range, const int max_points, + const int max_voxels, const int NDim) { + return NondeterministicHardVoxelizeForwardCUDAKernelLauncher( + points, voxels, coors, num_points_per_voxel, voxel_size, coors_range, + max_points, max_voxels, NDim); +}; + +void dynamic_voxelize_forward_cuda(const at::Tensor& points, at::Tensor& coors, + const std::vector voxel_size, + const std::vector coors_range, + const int NDim) { + DynamicVoxelizeForwardCUDAKernelLauncher(points, coors, voxel_size, + coors_range, NDim); +}; + +int hard_voxelize_forward_impl(const at::Tensor& points, at::Tensor& voxels, + at::Tensor& coors, + at::Tensor& num_points_per_voxel, + const std::vector voxel_size, + const std::vector coors_range, + const int max_points, const int max_voxels, + const int NDim); + +int nondeterministic_hard_voxelize_forward_impl( + const at::Tensor& points, at::Tensor& voxels, at::Tensor& coors, + at::Tensor& num_points_per_voxel, const std::vector voxel_size, + const std::vector coors_range, const int max_points, + const int max_voxels, const int NDim); + +void dynamic_voxelize_forward_impl(const at::Tensor& points, at::Tensor& coors, + const std::vector voxel_size, + const std::vector coors_range, + const int NDim); + +REGISTER_DEVICE_IMPL(hard_voxelize_forward_impl, CUDA, + hard_voxelize_forward_cuda); +REGISTER_DEVICE_IMPL(nondeterministic_hard_voxelize_forward_impl, CUDA, + nondeterministic_hard_voxelize_forward_cuda); +REGISTER_DEVICE_IMPL(dynamic_voxelize_forward_impl, CUDA, + dynamic_voxelize_forward_cuda); + +void RotatedFeatureAlignForwardCUDAKernelLauncher(const Tensor features, + const Tensor best_bboxes, + const float spatial_scale, + const int points, + Tensor output); + +void RotatedFeatureAlignBackwardCUDAKernelLauncher(const Tensor top_grad, + const Tensor best_bboxes, + const float spatial_scale, + const int points, + Tensor bottom_grad); + +void rotated_feature_align_forward_cuda(const Tensor features, + const Tensor best_bboxes, + const float spatial_scale, + const int points, Tensor output) { + RotatedFeatureAlignForwardCUDAKernelLauncher(features, best_bboxes, + spatial_scale, points, output); +}; + +void rotated_feature_align_backward_cuda(const Tensor top_grad, + const Tensor best_bboxes, + const float spatial_scale, + const int points, Tensor bottom_grad) { + RotatedFeatureAlignBackwardCUDAKernelLauncher( + top_grad, best_bboxes, spatial_scale, points, bottom_grad); +}; + +void rotated_feature_align_forward_impl(const Tensor features, + const Tensor best_bboxes, + const float spatial_scale, + const int points, Tensor output); + +void rotated_feature_align_backward_impl(const Tensor top_grad, + const Tensor best_bboxes, + const float spatial_scale, + const int points, Tensor bottom_grad); + +REGISTER_DEVICE_IMPL(rotated_feature_align_forward_impl, CUDA, + rotated_feature_align_forward_cuda); +REGISTER_DEVICE_IMPL(rotated_feature_align_backward_impl, CUDA, + rotated_feature_align_backward_cuda); + +void PointsInPolygonsForwardCUDAKernelLauncher(const at::Tensor points, + const at::Tensor polygons, + const int rows, const int cols, + at::Tensor output); + +void points_in_polygons_forward_cuda(const Tensor points, const Tensor polygons, + Tensor output, const int rows, + const int cols) { + PointsInPolygonsForwardCUDAKernelLauncher(points, polygons, rows, cols, + output); +}; + +void points_in_polygons_forward_impl(const Tensor points, const Tensor polygons, + Tensor output, const int rows, + const int cols); + +REGISTER_DEVICE_IMPL(points_in_polygons_forward_impl, CUDA, + points_in_polygons_forward_cuda); + +void MinAreaPolygonsCUDAKernelLauncher(const Tensor pointsets, Tensor polygons); + +void min_area_polygons_cuda(const Tensor pointsets, Tensor polygons) { + MinAreaPolygonsCUDAKernelLauncher(pointsets, polygons); +} + +void min_area_polygons_impl(const Tensor pointsets, Tensor polygons); + +REGISTER_DEVICE_IMPL(min_area_polygons_impl, CUDA, min_area_polygons_cuda); + +void ActiveRotatedFilterForwardCUDAKernelLauncher(const Tensor input, + const Tensor indices, + Tensor output); + +void ActiveRotatedFilterBackwardCUDAKernelLauncher(const Tensor grad_out, + const Tensor indices, + Tensor grad_in); + +void active_rotated_filter_forward_cuda(const Tensor input, + const Tensor indices, Tensor output) { + ActiveRotatedFilterForwardCUDAKernelLauncher(input, indices, output); +}; + +void active_rotated_filter_backward_cuda(const Tensor grad_out, + const Tensor indices, Tensor grad_in) { + ActiveRotatedFilterBackwardCUDAKernelLauncher(grad_out, indices, grad_in); +}; + +void active_rotated_filter_forward_impl(const Tensor input, + const Tensor indices, Tensor output); + +void active_rotated_filter_backward_impl(const Tensor grad_out, + const Tensor indices, Tensor grad_in); + +REGISTER_DEVICE_IMPL(active_rotated_filter_forward_impl, CUDA, + active_rotated_filter_forward_cuda); +REGISTER_DEVICE_IMPL(active_rotated_filter_backward_impl, CUDA, + active_rotated_filter_backward_cuda); + +void ConvexIoUCUDAKernelLauncher(const Tensor pointsets, const Tensor polygons, + Tensor ious); + +void ConvexGIoUCUDAKernelLauncher(const Tensor pointsets, const Tensor polygons, + Tensor output); + +void convex_iou_cuda(const Tensor pointsets, const Tensor polygons, + Tensor ious) { + ConvexIoUCUDAKernelLauncher(pointsets, polygons, ious); +} + +void convex_giou_cuda(const Tensor pointsets, const Tensor polygons, + Tensor output) { + ConvexGIoUCUDAKernelLauncher(pointsets, polygons, output); +} + +void convex_iou_impl(const Tensor pointsets, const Tensor polygons, + Tensor ious); + +void convex_giou_impl(const Tensor pointsets, const Tensor polygons, + Tensor output); + +REGISTER_DEVICE_IMPL(convex_iou_impl, CUDA, convex_iou_cuda); +REGISTER_DEVICE_IMPL(convex_giou_impl, CUDA, convex_giou_cuda); + +Tensor DiffIoURotatedSortVerticesCUDAKernelLauncher(Tensor vertices, + Tensor mask, + Tensor num_valid); + +Tensor diff_iou_rotated_sort_vertices_forward_cuda(Tensor vertices, Tensor mask, + Tensor num_valid) { + return DiffIoURotatedSortVerticesCUDAKernelLauncher(vertices, mask, + num_valid); +} + +Tensor diff_iou_rotated_sort_vertices_forward_impl(Tensor vertices, Tensor mask, + Tensor num_valid); + +REGISTER_DEVICE_IMPL(diff_iou_rotated_sort_vertices_forward_impl, CUDA, + diff_iou_rotated_sort_vertices_forward_cuda); + +void ChamferDistanceForwardCUDAKernelLauncher( + const Tensor xyz1, const Tensor xyz2, const Tensor dist1, + const Tensor dist2, const Tensor idx1, const Tensor idx2); + +void ChamferDistanceBackwardCUDAKernelLauncher( + const Tensor xyz1, const Tensor xyz2, Tensor idx1, Tensor idx2, + Tensor grad_dist1, Tensor grad_dist2, Tensor grad_xyz1, Tensor grad_xyz2); + +void chamfer_distance_forward_cuda(const Tensor xyz1, const Tensor xyz2, + const Tensor dist1, const Tensor dist2, + const Tensor idx1, const Tensor idx2) { + ChamferDistanceForwardCUDAKernelLauncher(xyz1, xyz2, dist1, dist2, idx1, + idx2); +}; + +void chamfer_distance_backward_cuda(const Tensor xyz1, const Tensor xyz2, + Tensor idx1, Tensor idx2, Tensor graddist1, + Tensor graddist2, Tensor gradxyz1, + Tensor gradxyz2) { + ChamferDistanceBackwardCUDAKernelLauncher(xyz1, xyz2, idx1, idx2, graddist1, + graddist2, gradxyz1, gradxyz2); +}; + +void chamfer_distance_forward_impl(const Tensor xyz1, const Tensor xyz2, + const Tensor dist1, const Tensor dist2, + const Tensor idx1, const Tensor idx2); + +void chamfer_distance_backward_impl(const Tensor xyz1, const Tensor xyz2, + Tensor idx1, Tensor idx2, Tensor graddist1, + Tensor graddist2, Tensor gradxyz1, + Tensor gradxyz2); + +REGISTER_DEVICE_IMPL(chamfer_distance_forward_impl, CUDA, + chamfer_distance_forward_cuda); +REGISTER_DEVICE_IMPL(chamfer_distance_backward_impl, CUDA, + chamfer_distance_backward_cuda); + +void PrROIPoolForwardCUDAKernelLauncher(Tensor input, Tensor rois, + Tensor output, int pooled_height, + int pooled_width, float spatial_scale); + +void PrROIPoolBackwardCUDAKernelLauncher(Tensor grad_output, Tensor rois, + Tensor grad_input, int pooled_height, + int pooled_width, float spatial_scale); + +void PrROIPoolCoorBackwardCUDAKernelLauncher( + Tensor output, Tensor grad_output, Tensor input, Tensor rois, + Tensor grad_rois, int pooled_height, int pooled_width, float spatial_scale); + +void prroi_pool_forward_cuda(Tensor input, Tensor rois, Tensor output, + int pooled_height, int pooled_width, + float spatial_scale) { + PrROIPoolForwardCUDAKernelLauncher(input, rois, output, pooled_height, + pooled_width, spatial_scale); +} + +void prroi_pool_backward_cuda(Tensor grad_output, Tensor rois, + Tensor grad_input, int pooled_height, + int pooled_width, float spatial_scale) { + PrROIPoolBackwardCUDAKernelLauncher(grad_output, rois, grad_input, + pooled_height, pooled_width, + spatial_scale); +} + +void prroi_pool_coor_backward_cuda(Tensor output, Tensor grad_output, + Tensor input, Tensor rois, Tensor grad_rois, + int pooled_height, int pooled_width, + float spatial_scale) { + PrROIPoolCoorBackwardCUDAKernelLauncher(output, grad_output, input, rois, + grad_rois, pooled_height, + pooled_width, spatial_scale); +} + +void prroi_pool_forward_impl(Tensor input, Tensor rois, Tensor output, + int pooled_height, int pooled_width, + float spatial_scale); +void prroi_pool_backward_impl(Tensor grad_output, Tensor rois, + Tensor grad_input, int pooled_height, + int pooled_width, float spatial_scale); +void prroi_pool_coor_backward_impl(Tensor output, Tensor grad_output, + Tensor input, Tensor rois, Tensor grad_rois, + int pooled_height, int pooled_width, + float spatial_scale); +REGISTER_DEVICE_IMPL(prroi_pool_forward_impl, CUDA, prroi_pool_forward_cuda); +REGISTER_DEVICE_IMPL(prroi_pool_backward_impl, CUDA, prroi_pool_backward_cuda); +REGISTER_DEVICE_IMPL(prroi_pool_coor_backward_impl, CUDA, + prroi_pool_coor_backward_cuda); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv.cpp new file mode 100644 index 000000000..86690b939 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv.cpp @@ -0,0 +1,517 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void deformable_im2col_impl(Tensor data_im, Tensor data_offset, + const int channels, const int height, + const int width, const int ksize_h, + const int ksize_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, + const int parallel_imgs, const int deformable_group, + Tensor data_col) { + DISPATCH_DEVICE_IMPL(deformable_im2col_impl, data_im, data_offset, channels, + height, width, ksize_h, ksize_w, pad_h, pad_w, stride_h, + stride_w, dilation_h, dilation_w, parallel_imgs, + deformable_group, data_col); +} + +void deformable_col2im_impl(Tensor data_col, Tensor data_offset, + const int channels, const int height, + const int width, const int ksize_h, + const int ksize_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, + const int parallel_imgs, const int deformable_group, + Tensor grad_im) { + DISPATCH_DEVICE_IMPL(deformable_col2im_impl, data_col, data_offset, channels, + height, width, ksize_h, ksize_w, pad_h, pad_w, stride_h, + stride_w, dilation_h, dilation_w, parallel_imgs, + deformable_group, grad_im); +} + +void deformable_col2im_coord_impl( + Tensor data_col, Tensor data_im, Tensor data_offset, const int channels, + const int height, const int width, const int ksize_h, const int ksize_w, + const int pad_h, const int pad_w, const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, const int parallel_imgs, + const int deformable_group, Tensor grad_offset) { + DISPATCH_DEVICE_IMPL(deformable_col2im_coord_impl, data_col, data_im, + data_offset, channels, height, width, ksize_h, ksize_w, + pad_h, pad_w, stride_h, stride_w, dilation_h, dilation_w, + parallel_imgs, deformable_group, grad_offset); +} + +void deform_conv_shape_check(at::Tensor input, at::Tensor offset, + at::Tensor *gradOutput, at::Tensor weight, int kH, + int kW, int dH, int dW, int padH, int padW, + int dilationH, int dilationW, int group, + int deformable_group) { + TORCH_CHECK( + weight.ndimension() == 4, + "4D weight tensor (nOutputPlane,nInputPlane,kH,kW) expected, but got: %s", + weight.ndimension()); + + TORCH_CHECK(weight.is_contiguous(), "weight tensor has to be contiguous"); + + TORCH_CHECK(kW > 0 && kH > 0, + "kernel size should be greater than zero, but got kH: %d kW: %d", + kH, kW); + + TORCH_CHECK((weight.size(2) == kH && weight.size(3) == kW), + "kernel size should be consistent with weight, ", + "but got kH: %d kW: %d weight.size(2): %d, weight.size(3): %d", + kH, kW, weight.size(2), weight.size(3)); + + TORCH_CHECK(dW > 0 && dH > 0, + "stride should be greater than zero, but got dH: %d dW: %d", dH, + dW); + + TORCH_CHECK( + dilationW > 0 && dilationH > 0, + "dilation should be greater than 0, but got dilationH: %d dilationW: %d", + dilationH, dilationW); + + int ndim = input.ndimension(); + int dimf = 0; + int dimh = 1; + int dimw = 2; + + if (ndim == 4) { + dimf++; + dimh++; + dimw++; + } + + TORCH_CHECK(ndim == 3 || ndim == 4, + "3D or 4D input tensor expected but got: %s", ndim); + + long nInputPlane = weight.size(1) * group; + long inputHeight = input.size(dimh); + long inputWidth = input.size(dimw); + long nOutputPlane = weight.size(0); + long outputHeight = + (inputHeight + 2 * padH - (dilationH * (kH - 1) + 1)) / dH + 1; + long outputWidth = + (inputWidth + 2 * padW - (dilationW * (kW - 1) + 1)) / dW + 1; + + TORCH_CHECK(nInputPlane % deformable_group == 0, + "input channels must divide deformable group size"); + + if (outputWidth < 1 || outputHeight < 1) + AT_ERROR( + "Given input size: (%ld x %ld x %ld). " + "Calculated output size: (%ld x %ld x %ld). Output size is too small", + nInputPlane, inputHeight, inputWidth, nOutputPlane, outputHeight, + outputWidth); + + TORCH_CHECK(input.size(1) == nInputPlane, + "invalid number of input planes, expected: %d, but got: %d", + nInputPlane, input.size(1)); + + TORCH_CHECK((inputHeight >= kH && inputWidth >= kW), + "input image is smaller than kernel"); + + TORCH_CHECK( + (offset.size(2) == outputHeight && offset.size(3) == outputWidth), + "invalid spatial size of offset, expected height: %d width: %d, but " + "got height: %d width: %d", + outputHeight, outputWidth, offset.size(2), offset.size(3)); + + TORCH_CHECK((offset.size(1) == deformable_group * 2 * kH * kW), + "invalid number of channels of offset"); + + if (gradOutput != NULL) { + TORCH_CHECK( + gradOutput->size(dimf) == nOutputPlane, + "invalid number of gradOutput planes, expected: %d, but got: %d", + nOutputPlane, gradOutput->size(dimf)); + + TORCH_CHECK( + (gradOutput->size(dimh) == outputHeight && + gradOutput->size(dimw) == outputWidth), + "invalid size of gradOutput, expected height: %d width: %d , but " + "got height: %d width: %d", + outputHeight, outputWidth, gradOutput->size(dimh), + gradOutput->size(dimw)); + } +} + +void deform_conv_forward(Tensor input, Tensor weight, Tensor offset, + Tensor output, Tensor columns, Tensor ones, int kW, + int kH, int dW, int dH, int padW, int padH, + int dilationW, int dilationH, int group, + int deformable_group, int im2col_step) { + if (input.device().is_cuda()) { +#ifdef MMCV_WITH_CUDA + CHECK_CUDA_INPUT(input); + CHECK_CUDA_INPUT(offset); + CHECK_CUDA_INPUT(weight); + CHECK_CUDA_INPUT(output); + CHECK_CUDA_INPUT(columns); + CHECK_CUDA_INPUT(ones); +#else + AT_ERROR("DeformConv is not compiled with GPU support"); +#endif + } else { + CHECK_CPU_INPUT(input); + CHECK_CPU_INPUT(offset); + CHECK_CPU_INPUT(weight); + CHECK_CPU_INPUT(output); + CHECK_CPU_INPUT(columns); + CHECK_CPU_INPUT(ones); + } + + deform_conv_shape_check(input, offset, NULL, weight, kH, kW, dH, dW, padH, + padW, dilationH, dilationW, group, deformable_group); + at::DeviceGuard guard(input.device()); + + int batch = 1; + if (input.ndimension() == 3) { + // Force batch + batch = 0; + input.unsqueeze_(0); + offset.unsqueeze_(0); + } + + // todo: assert batchsize dividable by im2col_step + + long batchSize = input.size(0); + long nInputPlane = input.size(1); + long inputHeight = input.size(2); + long inputWidth = input.size(3); + + long nOutputPlane = weight.size(0); + + long outputWidth = + (inputWidth + 2 * padW - (dilationW * (kW - 1) + 1)) / dW + 1; + long outputHeight = + (inputHeight + 2 * padH - (dilationH * (kH - 1) + 1)) / dH + 1; + + TORCH_CHECK((offset.size(0) == batchSize), "invalid batch size of offset"); + + output = output.view({batchSize / im2col_step, im2col_step, nOutputPlane, + outputHeight, outputWidth}); + columns = at::zeros( + {nInputPlane * kW * kH, im2col_step * outputHeight * outputWidth}, + input.options()); + + if (ones.ndimension() != 2 || + ones.size(0) * ones.size(1) < outputHeight * outputWidth) { + ones = at::ones({outputHeight, outputWidth}, input.options()); + } + + input = input.view({batchSize / im2col_step, im2col_step, nInputPlane, + inputHeight, inputWidth}); + offset = + offset.view({batchSize / im2col_step, im2col_step, + deformable_group * 2 * kH * kW, outputHeight, outputWidth}); + + Tensor output_buffer = at::zeros({batchSize / im2col_step, nOutputPlane, + im2col_step * outputHeight, outputWidth}, + output.options()); + + output_buffer = output_buffer.view( + {output_buffer.size(0), group, output_buffer.size(1) / group, + output_buffer.size(2), output_buffer.size(3)}); + + for (int elt = 0; elt < batchSize / im2col_step; elt++) { + deformable_im2col_impl(input[elt], offset[elt], nInputPlane, inputHeight, + inputWidth, kH, kW, padH, padW, dH, dW, dilationH, + dilationW, im2col_step, deformable_group, columns); + + columns = columns.view({group, columns.size(0) / group, columns.size(1)}); + weight = weight.view({group, weight.size(0) / group, weight.size(1), + weight.size(2), weight.size(3)}); + + for (int g = 0; g < group; g++) { + output_buffer[elt][g] = output_buffer[elt][g] + .flatten(1) + .addmm_(weight[g].flatten(1), columns[g]) + .view_as(output_buffer[elt][g]); + } + columns = + columns.view({columns.size(0) * columns.size(1), columns.size(2)}); + weight = weight.view({weight.size(0) * weight.size(1), weight.size(2), + weight.size(3), weight.size(4)}); + } + + output_buffer = output_buffer.view( + {output_buffer.size(0), output_buffer.size(1) * output_buffer.size(2), + output_buffer.size(3), output_buffer.size(4)}); + + output_buffer = output_buffer.view({batchSize / im2col_step, nOutputPlane, + im2col_step, outputHeight, outputWidth}); + output_buffer.transpose_(1, 2); + output.copy_(output_buffer); + output = output.view({batchSize, nOutputPlane, outputHeight, outputWidth}); + + input = input.view({batchSize, nInputPlane, inputHeight, inputWidth}); + offset = offset.view( + {batchSize, deformable_group * 2 * kH * kW, outputHeight, outputWidth}); + + if (batch == 0) { + output = output.view({nOutputPlane, outputHeight, outputWidth}); + input = input.view({nInputPlane, inputHeight, inputWidth}); + offset = offset.view({offset.size(1), offset.size(2), offset.size(3)}); + } +} + +void deform_conv_backward_input(Tensor input, Tensor offset, Tensor gradOutput, + Tensor gradInput, Tensor gradOffset, + Tensor weight, Tensor columns, int kW, int kH, + int dW, int dH, int padW, int padH, + int dilationW, int dilationH, int group, + int deformable_group, int im2col_step) { + if (input.device().is_cuda()) { +#ifdef MMCV_WITH_CUDA + CHECK_CUDA_INPUT(input); + CHECK_CUDA_INPUT(offset); + CHECK_CUDA_INPUT(gradOutput); + CHECK_CUDA_INPUT(gradInput); + CHECK_CUDA_INPUT(gradOffset); + CHECK_CUDA_INPUT(weight); + CHECK_CUDA_INPUT(columns); +#else + AT_ERROR("DeformConv is not compiled with GPU support"); +#endif + } else { + CHECK_CPU_INPUT(input); + CHECK_CPU_INPUT(offset); + CHECK_CPU_INPUT(gradOutput); + CHECK_CPU_INPUT(gradInput); + CHECK_CPU_INPUT(gradOffset); + CHECK_CPU_INPUT(weight); + CHECK_CPU_INPUT(columns); + } + deform_conv_shape_check(input, offset, &gradOutput, weight, kH, kW, dH, dW, + padH, padW, dilationH, dilationW, group, + deformable_group); + + at::DeviceGuard guard(input.device()); + + int batch = 1; + if (input.ndimension() == 3) { + // Force batch + batch = 0; + input = input.view({1, input.size(0), input.size(1), input.size(2)}); + offset = offset.view({1, offset.size(0), offset.size(1), offset.size(2)}); + gradOutput = gradOutput.view( + {1, gradOutput.size(0), gradOutput.size(1), gradOutput.size(2)}); + } + + long batchSize = input.size(0); + long nInputPlane = input.size(1); + long inputHeight = input.size(2); + long inputWidth = input.size(3); + + long nOutputPlane = weight.size(0); + + long outputWidth = + (inputWidth + 2 * padW - (dilationW * (kW - 1) + 1)) / dW + 1; + long outputHeight = + (inputHeight + 2 * padH - (dilationH * (kH - 1) + 1)) / dH + 1; + + TORCH_CHECK((offset.size(0) == batchSize), 3, "invalid batch size of offset"); + gradInput = gradInput.view({batchSize, nInputPlane, inputHeight, inputWidth}); + columns = at::zeros( + {nInputPlane * kW * kH, im2col_step * outputHeight * outputWidth}, + input.options()); + + // change order of grad output + gradOutput = gradOutput.view({batchSize / im2col_step, im2col_step, + nOutputPlane, outputHeight, outputWidth}); + gradOutput.transpose_(1, 2); + + gradInput = gradInput.view({batchSize / im2col_step, im2col_step, nInputPlane, + inputHeight, inputWidth}); + input = input.view({batchSize / im2col_step, im2col_step, nInputPlane, + inputHeight, inputWidth}); + gradOffset = gradOffset.view({batchSize / im2col_step, im2col_step, + deformable_group * 2 * kH * kW, outputHeight, + outputWidth}); + offset = + offset.view({batchSize / im2col_step, im2col_step, + deformable_group * 2 * kH * kW, outputHeight, outputWidth}); + + for (int elt = 0; elt < batchSize / im2col_step; elt++) { + // divide into groups + columns = columns.view({group, columns.size(0) / group, columns.size(1)}); + weight = weight.view({group, weight.size(0) / group, weight.size(1), + weight.size(2), weight.size(3)}); + gradOutput = gradOutput.view( + {gradOutput.size(0), group, gradOutput.size(1) / group, + gradOutput.size(2), gradOutput.size(3), gradOutput.size(4)}); + + for (int g = 0; g < group; g++) { + columns[g] = columns[g].addmm_(weight[g].flatten(1).transpose(0, 1), + gradOutput[elt][g].flatten(1), 0.0f, 1.0f); + } + + columns = + columns.view({columns.size(0) * columns.size(1), columns.size(2)}); + gradOutput = gradOutput.view( + {gradOutput.size(0), gradOutput.size(1) * gradOutput.size(2), + gradOutput.size(3), gradOutput.size(4), gradOutput.size(5)}); + + deformable_col2im_coord_impl(columns, input[elt], offset[elt], nInputPlane, + inputHeight, inputWidth, kH, kW, padH, padW, + dH, dW, dilationH, dilationW, im2col_step, + deformable_group, gradOffset[elt]); + + deformable_col2im_impl(columns, offset[elt], nInputPlane, inputHeight, + inputWidth, kH, kW, padH, padW, dH, dW, dilationH, + dilationW, im2col_step, deformable_group, + gradInput[elt]); + + weight = weight.view({weight.size(0) * weight.size(1), weight.size(2), + weight.size(3), weight.size(4)}); + } + + gradOutput.transpose_(1, 2); + gradOutput = + gradOutput.view({batchSize, nOutputPlane, outputHeight, outputWidth}); + + gradInput = gradInput.view({batchSize, nInputPlane, inputHeight, inputWidth}); + input = input.view({batchSize, nInputPlane, inputHeight, inputWidth}); + gradOffset = gradOffset.view( + {batchSize, deformable_group * 2 * kH * kW, outputHeight, outputWidth}); + offset = offset.view( + {batchSize, deformable_group * 2 * kH * kW, outputHeight, outputWidth}); + + if (batch == 0) { + gradOutput = gradOutput.view({nOutputPlane, outputHeight, outputWidth}); + input = input.view({nInputPlane, inputHeight, inputWidth}); + gradInput = gradInput.view({nInputPlane, inputHeight, inputWidth}); + offset = offset.view({offset.size(1), offset.size(2), offset.size(3)}); + gradOffset = + gradOffset.view({offset.size(1), offset.size(2), offset.size(3)}); + } +} + +void deform_conv_backward_parameters(Tensor input, Tensor offset, + Tensor gradOutput, Tensor gradWeight, + Tensor columns, Tensor ones, int kW, + int kH, int dW, int dH, int padW, int padH, + int dilationW, int dilationH, int group, + int deformable_group, float scale, + int im2col_step) { + if (input.device().is_cuda()) { +#ifdef MMCV_WITH_CUDA + CHECK_CUDA_INPUT(input); + CHECK_CUDA_INPUT(offset); + CHECK_CUDA_INPUT(gradOutput); + CHECK_CUDA_INPUT(gradWeight); + CHECK_CUDA_INPUT(columns); + CHECK_CUDA_INPUT(ones); +#else + AT_ERROR("DeformConv is not compiled with GPU support"); +#endif + } else { + CHECK_CPU_INPUT(input); + CHECK_CPU_INPUT(offset); + CHECK_CPU_INPUT(gradOutput); + CHECK_CPU_INPUT(gradWeight); + CHECK_CPU_INPUT(columns); + CHECK_CPU_INPUT(ones); + } + + deform_conv_shape_check(input, offset, &gradOutput, gradWeight, kH, kW, dH, + dW, padH, padW, dilationH, dilationW, group, + deformable_group); + at::DeviceGuard guard(input.device()); + + int batch = 1; + + if (input.ndimension() == 3) { + // Force batch + batch = 0; + input = input.view( + at::IntList({1, input.size(0), input.size(1), input.size(2)})); + gradOutput = gradOutput.view( + {1, gradOutput.size(0), gradOutput.size(1), gradOutput.size(2)}); + } + + long batchSize = input.size(0); + long nInputPlane = input.size(1); + long inputHeight = input.size(2); + long inputWidth = input.size(3); + + long nOutputPlane = gradWeight.size(0); + + long outputWidth = + (inputWidth + 2 * padW - (dilationW * (kW - 1) + 1)) / dW + 1; + long outputHeight = + (inputHeight + 2 * padH - (dilationH * (kH - 1) + 1)) / dH + 1; + + TORCH_CHECK((offset.size(0) == batchSize), "invalid batch size of offset"); + + columns = at::zeros( + {nInputPlane * kW * kH, im2col_step * outputHeight * outputWidth}, + input.options()); + + gradOutput = gradOutput.view({batchSize / im2col_step, im2col_step, + nOutputPlane, outputHeight, outputWidth}); + gradOutput.transpose_(1, 2); + + Tensor gradOutputBuffer = at::zeros_like(gradOutput); + gradOutputBuffer = + gradOutputBuffer.view({batchSize / im2col_step, nOutputPlane, im2col_step, + outputHeight, outputWidth}); + gradOutputBuffer = gradOutputBuffer.contiguous(); + gradOutputBuffer.copy_(gradOutput); + gradOutputBuffer = + gradOutputBuffer.view({batchSize / im2col_step, nOutputPlane, + im2col_step * outputHeight, outputWidth}); + + gradOutput.transpose_(1, 2); + gradOutput = + gradOutput.view({batchSize, nOutputPlane, outputHeight, outputWidth}); + + input = input.view({batchSize / im2col_step, im2col_step, nInputPlane, + inputHeight, inputWidth}); + offset = + offset.view({batchSize / im2col_step, im2col_step, + deformable_group * 2 * kH * kW, outputHeight, outputWidth}); + + for (int elt = 0; elt < batchSize / im2col_step; elt++) { + deformable_im2col_impl(input[elt], offset[elt], nInputPlane, inputHeight, + inputWidth, kH, kW, padH, padW, dH, dW, dilationH, + dilationW, im2col_step, deformable_group, columns); + + // divide into group + gradOutputBuffer = gradOutputBuffer.view( + {gradOutputBuffer.size(0), group, gradOutputBuffer.size(1) / group, + gradOutputBuffer.size(2), gradOutputBuffer.size(3)}); + columns = columns.view({group, columns.size(0) / group, columns.size(1)}); + gradWeight = + gradWeight.view({group, gradWeight.size(0) / group, gradWeight.size(1), + gradWeight.size(2), gradWeight.size(3)}); + + for (int g = 0; g < group; g++) { + gradWeight[g] = gradWeight[g] + .flatten(1) + .addmm_(gradOutputBuffer[elt][g].flatten(1), + columns[g].transpose(1, 0), 1.0, scale) + .view_as(gradWeight[g]); + } + gradOutputBuffer = gradOutputBuffer.view( + {gradOutputBuffer.size(0), + gradOutputBuffer.size(1) * gradOutputBuffer.size(2), + gradOutputBuffer.size(3), gradOutputBuffer.size(4)}); + columns = + columns.view({columns.size(0) * columns.size(1), columns.size(2)}); + gradWeight = gradWeight.view({gradWeight.size(0) * gradWeight.size(1), + gradWeight.size(2), gradWeight.size(3), + gradWeight.size(4)}); + } + + input = input.view({batchSize, nInputPlane, inputHeight, inputWidth}); + offset = offset.view( + {batchSize, deformable_group * 2 * kH * kW, outputHeight, outputWidth}); + + if (batch == 0) { + gradOutput = gradOutput.view({nOutputPlane, outputHeight, outputWidth}); + input = input.view({nInputPlane, inputHeight, inputWidth}); + } +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_parrots.cpp new file mode 100644 index 000000000..c07a170df --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_parrots.cpp @@ -0,0 +1,273 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "deform_conv_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void deform_conv_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kW, kH, dW, dH, padW, padH, dilationW, dilationH, group, deformable_group, + im2col_step; + SSAttrs(attr) + .get("kW", kW) + .get("kH", kH) + .get("dW", dW) + .get("dH", dH) + .get("padW", padW) + .get("padH", padH) + .get("dilationW", dilationW) + .get("dilationH", dilationH) + .get("group", group) + .get("deformable_group", deformable_group) + .get("im2col_step", im2col_step) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& weight = buildATensor(ctx, ins[1]); + const auto& offset = buildATensor(ctx, ins[2]); + + auto output = buildATensor(ctx, outs[0]); + auto columns = buildATensor(ctx, outs[1]); + auto ones = buildATensor(ctx, outs[2]); + + deform_conv_forward(input, weight, offset, output, columns, ones, kW, kH, dW, + dH, padW, padH, dilationW, dilationH, group, + deformable_group, im2col_step); +} + +void deform_conv_backward_input_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kW, kH, dW, dH, padW, padH, dilationW, dilationH, group, deformable_group, + im2col_step; + SSAttrs(attr) + .get("kW", kW) + .get("kH", kH) + .get("dW", dW) + .get("dH", dH) + .get("padW", padW) + .get("padH", padH) + .get("dilationW", dilationW) + .get("dilationH", dilationH) + .get("group", group) + .get("deformable_group", deformable_group) + .get("im2col_step", im2col_step) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& offset = buildATensor(ctx, ins[1]); + const auto& gradOutput = buildATensor(ctx, ins[2]); + + auto gradInput = buildATensor(ctx, outs[0]); + auto gradOffset = buildATensor(ctx, outs[1]); + auto weight = buildATensor(ctx, outs[2]); + auto columns = buildATensor(ctx, outs[3]); + + deform_conv_backward_input(input, offset, gradOutput, gradInput, gradOffset, + weight, columns, kW, kH, dW, dH, padW, padH, + dilationW, dilationH, group, deformable_group, + im2col_step); +} + +void deform_conv_backward_parameters_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kW, kH, dW, dH, padW, padH, dilationW, dilationH, group, deformable_group, + im2col_step; + float scale; + SSAttrs(attr) + .get("kW", kW) + .get("kH", kH) + .get("dW", dW) + .get("dH", dH) + .get("padW", padW) + .get("padH", padH) + .get("dilationW", dilationW) + .get("dilationH", dilationH) + .get("group", group) + .get("deformable_group", deformable_group) + .get("scale", scale) + .get("im2col_step", im2col_step) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& offset = buildATensor(ctx, ins[1]); + const auto& gradOutput = buildATensor(ctx, ins[2]); + + auto gradWeight = buildATensor(ctx, outs[0]); + auto columns = buildATensor(ctx, outs[1]); + auto ones = buildATensor(ctx, outs[2]); + deform_conv_backward_parameters(input, offset, gradOutput, gradWeight, + columns, ones, kW, kH, dW, dH, padW, padH, + dilationW, dilationH, group, deformable_group, + scale, im2col_step); +} +#endif + +void deform_conv_forward_cpu_parrots(HostContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kW, kH, dW, dH, padW, padH, dilationW, dilationH, group, deformable_group, + im2col_step; + SSAttrs(attr) + .get("kW", kW) + .get("kH", kH) + .get("dW", dW) + .get("dH", dH) + .get("padW", padW) + .get("padH", padH) + .get("dilationW", dilationW) + .get("dilationH", dilationH) + .get("group", group) + .get("deformable_group", deformable_group) + .get("im2col_step", im2col_step) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& weight = buildATensor(ctx, ins[1]); + const auto& offset = buildATensor(ctx, ins[2]); + + auto output = buildATensor(ctx, outs[0]); + auto columns = buildATensor(ctx, outs[1]); + auto ones = buildATensor(ctx, outs[2]); + + deform_conv_forward(input, weight, offset, output, columns, ones, kW, kH, dW, + dH, padW, padH, dilationW, dilationH, group, + deformable_group, im2col_step); +} + +void deform_conv_backward_input_cpu_parrots(HostContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kW, kH, dW, dH, padW, padH, dilationW, dilationH, group, deformable_group, + im2col_step; + SSAttrs(attr) + .get("kW", kW) + .get("kH", kH) + .get("dW", dW) + .get("dH", dH) + .get("padW", padW) + .get("padH", padH) + .get("dilationW", dilationW) + .get("dilationH", dilationH) + .get("group", group) + .get("deformable_group", deformable_group) + .get("im2col_step", im2col_step) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& offset = buildATensor(ctx, ins[1]); + const auto& gradOutput = buildATensor(ctx, ins[2]); + + auto gradInput = buildATensor(ctx, outs[0]); + auto gradOffset = buildATensor(ctx, outs[1]); + auto weight = buildATensor(ctx, outs[2]); + auto columns = buildATensor(ctx, outs[3]); + + deform_conv_backward_input(input, offset, gradOutput, gradInput, gradOffset, + weight, columns, kW, kH, dW, dH, padW, padH, + dilationW, dilationH, group, deformable_group, + im2col_step); +} + +void deform_conv_backward_parameters_cpu_parrots( + HostContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kW, kH, dW, dH, padW, padH, dilationW, dilationH, group, deformable_group, + im2col_step; + float scale; + SSAttrs(attr) + .get("kW", kW) + .get("kH", kH) + .get("dW", dW) + .get("dH", dH) + .get("padW", padW) + .get("padH", padH) + .get("dilationW", dilationW) + .get("dilationH", dilationH) + .get("group", group) + .get("deformable_group", deformable_group) + .get("scale", scale) + .get("im2col_step", im2col_step) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& offset = buildATensor(ctx, ins[1]); + const auto& gradOutput = buildATensor(ctx, ins[2]); + + auto gradWeight = buildATensor(ctx, outs[0]); + auto columns = buildATensor(ctx, outs[1]); + auto ones = buildATensor(ctx, outs[2]); + deform_conv_backward_parameters(input, offset, gradOutput, gradWeight, + columns, ones, kW, kH, dW, dH, padW, padH, + dilationW, dilationH, group, deformable_group, + scale, im2col_step); +} + +PARROTS_EXTENSION_REGISTER(deform_conv_forward) + .attr("kW") + .attr("kH") + .attr("dW") + .attr("dH") + .attr("padW") + .attr("padH") + .attr("dilationW") + .attr("dilationH") + .attr("group") + .attr("deformable_group") + .attr("im2col_step") + .input(3) + .output(3) + .apply(deform_conv_forward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(deform_conv_forward_cuda_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(deform_conv_backward_input) + .attr("kW") + .attr("kH") + .attr("dW") + .attr("dH") + .attr("padW") + .attr("padH") + .attr("dilationW") + .attr("dilationH") + .attr("group") + .attr("deformable_group") + .attr("im2col_step") + .input(3) + .output(4) + .apply(deform_conv_backward_input_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(deform_conv_backward_input_cuda_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(deform_conv_backward_parameters) + .attr("kW") + .attr("kH") + .attr("dW") + .attr("dH") + .attr("padW") + .attr("padH") + .attr("dilationW") + .attr("dilationH") + .attr("group") + .attr("deformable_group") + .attr("scale") + .attr("im2col_step") + .input(3) + .output(3) + .apply(deform_conv_backward_parameters_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(deform_conv_backward_parameters_cuda_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_pytorch.h new file mode 100644 index 000000000..e0d3d40d1 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_pytorch.h @@ -0,0 +1,28 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef DEFORM_CONV_PYTORCH_H +#define DEFORM_CONV_PYTORCH_H +#include +using namespace at; + +void deform_conv_forward(Tensor input, Tensor weight, Tensor offset, + Tensor output, Tensor columns, Tensor ones, int kW, + int kH, int dW, int dH, int padW, int padH, + int dilationW, int dilationH, int group, + int deformable_group, int im2col_step); + +void deform_conv_backward_input(Tensor input, Tensor offset, Tensor gradOutput, + Tensor gradInput, Tensor gradOffset, + Tensor weight, Tensor columns, int kW, int kH, + int dW, int dH, int padW, int padH, + int dilationW, int dilationH, int group, + int deformable_group, int im2col_step); + +void deform_conv_backward_parameters(Tensor input, Tensor offset, + Tensor gradOutput, Tensor gradWeight, + Tensor columns, Tensor ones, int kW, + int kH, int dW, int dH, int padW, int padH, + int dilationW, int dilationH, int group, + int deformable_group, float scale, + int im2col_step); + +#endif // DEFORM_CONV_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool.cpp new file mode 100644 index 000000000..4fb78a96e --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool.cpp @@ -0,0 +1,42 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void deform_roi_pool_forward_impl(Tensor input, Tensor rois, Tensor offset, + Tensor output, int pooled_height, + int pooled_width, float spatial_scale, + int sampling_ratio, float gamma) { + DISPATCH_DEVICE_IMPL(deform_roi_pool_forward_impl, input, rois, offset, + output, pooled_height, pooled_width, spatial_scale, + sampling_ratio, gamma); +} + +void deform_roi_pool_backward_impl(Tensor grad_output, Tensor input, + Tensor rois, Tensor offset, + Tensor grad_input, Tensor grad_offset, + int pooled_height, int pooled_width, + float spatial_scale, int sampling_ratio, + float gamma) { + DISPATCH_DEVICE_IMPL(deform_roi_pool_backward_impl, grad_output, input, rois, + offset, grad_input, grad_offset, pooled_height, + pooled_width, spatial_scale, sampling_ratio, gamma); +} + +void deform_roi_pool_forward(Tensor input, Tensor rois, Tensor offset, + Tensor output, int pooled_height, int pooled_width, + float spatial_scale, int sampling_ratio, + float gamma) { + deform_roi_pool_forward_impl(input, rois, offset, output, pooled_height, + pooled_width, spatial_scale, sampling_ratio, + gamma); +} + +void deform_roi_pool_backward(Tensor grad_output, Tensor input, Tensor rois, + Tensor offset, Tensor grad_input, + Tensor grad_offset, int pooled_height, + int pooled_width, float spatial_scale, + int sampling_ratio, float gamma) { + deform_roi_pool_backward_impl(grad_output, input, rois, offset, grad_input, + grad_offset, pooled_height, pooled_width, + spatial_scale, sampling_ratio, gamma); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_parrots.cpp new file mode 100644 index 000000000..fc2701d52 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_parrots.cpp @@ -0,0 +1,102 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "deform_roi_pool_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +/*void deform_roi_pool_forward_cuda(Tensor input, Tensor rois, Tensor offset, + * Tensor output, int pooled_height, + * int pooled_width, float spatial_scale, + * int sampling_ratio, float gamma); + */ +void deform_roi_pool_forward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + int sampling_ratio; + float gamma; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .get("sampling_ratio", sampling_ratio) + .get("gamma", gamma) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + const auto& offset = buildATensor(ctx, ins[2]); + + auto output = buildATensor(ctx, outs[0]); + deform_roi_pool_forward_cuda(input, rois, offset, output, pooled_height, + pooled_width, spatial_scale, sampling_ratio, + gamma); +} + +/*void deform_roi_pool_backward_cuda(Tensor grad_output, Tensor input, + * Tensor rois, Tensor offset, + * Tensor grad_input, Tensor grad_offset, + * int pooled_height, int pooled_width, + * float spatial_scale, int sampling_ratio, + * float gamma); + */ +void deform_roi_pool_backward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + int sampling_ratio; + float gamma; + + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .get("sampling_ratio", sampling_ratio) + .get("gamma", gamma) + .done(); + + const auto& grad_output = buildATensor(ctx, ins[0]); + const auto& input = buildATensor(ctx, ins[1]); + const auto& rois = buildATensor(ctx, ins[2]); + const auto& offset = buildATensor(ctx, ins[3]); + + auto grad_input = buildATensor(ctx, outs[0]); + auto grad_offset = buildATensor(ctx, outs[1]); + + deform_roi_pool_backward_cuda(grad_output, input, rois, offset, grad_input, + grad_offset, pooled_height, pooled_width, + spatial_scale, sampling_ratio, gamma); +} + +PARROTS_EXTENSION_REGISTER(deform_roi_pool_forward) + .attr("pooled_height") + .attr("pooled_width") + .attr("spatial_scale") + .attr("sampling_ratio") + .attr("gamma") + .input(3) + .output(1) + .apply(deform_roi_pool_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(deform_roi_pool_backward) + .attr("pooled_height") + .attr("pooled_width") + .attr("spatial_scale") + .attr("sampling_ratio") + .attr("gamma") + .input(4) + .output(2) + .apply(deform_roi_pool_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_pytorch.h new file mode 100644 index 000000000..ac0f2c324 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_pytorch.h @@ -0,0 +1,18 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef DEFORM_ROI_POOL_PYTORCH_H +#define DEFORM_ROI_POOL_PYTORCH_H +#include +using namespace at; + +void deform_roi_pool_forward_cuda(Tensor input, Tensor rois, Tensor offset, + Tensor output, int pooled_height, + int pooled_width, float spatial_scale, + int sampling_ratio, float gamma); + +void deform_roi_pool_backward_cuda(Tensor grad_output, Tensor input, + Tensor rois, Tensor offset, + Tensor grad_input, Tensor grad_offset, + int pooled_height, int pooled_width, + float spatial_scale, int sampling_ratio, + float gamma); +#endif // DEFORM_ROI_POOL_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated.cpp new file mode 100644 index 000000000..2361b7fbe --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated.cpp @@ -0,0 +1,14 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +Tensor diff_iou_rotated_sort_vertices_forward_impl(Tensor vertices, Tensor mask, + Tensor num_valid) { + return DISPATCH_DEVICE_IMPL(diff_iou_rotated_sort_vertices_forward_impl, + vertices, mask, num_valid); +} + +Tensor diff_iou_rotated_sort_vertices_forward(Tensor vertices, Tensor mask, + Tensor num_valid) { + return diff_iou_rotated_sort_vertices_forward_impl(vertices, mask, num_valid); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_parrots.cpp new file mode 100644 index 000000000..b4d3e0e05 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_parrots.cpp @@ -0,0 +1,28 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "diff_iou_rotated_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void diff_iou_rotated_sort_vertices_forward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + at::Tensor boxes, scores, dets; + auto vertices = buildATensor(ctx, ins[0]); + auto mask = buildATensor(ctx, ins[1]); + auto num_valid = buildATensor(ctx, ins[2]); + auto out = + diff_iou_rotated_sort_vertices_forward_cuda(vertices, mask, num_valid); + updateDArray(ctx, out, outs[0]); +} + +PARROTS_EXTENSION_REGISTER(diff_iou_rotated_sort_vertices_forward) + .input(3) + .output(1) + .apply(diff_iou_rotated_sort_vertices_forward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_pytorch.h new file mode 100644 index 000000000..ef911ecc2 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_pytorch.h @@ -0,0 +1,10 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef DIFF_IOU_ROTATED_PYTORCH_H +#define DIFF_IOU_ROTATED_PYTORCH_H +#include +using namespace at; + +Tensor diff_iou_rotated_sort_vertices_forward_cuda(Tensor vertices, Tensor mask, + Tensor num_valid); + +#endif // DIFF_IOU_ROTATED_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss.cpp new file mode 100644 index 000000000..ed0e21865 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss.cpp @@ -0,0 +1,53 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void sigmoid_focal_loss_forward_impl(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha) { + DISPATCH_DEVICE_IMPL(sigmoid_focal_loss_forward_impl, input, target, weight, + output, gamma, alpha); +} + +void sigmoid_focal_loss_backward_impl(Tensor input, Tensor target, + Tensor weight, Tensor grad_input, + float gamma, float alpha) { + DISPATCH_DEVICE_IMPL(sigmoid_focal_loss_backward_impl, input, target, weight, + grad_input, gamma, alpha); +} + +void softmax_focal_loss_forward_impl(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha) { + DISPATCH_DEVICE_IMPL(softmax_focal_loss_forward_impl, input, target, weight, + output, gamma, alpha); +} + +void softmax_focal_loss_backward_impl(Tensor input, Tensor target, + Tensor weight, Tensor buff, + Tensor grad_input, float gamma, + float alpha) { + DISPATCH_DEVICE_IMPL(softmax_focal_loss_backward_impl, input, target, weight, + buff, grad_input, gamma, alpha); +} + +void sigmoid_focal_loss_forward(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha) { + sigmoid_focal_loss_forward_impl(input, target, weight, output, gamma, alpha); +} + +void sigmoid_focal_loss_backward(Tensor input, Tensor target, Tensor weight, + Tensor grad_input, float gamma, float alpha) { + sigmoid_focal_loss_backward_impl(input, target, weight, grad_input, gamma, + alpha); +} + +void softmax_focal_loss_forward(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha) { + softmax_focal_loss_forward_impl(input, target, weight, output, gamma, alpha); +} + +void softmax_focal_loss_backward(Tensor input, Tensor target, Tensor weight, + Tensor buff, Tensor grad_input, float gamma, + float alpha) { + softmax_focal_loss_backward_impl(input, target, weight, buff, grad_input, + gamma, alpha); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_parrots.cpp new file mode 100644 index 000000000..044e200c4 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_parrots.cpp @@ -0,0 +1,113 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "focal_loss_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void sigmoid_focal_loss_forward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float gamma; + float alpha; + SSAttrs(attr).get("gamma", gamma).get("alpha", alpha).done(); + + // get inputs and outputs + const auto& input = buildATensor(ctx, ins[0]); + const auto& target = buildATensor(ctx, ins[1]); + const auto& weight = buildATensor(ctx, ins[2]); + + auto output = buildATensor(ctx, outs[0]); + + sigmoid_focal_loss_forward_cuda(input, target, weight, output, gamma, alpha); +} + +void sigmoid_focal_loss_backward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float gamma; + float alpha; + SSAttrs(attr).get("gamma", gamma).get("alpha", alpha).done(); + + // get inputs and outputs + const auto& input = buildATensor(ctx, ins[0]); + const auto& target = buildATensor(ctx, ins[1]); + const auto& weight = buildATensor(ctx, ins[2]); + + auto grad_input = buildATensor(ctx, outs[0]); + + sigmoid_focal_loss_backward_cuda(input, target, weight, grad_input, gamma, + alpha); +} + +void softmax_focal_loss_forward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float gamma; + float alpha; + SSAttrs(attr).get("gamma", gamma).get("alpha", alpha).done(); + + // get inputs and outputs + const auto& input = buildATensor(ctx, ins[0]); + const auto& target = buildATensor(ctx, ins[1]); + const auto& weight = buildATensor(ctx, ins[2]); + + auto output = buildATensor(ctx, outs[0]); + softmax_focal_loss_forward_cuda(input, target, weight, output, gamma, alpha); +} + +void softmax_focal_loss_backward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float gamma; + float alpha; + SSAttrs(attr).get("gamma", gamma).get("alpha", alpha).done(); + + // get inputs and outputs + const auto& input = buildATensor(ctx, ins[0]); + const auto& target = buildATensor(ctx, ins[1]); + const auto& weight = buildATensor(ctx, ins[2]); + + auto buff = buildATensor(ctx, outs[0]); + auto grad_input = buildATensor(ctx, outs[1]); + softmax_focal_loss_backward_cuda(input, target, weight, buff, grad_input, + gamma, alpha); +} + +PARROTS_EXTENSION_REGISTER(sigmoid_focal_loss_forward) + .attr("gamma") + .attr("alpha") + .input(3) + .output(1) + .apply(sigmoid_focal_loss_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(sigmoid_focal_loss_backward) + .attr("gamma") + .attr("alpha") + .input(3) + .output(1) + .apply(sigmoid_focal_loss_backward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(softmax_focal_loss_forward) + .attr("gamma") + .attr("alpha") + .input(3) + .output(1) + .apply(softmax_focal_loss_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(softmax_focal_loss_backward) + .attr("gamma") + .attr("alpha") + .input(3) + .output(2) + .apply(softmax_focal_loss_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_pytorch.h new file mode 100644 index 000000000..b7a00c8ab --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_pytorch.h @@ -0,0 +1,21 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef FOCAL_LOSS_PYTORCH_H +#define FOCAL_LOSS_PYTORCH_H +#include +using namespace at; + +void sigmoid_focal_loss_forward_cuda(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha); + +void sigmoid_focal_loss_backward_cuda(Tensor input, Tensor target, + Tensor weight, Tensor grad_input, + float gamma, float alpha); + +void softmax_focal_loss_forward_cuda(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha); + +void softmax_focal_loss_backward_cuda(Tensor input, Tensor target, + Tensor weight, Tensor buff, + Tensor grad_input, float gamma, + float alpha); +#endif // FOCAL_LOSS_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample.cpp new file mode 100644 index 000000000..9c7098acd --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample.cpp @@ -0,0 +1,34 @@ +// Modified from +// https://github.com/sshaoshuai/Pointnet2.PyTorch/tree/master/pointnet2/src/sampling.cpp + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void furthest_point_sampling_forward_impl(Tensor points_tensor, + Tensor temp_tensor, Tensor idx_tensor, + int b, int n, int m) { + DISPATCH_DEVICE_IMPL(furthest_point_sampling_forward_impl, points_tensor, + temp_tensor, idx_tensor, b, n, m); +} + +void furthest_point_sampling_with_dist_forward_impl(Tensor points_tensor, + Tensor temp_tensor, + Tensor idx_tensor, int b, + int n, int m) { + DISPATCH_DEVICE_IMPL(furthest_point_sampling_with_dist_forward_impl, + points_tensor, temp_tensor, idx_tensor, b, n, m); +} + +void furthest_point_sampling_forward(Tensor points_tensor, Tensor temp_tensor, + Tensor idx_tensor, int b, int n, int m) { + furthest_point_sampling_forward_impl(points_tensor, temp_tensor, idx_tensor, + b, n, m); +} + +void furthest_point_sampling_with_dist_forward(Tensor points_tensor, + Tensor temp_tensor, + Tensor idx_tensor, int b, int n, + int m) { + furthest_point_sampling_with_dist_forward_impl(points_tensor, temp_tensor, + idx_tensor, b, n, m); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_parrots.cpp new file mode 100644 index 000000000..483bfb243 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_parrots.cpp @@ -0,0 +1,57 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "furthest_point_sample_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void furthest_point_sample_forward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int b, n, m; + SSAttrs(attr).get("b", b).get("n", n).get("m", m).done(); + + auto points_tensor = buildATensor(ctx, ins[0]); + auto temp_tensor = buildATensor(ctx, ins[1]); + + auto idx_tensor = buildATensor(ctx, outs[0]); + + furthest_point_sampling_forward(points_tensor, temp_tensor, idx_tensor, b, n, + m); +} + +void furthest_point_sampling_with_dist_forward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int b, n, m; + SSAttrs(attr).get("b", b).get("n", n).get("m", m).done(); + + auto points_tensor = buildATensor(ctx, ins[0]); + auto temp_tensor = buildATensor(ctx, ins[1]); + + auto idx_tensor = buildATensor(ctx, outs[0]); + + furthest_point_sampling_with_dist_forward(points_tensor, temp_tensor, + idx_tensor, b, n, m); +} +PARROTS_EXTENSION_REGISTER(furthest_point_sampling_forward) + .attr("b") + .attr("n") + .attr("m") + .input(2) + .output(1) + .apply(furthest_point_sample_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(furthest_point_sampling_with_dist_forward) + .attr("b") + .attr("n") + .attr("m") + .input(2) + .output(1) + .apply(furthest_point_sampling_with_dist_forward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_pytorch.h new file mode 100644 index 000000000..0325cd66e --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_pytorch.h @@ -0,0 +1,14 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef FURTHEST_POINT_SAMPLE_PYTORCH_H +#define FURTHEST_POINT_SAMPLE_PYTORCH_H +#include +using namespace at; + +void furthest_point_sampling_forward(Tensor points_tensor, Tensor temp_tensor, + Tensor idx_tensor, int b, int n, int m); + +void furthest_point_sampling_with_dist_forward(Tensor points_tensor, + Tensor temp_tensor, + Tensor idx_tensor, int b, int n, + int m); +#endif // FURTHEST_POINT_SAMPLE_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_leakyrelu.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_leakyrelu.cpp new file mode 100644 index 000000000..8d411c9d8 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_leakyrelu.cpp @@ -0,0 +1,119 @@ +// Modified from +// https://github.com/rosinality/stylegan2-pytorch/blob/master/op/fused_bias_act.cpp + +/* +Copyright (c) 2021, NVIDIA Corporation. All rights reserved. + +NVIDIA Source Code License for StyleGAN2 with Adaptive Discriminator +Augmentation (ADA) +======================================================================= + +1. Definitions + +"Licensor" means any person or entity that distributes its Work. + +"Software" means the original work of authorship made available under +this License. + +"Work" means the Software and any additions to or derivative works of +the Software that are made available under this License. + +The terms "reproduce," "reproduction," "derivative works," and +"distribution" have the meaning as provided under U.S. copyright law; +provided, however, that for the purposes of this License, derivative +works shall not include works that remain separable from, or merely +link (or bind by name) to the interfaces of, the Work. + +Works, including the Software, are "made available" under this License +by including in or with the Work either (a) a copyright notice +referencing the applicability of this License to the Work, or (b) a +copy of this License. + +2. License Grants + + 2.1 Copyright Grant. Subject to the terms and conditions of this + License, each Licensor grants to you a perpetual, worldwide, + non-exclusive, royalty-free, copyright license to reproduce, + prepare derivative works of, publicly display, publicly perform, + sublicense and distribute its Work and any resulting derivative + works in any form. + +3. Limitations + + 3.1 Redistribution. You may reproduce or distribute the Work only + if (a) you do so under this License, (b) you include a complete + copy of this License with your distribution, and (c) you retain + without modification any copyright, patent, trademark, or + attribution notices that are present in the Work. + + 3.2 Derivative Works. You may specify that additional or different + terms apply to the use, reproduction, and distribution of your + derivative works of the Work ("Your Terms") only if (a) Your Terms + provide that the use limitation in Section 3.3 applies to your + derivative works, and (b) you identify the specific derivative + works that are subject to Your Terms. Notwithstanding Your Terms, + this License (including the redistribution requirements in Section + 3.1) will continue to apply to the Work itself. + + 3.3 Use Limitation. The Work and any derivative works thereof only + may be used or intended for use non-commercially. Notwithstanding + the foregoing, NVIDIA and its affiliates may use the Work and any + derivative works commercially. As used herein, "non-commercially" + means for research or evaluation purposes only. + + 3.4 Patent Claims. If you bring or threaten to bring a patent claim + against any Licensor (including any claim, cross-claim or + counterclaim in a lawsuit) to enforce any patents that you allege + are infringed by any Work, then your rights under this License from + such Licensor (including the grant in Section 2.1) will terminate + immediately. + + 3.5 Trademarks. This License does not grant any rights to use any + Licensor’s or its affiliates’ names, logos, or trademarks, except + as necessary to reproduce the notices described in this License. + + 3.6 Termination. If you violate any term of this License, then your + rights under this License (including the grant in Section 2.1) will + terminate immediately. + +4. Disclaimer of Warranty. + +THE WORK IS PROVIDED "AS IS" WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WARRANTIES OR CONDITIONS OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR +NON-INFRINGEMENT. YOU BEAR THE RISK OF UNDERTAKING ANY ACTIVITIES UNDER +THIS LICENSE. + +5. Limitation of Liability. + +EXCEPT AS PROHIBITED BY APPLICABLE LAW, IN NO EVENT AND UNDER NO LEGAL +THEORY, WHETHER IN TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE +SHALL ANY LICENSOR BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY DIRECT, +INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF +OR RELATED TO THIS LICENSE, THE USE OR INABILITY TO USE THE WORK +(INCLUDING BUT NOT LIMITED TO LOSS OF GOODWILL, BUSINESS INTERRUPTION, +LOST PROFITS OR DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY OTHER +COMMERCIAL DAMAGES OR LOSSES), EVEN IF THE LICENSOR HAS BEEN ADVISED OF +THE POSSIBILITY OF SUCH DAMAGES. + +======================================================================= +*/ + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +torch::Tensor fused_bias_leakyrelu_op_impl(const torch::Tensor& input, + const torch::Tensor& bias, + const torch::Tensor& refer, int act, + int grad, float alpha, float scale) { + return DISPATCH_DEVICE_IMPL(fused_bias_leakyrelu_op_impl, input, bias, refer, + act, grad, alpha, scale); +} + +torch::Tensor fused_bias_leakyrelu(const torch::Tensor& input, + const torch::Tensor& bias, + const torch::Tensor& refer, int act, + int grad, float alpha, float scale) { + return fused_bias_leakyrelu_op_impl(input, bias, refer, act, grad, alpha, + scale); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_parrots.cpp new file mode 100644 index 000000000..47409ad20 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_parrots.cpp @@ -0,0 +1,41 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include + +#include +#include +#include +using namespace at; +using namespace parrots; + +torch::Tensor fused_bias_leakyrelu(const torch::Tensor &input, + const torch::Tensor &bias, + const torch::Tensor &refer, int act, + int grad, float alpha, float scale); + +void fused_bias_leakyrelu_parrots(CudaContext &ctx, const SSElement &attr, + const OperatorBase::in_list_t &ins, + OperatorBase::out_list_t &outs) { + int act, grad; + float alpha, scale; + SSAttrs(attr) + .get("act", act) + .get("grad", grad) + .get("alpha", alpha) + .get("scale", scale) + .done(); + const auto &input = buildATensor(ctx, ins[0]); + const auto &bias = buildATensor(ctx, ins[1]); + const auto &refer = buildATensor(ctx, ins[2]); + auto out = fused_bias_leakyrelu(input, bias, refer, act, grad, alpha, scale); + updateDArray(ctx, out, outs[0]); +} + +PARROTS_EXTENSION_REGISTER(fused_bias_leakyrelu) + .attr("act") + .attr("grad") + .attr("alpha") + .attr("scale") + .input(3) + .output(1) + .apply(fused_bias_leakyrelu_parrots) + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points.cpp new file mode 100644 index 000000000..b8fb02002 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points.cpp @@ -0,0 +1,30 @@ +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void gather_points_forward_impl(int b, int c, int n, int npoints, + const Tensor points, const Tensor idx, + Tensor out) { + DISPATCH_DEVICE_IMPL(gather_points_forward_impl, b, c, n, npoints, points, + idx, out); +} + +void gather_points_backward_impl(int b, int c, int n, int npoints, + const Tensor grad_out, const Tensor idx, + Tensor grad_points) { + DISPATCH_DEVICE_IMPL(gather_points_backward_impl, b, c, n, npoints, grad_out, + idx, grad_points); +} + +void gather_points_forward(Tensor points_tensor, Tensor idx_tensor, + Tensor out_tensor, int b, int c, int n, + int npoints) { + gather_points_forward_impl(b, c, n, npoints, points_tensor, idx_tensor, + out_tensor); +} + +void gather_points_backward(Tensor grad_out_tensor, Tensor idx_tensor, + Tensor grad_points_tensor, int b, int c, int n, + int npoints) { + gather_points_backward_impl(b, c, n, npoints, grad_out_tensor, idx_tensor, + grad_points_tensor); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_parrots.cpp new file mode 100644 index 000000000..1d2d9e129 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_parrots.cpp @@ -0,0 +1,71 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "gather_points_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void gather_points_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int b, c, n, npoints; + SSAttrs(attr) + .get("b", b) + .get("c", c) + .get("n", n) + .get("npoints", npoints) + .done(); + + auto points_tensor = buildATensor(ctx, ins[0]); + auto idx_tensor = buildATensor(ctx, ins[1]); + + auto out_tensor = buildATensor(ctx, outs[0]); + + gather_points_forward(points_tensor, idx_tensor, out_tensor, b, c, n, + npoints); +} + +void gather_points_backward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int b, c, n, npoints; + SSAttrs(attr) + .get("b", b) + .get("c", c) + .get("n", n) + .get("npoints", npoints) + .done(); + + auto grad_out_tensor = buildATensor(ctx, ins[0]); + auto idx_tensor = buildATensor(ctx, ins[1]); + + auto grad_points_tensor = buildATensor(ctx, outs[0]); + + gather_points_backward(grad_out_tensor, idx_tensor, grad_points_tensor, b, c, + n, npoints); +} + +PARROTS_EXTENSION_REGISTER(gather_points_forward) + .attr("b") + .attr("c") + .attr("n") + .attr("npoints") + .input(2) + .output(1) + .apply(gather_points_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(gather_points_backward) + .attr("b") + .attr("c") + .attr("n") + .attr("npoints") + .input(2) + .output(1) + .apply(gather_points_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_pytorch.h new file mode 100644 index 000000000..1689ae6ad --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_pytorch.h @@ -0,0 +1,13 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef GATHER_POINTS_PYTORCH_H +#define GATHER_POINTS_PYTORCH_H +#include +using namespace at; + +void gather_points_forward(Tensor points_tensor, Tensor idx_tensor, + Tensor out_tensor, int b, int c, int n, int npoints); + +void gather_points_backward(Tensor grad_out_tensor, Tensor idx_tensor, + Tensor grad_points_tensor, int b, int c, int n, + int npoints); +#endif // GATHER_POINTS_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points.cpp new file mode 100644 index 000000000..cdd190d40 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points.cpp @@ -0,0 +1,34 @@ +// Copyright (c) OpenMMLab. All rights reserved. +// Modified from +// https://github.com/sshaoshuai/Pointnet2.PyTorch/tree/master/pointnet2/src/group_points.cpp + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void group_points_forward_impl(int b, int c, int n, int npoints, int nsample, + const Tensor points, const Tensor idx, + Tensor out) { + DISPATCH_DEVICE_IMPL(group_points_forward_impl, b, c, n, npoints, nsample, + points, idx, out); +} + +void group_points_backward_impl(int b, int c, int n, int npoints, int nsample, + const Tensor grad_out, const Tensor idx, + Tensor grad_points) { + DISPATCH_DEVICE_IMPL(group_points_backward_impl, b, c, n, npoints, nsample, + grad_out, idx, grad_points); +} + +void group_points_forward(Tensor points_tensor, Tensor idx_tensor, + Tensor out_tensor, int b, int c, int n, int npoints, + int nsample) { + DISPATCH_DEVICE_IMPL(group_points_forward_impl, b, c, n, npoints, nsample, + points_tensor, idx_tensor, out_tensor); +} + +void group_points_backward(Tensor grad_out_tensor, Tensor idx_tensor, + Tensor grad_points_tensor, int b, int c, int n, + int npoints, int nsample) { + group_points_backward_impl(b, c, n, npoints, nsample, grad_out_tensor, + idx_tensor, grad_points_tensor); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_parrots.cpp new file mode 100644 index 000000000..282c01a8c --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_parrots.cpp @@ -0,0 +1,72 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "group_points_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void group_points_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int b, c, n, npoints, nsample; + SSAttrs(attr) + .get("b", b) + .get("c", c) + .get("n", n) + .get("npoints", npoints) + .get("nsample", nsample) + .done(); + auto points_tensor = buildATensor(ctx, ins[0]); + auto idx_tensor = buildATensor(ctx, ins[1]); + + auto out_tensor = buildATensor(ctx, outs[0]); + + group_points_forward(points_tensor, idx_tensor, out_tensor, b, c, n, npoints, + nsample); +} + +void group_points_backward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int b, c, n, npoints, nsample; + SSAttrs(attr) + .get("b", b) + .get("c", c) + .get("n", n) + .get("npoints", npoints) + .get("nsample", nsample) + .done(); + auto grad_out_tensor = buildATensor(ctx, ins[0]); + auto idx_tensor = buildATensor(ctx, ins[1]); + + auto grad_points_tensor = buildATensor(ctx, outs[0]); + + group_points_backward(grad_out_tensor, idx_tensor, grad_points_tensor, b, c, + n, npoints, nsample); +} + +PARROTS_EXTENSION_REGISTER(group_points_forward) + .attr("b") + .attr("c") + .attr("n") + .attr("npoints") + .attr("nsample") + .input(2) + .output(1) + .apply(group_points_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(group_points_backward) + .attr("b") + .attr("c") + .attr("n") + .attr("npoints") + .attr("nsample") + .input(2) + .output(1) + .apply(group_points_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_pytorch.h new file mode 100644 index 000000000..e704ab078 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_pytorch.h @@ -0,0 +1,15 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef GROUP_POINTS_PYTORCH_H +#define GROUP_POINTS_PYTORCH_H +#include +using namespace at; + +void group_points_forward(Tensor points_tensor, Tensor idx_tensor, + Tensor out_tensor, int b, int c, int n, int npoints, + int nsample); + +void group_points_backward(Tensor grad_out_tensor, Tensor idx_tensor, + Tensor grad_points_tensor, int b, int c, int n, + int npoints, int nsample); + +#endif // GROUP_POINTS_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/info.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/info.cpp new file mode 100644 index 000000000..a4cc41861 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/info.cpp @@ -0,0 +1,65 @@ +// Copyright (c) OpenMMLab. All rights reserved +// modified from +// https://github.com/facebookresearch/detectron2/blob/master/detectron2/layers/csrc/vision.cpp +#include "pytorch_cpp_helper.hpp" + +#ifdef MMCV_WITH_CUDA +#ifdef MMCV_WITH_HIP +#include +int get_hiprt_version() { + int runtimeVersion; + hipRuntimeGetVersion(&runtimeVersion); + return runtimeVersion; +} +#else +#include +int get_cudart_version() { return CUDART_VERSION; } +#endif +#endif + +std::string get_compiling_cuda_version() { +#ifdef MMCV_WITH_CUDA +#ifndef MMCV_WITH_HIP + std::ostringstream oss; + // copied from + // https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/cuda/detail/CUDAHooks.cpp#L231 + auto printCudaStyleVersion = [&](int v) { + oss << (v / 1000) << "." << (v / 10 % 100); + if (v % 10 != 0) { + oss << "." << (v % 10); + } + }; + printCudaStyleVersion(get_cudart_version()); + return oss.str(); +#else + std::ostringstream oss; + oss << get_hiprt_version(); + return oss.str(); +#endif +#else + return std::string("not available"); +#endif +} + +// similar to +// https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/Version.cpp +std::string get_compiler_version() { + std::ostringstream ss; +#if defined(__GNUC__) +#ifndef __clang__ + { ss << "GCC " << __GNUC__ << "." << __GNUC_MINOR__; } +#endif +#endif + +#if defined(__clang_major__) + { + ss << "clang " << __clang_major__ << "." << __clang_minor__ << "." + << __clang_patchlevel__; + } +#endif + +#if defined(_MSC_VER) + { ss << "MSVC " << _MSC_FULL_VER; } +#endif + return ss.str(); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d.cpp new file mode 100644 index 000000000..a347c0ee9 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d.cpp @@ -0,0 +1,66 @@ +// Modified from +// https://github.com/open-mmlab/OpenPCDet/blob/master/pcdet/ops/iou3d_nms/src/iou3d_nms.cpp + +/* +3D IoU Calculation and Rotated NMS(modified from 2D NMS written by others) +Written by Shaoshuai Shi +All Rights Reserved 2019-2020. +*/ + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +const int THREADS_PER_BLOCK_NMS = sizeof(unsigned long long) * 8; + +void iou3d_boxes_overlap_bev_forward_impl(const int num_a, const Tensor boxes_a, + const int num_b, const Tensor boxes_b, + Tensor ans_overlap) { + DISPATCH_DEVICE_IMPL(iou3d_boxes_overlap_bev_forward_impl, num_a, boxes_a, + num_b, boxes_b, ans_overlap); +} + +void iou3d_nms3d_forward_impl(const Tensor boxes, Tensor &keep, + Tensor &keep_num, float nms_overlap_thresh) { + DISPATCH_DEVICE_IMPL(iou3d_nms3d_forward_impl, boxes, keep, keep_num, + nms_overlap_thresh); +} + +void iou3d_nms3d_normal_forward_impl(const Tensor boxes, Tensor &keep, + Tensor &keep_num, + float nms_overlap_thresh) { + DISPATCH_DEVICE_IMPL(iou3d_nms3d_normal_forward_impl, boxes, keep, keep_num, + nms_overlap_thresh); +} + +void iou3d_boxes_overlap_bev_forward(Tensor boxes_a, Tensor boxes_b, + Tensor ans_overlap) { + // params boxes: (N, 7) [x, y, z, dx, dy, dz, heading] + // params boxes_b: (M, 5) + // params ans_overlap: (N, M) + int num_a = boxes_a.size(0); + int num_b = boxes_b.size(0); + + iou3d_boxes_overlap_bev_forward_impl(num_a, boxes_a, num_b, boxes_b, + ans_overlap); +} + +void iou3d_nms3d_forward(Tensor boxes, Tensor keep, Tensor keep_num, + float nms_overlap_thresh) { + // params boxes: (N, 7) [x, y, z, dx, dy, dz, heading] + // params keep: (N) + CHECK_CONTIGUOUS(boxes); + CHECK_CONTIGUOUS(keep); + + iou3d_nms3d_forward_impl(boxes, keep, keep_num, nms_overlap_thresh); +} + +void iou3d_nms3d_normal_forward(Tensor boxes, Tensor keep, Tensor keep_num, + float nms_overlap_thresh) { + // params boxes: (N, 7) [x, y, z, dx, dy, dz, heading] + // params keep: (N) + + CHECK_CONTIGUOUS(boxes); + CHECK_CONTIGUOUS(keep); + + iou3d_nms3d_normal_forward_impl(boxes, keep, keep_num, nms_overlap_thresh); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_parrots.cpp new file mode 100644 index 000000000..20e288aea --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_parrots.cpp @@ -0,0 +1,70 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "iou3d_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void iou3d_boxes_overlap_bev_forward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto boxes_a = buildATensor(ctx, ins[0]); + auto boxes_b = buildATensor(ctx, ins[1]); + + auto ans_iou = buildATensor(ctx, outs[0]); + + iou3d_boxes_overlap_bev_forward(boxes_a, boxes_b, ans_iou); +} + +void iou3d_nms3d_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float nms_overlap_thresh; + SSAttrs(attr).get("nms_overlap_thresh", nms_overlap_thresh).done(); + + auto boxes = buildATensor(ctx, ins[0]); + + auto keep = buildATensor(ctx, outs[0]); + auto keep_num = buildATensor(ctx, outs[1]); + + iou3d_nms3d_forward(boxes, keep, keep_num, nms_overlap_thresh); +} + +void iou3d_nms3d_normal_forward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float nms_overlap_thresh; + SSAttrs(attr).get("nms_overlap_thresh", nms_overlap_thresh).done(); + + auto boxes = buildATensor(ctx, ins[0]); + + auto keep = buildATensor(ctx, outs[0]); + auto keep_num = buildATensor(ctx, outs[1]); + + iou3d_nms3d_normal_forward(boxes, keep, keep_num, nms_overlap_thresh); +} + +PARROTS_EXTENSION_REGISTER(iou3d_boxes_overlap_bev_forward) + .input(2) + .output(1) + .apply(iou3d_boxes_overlap_bev_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(iou3d_nms3d_forward) + .attr("nms_overlap_thresh") + .input(1) + .output(2) + .apply(iou3d_nms3d_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(iou3d_nms3d_normal_forward) + .attr("nms_overlap_thresh") + .input(1) + .output(2) + .apply(iou3d_nms3d_normal_forward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_pytorch.h new file mode 100644 index 000000000..76170edc7 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_pytorch.h @@ -0,0 +1,16 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef IOU_3D_PYTORCH_H +#define IOU_3D_PYTORCH_H +#include +using namespace at; + +void iou3d_boxes_overlap_bev_forward(Tensor boxes_a, Tensor boxes_b, + Tensor ans_overlap); + +void iou3d_nms3d_forward(Tensor boxes, Tensor keep, Tensor keep_num, + float nms_overlap_thresh); + +void iou3d_nms3d_normal_forward(Tensor boxes, Tensor keep, Tensor keep_num, + float nms_overlap_thresh); + +#endif // IOU_3D_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn.cpp new file mode 100644 index 000000000..b4be9428c --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn.cpp @@ -0,0 +1,17 @@ +// Modified from +// https://github.com/CVMI-Lab/PAConv/tree/main/scene_seg/lib/pointops/src/knnquery_heap + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void knn_forward_impl(int b, int n, int m, int nsample, const Tensor xyz, + const Tensor new_xyz, Tensor idx, Tensor dist2) { + DISPATCH_DEVICE_IMPL(knn_forward_impl, b, n, m, nsample, xyz, new_xyz, idx, + dist2); +} + +void knn_forward(Tensor xyz_tensor, Tensor new_xyz_tensor, Tensor idx_tensor, + Tensor dist2_tensor, int b, int n, int m, int nsample) { + knn_forward_impl(b, n, m, nsample, xyz_tensor, new_xyz_tensor, idx_tensor, + dist2_tensor); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_parrots.cpp new file mode 100644 index 000000000..585b84644 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_parrots.cpp @@ -0,0 +1,41 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "knn_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void knn_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int b, n, m, nsample; + SSAttrs(attr) + .get("b", b) + .get("n", n) + .get("m", m) + .get("nsample", nsample) + .done(); + + auto xyz_tensor = buildATensor(ctx, ins[0]); + auto new_xyz_tensor = buildATensor(ctx, ins[1]); + + auto idx_tensor = buildATensor(ctx, outs[0]); + auto dist2_tensor = buildATensor(ctx, outs[1]); + + knn_forward(xyz_tensor, new_xyz_tensor, idx_tensor, dist2_tensor, b, n, m, + nsample); +} + +PARROTS_EXTENSION_REGISTER(knn_forward) + .attr("b") + .attr("n") + .attr("m") + .attr("nsample") + .input(2) + .output(2) + .apply(knn_forward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_pytorch.h new file mode 100644 index 000000000..b0875f838 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_pytorch.h @@ -0,0 +1,9 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef KNN_PYTORCH_H +#define KNN_PYTORCH_H +#include +using namespace at; + +void knn_forward(Tensor xyz_tensor, Tensor new_xyz_tensor, Tensor idx_tensor, + Tensor dist2_tensor, int b, int n, int m, int nsample); +#endif // KNN_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d.cpp new file mode 100644 index 000000000..590392535 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d.cpp @@ -0,0 +1,33 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void masked_im2col_forward_impl(const Tensor im, const Tensor mask_h_idx, + const Tensor mask_w_idx, Tensor col, + const int kernel_h, const int kernel_w, + const int pad_h, const int pad_w) { + DISPATCH_DEVICE_IMPL(masked_im2col_forward_impl, im, mask_h_idx, mask_w_idx, + col, kernel_h, kernel_w, pad_h, pad_w); +} + +void masked_col2im_forward_impl(const Tensor col, const Tensor mask_h_idx, + const Tensor mask_w_idx, Tensor im, int height, + int width, int channels) { + DISPATCH_DEVICE_IMPL(masked_col2im_forward_impl, col, mask_h_idx, mask_w_idx, + im, height, width, channels); +} + +void masked_im2col_forward(const Tensor im, const Tensor mask_h_idx, + const Tensor mask_w_idx, Tensor col, + const int kernel_h, const int kernel_w, + const int pad_h, const int pad_w) { + masked_im2col_forward_impl(im, mask_h_idx, mask_w_idx, col, kernel_h, + kernel_w, pad_h, pad_w); +} + +void masked_col2im_forward(const Tensor col, const Tensor mask_h_idx, + const Tensor mask_w_idx, Tensor im, int height, + int width, int channels) { + masked_col2im_forward_impl(col, mask_h_idx, mask_w_idx, im, height, width, + channels); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_parrots.cpp new file mode 100644 index 000000000..39f19740c --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_parrots.cpp @@ -0,0 +1,72 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "masked_conv2d_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void masked_im2col_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + // im: (n, ic, h, w), kernel size (kh, kw) + // kernel: (oc, ic * kh * kw), col: (kh * kw * ic, ow * oh) + int kernel_h, kernel_w, pad_h, pad_w; + SSAttrs(attr) + .get("kernel_h", kernel_h) + .get("kernel_w", kernel_w) + .get("pad_h", pad_h) + .get("pad_w", pad_w) + .done(); + + const auto& im = buildATensor(ctx, ins[0]); + const auto& mask_h_idx = buildATensor(ctx, ins[1]); + const auto& mask_w_idx = buildATensor(ctx, ins[2]); + + auto col = buildATensor(ctx, outs[0]); + masked_im2col_forward_cuda(im, mask_h_idx, mask_w_idx, col, kernel_h, + kernel_w, pad_h, pad_w); +} + +void masked_col2im_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + // im: (n, ic, h, w), kernel size (kh, kw) + // kernel: (oc, ic * kh * kh), col: (kh * kw * ic, ow * oh) + int height, width, channels; + SSAttrs(attr) + .get("height", height) + .get("width", width) + .get("channels", channels) + .done(); + + const auto& col = buildATensor(ctx, ins[0]); + const auto& mask_h_idx = buildATensor(ctx, ins[1]); + const auto& mask_w_idx = buildATensor(ctx, ins[2]); + + auto im = buildATensor(ctx, outs[0]); + masked_col2im_forward_cuda(col, mask_h_idx, mask_w_idx, im, height, width, + channels); +} + +PARROTS_EXTENSION_REGISTER(masked_im2col_forward) + .attr("kernel_h") + .attr("kernel_w") + .attr("pad_h") + .attr("pad_w") + .input(3) + .output(1) + .apply(masked_im2col_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(masked_col2im_forward) + .attr("height") + .attr("width") + .attr("channels") + .input(3) + .output(1) + .apply(masked_col2im_forward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_pytorch.h new file mode 100644 index 000000000..36d5643f6 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_pytorch.h @@ -0,0 +1,15 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef MASKED_CONV2D_PYTORCH_H +#define MASKED_CONV2D_PYTORCH_H +#include +using namespace at; + +void masked_im2col_forward_cuda(const Tensor im, const Tensor mask_h_idx, + const Tensor mask_w_idx, Tensor col, + const int kernel_h, const int kernel_w, + const int pad_h, const int pad_w); + +void masked_col2im_forward_cuda(const Tensor col, const Tensor mask_h_idx, + const Tensor mask_w_idx, Tensor im, int height, + int width, int channels); +#endif // MASKED_CONV2D_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons.cpp new file mode 100644 index 000000000..8ff996dc8 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons.cpp @@ -0,0 +1,11 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void min_area_polygons_impl(const Tensor pointsets, Tensor polygons) { + DISPATCH_DEVICE_IMPL(min_area_polygons_impl, pointsets, polygons); +} + +void min_area_polygons(const Tensor pointsets, Tensor polygons) { + min_area_polygons_impl(pointsets, polygons); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_parrots.cpp new file mode 100644 index 000000000..d9e4ff4b3 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_parrots.cpp @@ -0,0 +1,26 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "min_area_polygons_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void min_area_polygons_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto pointsets = buildATensor(ctx, ins[0]); + + auto polygons = buildATensor(ctx, outs[0]); + min_area_polygons(pointsets, polygons); +} + +PARROTS_EXTENSION_REGISTER(min_area_polygons) + .input(1) + .output(1) + .apply(min_area_polygons_cuda_parrots) + .done(); + +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_pytorch.h new file mode 100644 index 000000000..1df276418 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_pytorch.h @@ -0,0 +1,9 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef MIN_AREA_POLYGONS_PYTORCH_H +#define MIN_AREA_POLYGONS_PYTORCH_H +#include +using namespace at; + +void min_area_polygons(const Tensor pointsets, Tensor polygons); + +#endif // MIN_AREA_POLYGONS_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv.cpp new file mode 100644 index 000000000..12b538a05 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv.cpp @@ -0,0 +1,237 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void modulated_deformable_im2col_impl( + const Tensor data_im, const Tensor data_offset, const Tensor data_mask, + const int batch_size, const int channels, const int height_im, + const int width_im, const int height_col, const int width_col, + const int kernel_h, const int kernel_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, const int dilation_h, + const int dilation_w, const int deformable_group, Tensor data_col) { + DISPATCH_DEVICE_IMPL(modulated_deformable_im2col_impl, data_im, data_offset, + data_mask, batch_size, channels, height_im, width_im, + height_col, width_col, kernel_h, kernel_w, pad_h, pad_w, + stride_h, stride_w, dilation_h, dilation_w, + deformable_group, data_col); +} + +void modulated_deformable_col2im_impl( + const Tensor data_col, const Tensor data_offset, const Tensor data_mask, + const int batch_size, const int channels, const int height_im, + const int width_im, const int height_col, const int width_col, + const int kernel_h, const int kernel_w, const int pad_h, const int pad_w, + const int stride_h, const int stride_w, const int dilation_h, + const int dilation_w, const int deformable_group, Tensor grad_im) { + DISPATCH_DEVICE_IMPL(modulated_deformable_col2im_impl, data_col, data_offset, + data_mask, batch_size, channels, height_im, width_im, + height_col, width_col, kernel_h, kernel_w, pad_h, pad_w, + stride_h, stride_w, dilation_h, dilation_w, + deformable_group, grad_im); +} + +void modulated_deformable_col2im_coord_impl( + const Tensor data_col, const Tensor data_im, const Tensor data_offset, + const Tensor data_mask, const int batch_size, const int channels, + const int height_im, const int width_im, const int height_col, + const int width_col, const int kernel_h, const int kernel_w, + const int pad_h, const int pad_w, const int stride_h, const int stride_w, + const int dilation_h, const int dilation_w, const int deformable_group, + Tensor grad_offset, Tensor grad_mask) { + DISPATCH_DEVICE_IMPL(modulated_deformable_col2im_coord_impl, data_col, + data_im, data_offset, data_mask, batch_size, channels, + height_im, width_im, height_col, width_col, kernel_h, + kernel_w, pad_h, pad_w, stride_h, stride_w, dilation_h, + dilation_w, deformable_group, grad_offset, grad_mask); +} + +void modulated_deform_conv_forward( + Tensor input, Tensor weight, Tensor bias, Tensor ones, Tensor offset, + Tensor mask, Tensor output, Tensor columns, int kernel_h, int kernel_w, + const int stride_h, const int stride_w, const int pad_h, const int pad_w, + const int dilation_h, const int dilation_w, const int group, + const int deformable_group, const bool with_bias) { + at::DeviceGuard guard(input.device()); + + const int batch = input.size(0); + const int channels = input.size(1); + const int height = input.size(2); + const int width = input.size(3); + + const int channels_out = weight.size(0); + const int channels_kernel = weight.size(1); + const int kernel_h_ = weight.size(2); + const int kernel_w_ = weight.size(3); + + if (kernel_h_ != kernel_h || kernel_w_ != kernel_w) + AT_ERROR("Input shape and kernel shape won't match: (%d x %d vs %d x %d).", + kernel_h_, kernel_w, kernel_h_, kernel_w_); + if (channels != channels_kernel * group) + AT_ERROR("Input shape and kernel channels won't match: (%d vs %d).", + channels, channels_kernel * group); + + const int height_out = + (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1; + const int width_out = + (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1; + + if (ones.ndimension() != 2 || + ones.size(0) * ones.size(1) < height_out * width_out) { + // Resize plane and fill with ones... + ones = at::ones({height_out, width_out}, input.options()); + } + + // resize output + output = output.view({batch, channels_out, height_out, width_out}).zero_(); + // resize temporary columns + columns = + at::zeros({channels * kernel_h * kernel_w, 1 * height_out * width_out}, + input.options()); + + output = output.view({output.size(0), group, output.size(1) / group, + output.size(2), output.size(3)}); + + for (int b = 0; b < batch; b++) { + modulated_deformable_im2col_impl( + input[b], offset[b], mask[b], 1, channels, height, width, height_out, + width_out, kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w, + dilation_h, dilation_w, deformable_group, columns); + + // divide into group + weight = weight.view({group, weight.size(0) / group, weight.size(1), + weight.size(2), weight.size(3)}); + columns = columns.view({group, columns.size(0) / group, columns.size(1)}); + + for (int g = 0; g < group; g++) { + output[b][g] = output[b][g] + .flatten(1) + .addmm_(weight[g].flatten(1), columns[g]) + .view_as(output[b][g]); + } + + weight = weight.view({weight.size(0) * weight.size(1), weight.size(2), + weight.size(3), weight.size(4)}); + columns = + columns.view({columns.size(0) * columns.size(1), columns.size(2)}); + } + + output = output.view({output.size(0), output.size(1) * output.size(2), + output.size(3), output.size(4)}); + + if (with_bias) { + output += bias.view({1, bias.size(0), 1, 1}); + } +} + +void modulated_deform_conv_backward( + Tensor input, Tensor weight, Tensor bias, Tensor ones, Tensor offset, + Tensor mask, Tensor columns, Tensor grad_input, Tensor grad_weight, + Tensor grad_bias, Tensor grad_offset, Tensor grad_mask, Tensor grad_output, + int kernel_h, int kernel_w, int stride_h, int stride_w, int pad_h, + int pad_w, int dilation_h, int dilation_w, int group, int deformable_group, + const bool with_bias) { + at::DeviceGuard guard(input.device()); + + const int batch = input.size(0); + const int channels = input.size(1); + const int height = input.size(2); + const int width = input.size(3); + + const int channels_kernel = weight.size(1); + const int kernel_h_ = weight.size(2); + const int kernel_w_ = weight.size(3); + if (kernel_h_ != kernel_h || kernel_w_ != kernel_w) + AT_ERROR("Input shape and kernel shape won't match: (%d x %d vs %d x %d).", + kernel_h_, kernel_w, kernel_h_, kernel_w_); + if (channels != channels_kernel * group) + AT_ERROR("Input shape and kernel channels won't match: (%d vs %d).", + channels, channels_kernel * group); + + const int height_out = + (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1; + const int width_out = + (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1; + + if (ones.ndimension() != 2 || + ones.size(0) * ones.size(1) < height_out * width_out) { + // Resize plane and fill with ones... + ones = at::ones({height_out, width_out}, input.options()); + } + + grad_input = grad_input.view({batch, channels, height, width}); + columns = at::zeros({channels * kernel_h * kernel_w, height_out * width_out}, + input.options()); + + grad_output = + grad_output.view({grad_output.size(0), group, grad_output.size(1) / group, + grad_output.size(2), grad_output.size(3)}); + + for (int b = 0; b < batch; b++) { + // divide int group + columns = columns.view({group, columns.size(0) / group, columns.size(1)}); + weight = weight.view({group, weight.size(0) / group, weight.size(1), + weight.size(2), weight.size(3)}); + + for (int g = 0; g < group; g++) { + columns[g].addmm_(weight[g].flatten(1).transpose(0, 1), + grad_output[b][g].flatten(1), 0.0f, 1.0f); + } + + columns = + columns.view({columns.size(0) * columns.size(1), columns.size(2)}); + weight = weight.view({weight.size(0) * weight.size(1), weight.size(2), + weight.size(3), weight.size(4)}); + + // gradient w.r.t. input coordinate data + modulated_deformable_col2im_coord_impl( + columns, input[b], offset[b], mask[b], 1, channels, height, width, + height_out, width_out, kernel_h, kernel_w, pad_h, pad_w, stride_h, + stride_w, dilation_h, dilation_w, deformable_group, grad_offset[b], + grad_mask[b]); + // gradient w.r.t. input data + modulated_deformable_col2im_impl( + columns, offset[b], mask[b], 1, channels, height, width, height_out, + width_out, kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w, + dilation_h, dilation_w, deformable_group, grad_input[b]); + + // gradient w.r.t. weight, dWeight should accumulate across the batch and + // group + modulated_deformable_im2col_impl( + input[b], offset[b], mask[b], 1, channels, height, width, height_out, + width_out, kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w, + dilation_h, dilation_w, deformable_group, columns); + + columns = columns.view({group, columns.size(0) / group, columns.size(1)}); + grad_weight = grad_weight.view({group, grad_weight.size(0) / group, + grad_weight.size(1), grad_weight.size(2), + grad_weight.size(3)}); + if (with_bias) + grad_bias = grad_bias.view({group, grad_bias.size(0) / group}); + + for (int g = 0; g < group; g++) { + grad_weight[g] = + grad_weight[g] + .flatten(1) + .addmm_(grad_output[b][g].flatten(1), columns[g].transpose(0, 1)) + .view_as(grad_weight[g]); + if (with_bias) { + grad_bias[g] = + grad_bias[g] + .view({-1, 1}) + .addmm_(grad_output[b][g].flatten(1), ones.view({-1, 1})) + .view(-1); + } + } + + columns = + columns.view({columns.size(0) * columns.size(1), columns.size(2)}); + grad_weight = grad_weight.view({grad_weight.size(0) * grad_weight.size(1), + grad_weight.size(2), grad_weight.size(3), + grad_weight.size(4)}); + if (with_bias) + grad_bias = grad_bias.view({grad_bias.size(0) * grad_bias.size(1)}); + } + grad_output = grad_output.view({grad_output.size(0) * grad_output.size(1), + grad_output.size(2), grad_output.size(3), + grad_output.size(4)}); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_parrots.cpp new file mode 100644 index 000000000..2ef7efff6 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_parrots.cpp @@ -0,0 +1,199 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "modulated_deform_conv_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void modulated_deform_conv_forward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kernel_h, kernel_w, stride_h, stride_w, pad_h, pad_w, dilation_h, + dilation_w, group, deformable_group, with_bias; + SSAttrs(attr) + .get("kernel_h", kernel_h) + .get("kernel_w", kernel_w) + .get("stride_h", stride_h) + .get("stride_w", stride_w) + .get("pad_h", pad_h) + .get("pad_w", pad_w) + .get("dilation_h", dilation_h) + .get("dilation_w", dilation_w) + .get("group", group) + .get("deformable_group", deformable_group) + .get("with_bias", with_bias) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& weight = buildATensor(ctx, ins[1]); + const auto& bias = buildATensor(ctx, ins[2]); + const auto& ones = buildATensor(ctx, ins[3]); + const auto& offset = buildATensor(ctx, ins[4]); + const auto& mask = buildATensor(ctx, ins[5]); + + auto output = buildATensor(ctx, outs[0]); + auto columns = buildATensor(ctx, outs[1]); + + modulated_deform_conv_forward(input, weight, bias, ones, offset, mask, output, + columns, kernel_h, kernel_w, stride_h, stride_w, + pad_h, pad_w, dilation_h, dilation_w, group, + deformable_group, with_bias); +} + +void modulated_deform_conv_backward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kernel_h, kernel_w, stride_h, stride_w, pad_h, pad_w, dilation_h, + dilation_w, group, deformable_group, with_bias; + SSAttrs(attr) + .get("kernel_h", kernel_h) + .get("kernel_w", kernel_w) + .get("stride_h", stride_h) + .get("stride_w", stride_w) + .get("pad_h", pad_h) + .get("pad_w", pad_w) + .get("dilation_h", dilation_h) + .get("dilation_w", dilation_w) + .get("group", group) + .get("deformable_group", deformable_group) + .get("with_bias", with_bias) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& weight = buildATensor(ctx, ins[1]); + const auto& bias = buildATensor(ctx, ins[2]); + const auto& ones = buildATensor(ctx, ins[3]); + const auto& offset = buildATensor(ctx, ins[4]); + const auto& mask = buildATensor(ctx, ins[5]); + + auto columns = buildATensor(ctx, outs[0]); + auto grad_input = buildATensor(ctx, outs[1]); + auto grad_weight = buildATensor(ctx, outs[2]); + auto grad_bias = buildATensor(ctx, outs[3]); + auto grad_offset = buildATensor(ctx, outs[4]); + auto grad_mask = buildATensor(ctx, outs[5]); + auto grad_output = buildATensor(ctx, outs[6]); + modulated_deform_conv_backward( + input, weight, bias, ones, offset, mask, columns, grad_input, grad_weight, + grad_bias, grad_offset, grad_mask, grad_output, kernel_h, kernel_w, + stride_h, stride_w, pad_h, pad_w, dilation_h, dilation_w, group, + deformable_group, with_bias); +} +#endif + +void modulated_deform_conv_forward_cpu_parrots( + HostContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kernel_h, kernel_w, stride_h, stride_w, pad_h, pad_w, dilation_h, + dilation_w, group, deformable_group, with_bias; + SSAttrs(attr) + .get("kernel_h", kernel_h) + .get("kernel_w", kernel_w) + .get("stride_h", stride_h) + .get("stride_w", stride_w) + .get("pad_h", pad_h) + .get("pad_w", pad_w) + .get("dilation_h", dilation_h) + .get("dilation_w", dilation_w) + .get("group", group) + .get("deformable_group", deformable_group) + .get("with_bias", with_bias) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& weight = buildATensor(ctx, ins[1]); + const auto& bias = buildATensor(ctx, ins[2]); + const auto& ones = buildATensor(ctx, ins[3]); + const auto& offset = buildATensor(ctx, ins[4]); + const auto& mask = buildATensor(ctx, ins[5]); + + auto output = buildATensor(ctx, outs[0]); + auto columns = buildATensor(ctx, outs[1]); + + modulated_deform_conv_forward(input, weight, bias, ones, offset, mask, output, + columns, kernel_h, kernel_w, stride_h, stride_w, + pad_h, pad_w, dilation_h, dilation_w, group, + deformable_group, with_bias); +} + +void modulated_deform_conv_backward_cpu_parrots( + HostContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kernel_h, kernel_w, stride_h, stride_w, pad_h, pad_w, dilation_h, + dilation_w, group, deformable_group, with_bias; + SSAttrs(attr) + .get("kernel_h", kernel_h) + .get("kernel_w", kernel_w) + .get("stride_h", stride_h) + .get("stride_w", stride_w) + .get("pad_h", pad_h) + .get("pad_w", pad_w) + .get("dilation_h", dilation_h) + .get("dilation_w", dilation_w) + .get("group", group) + .get("deformable_group", deformable_group) + .get("with_bias", with_bias) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& weight = buildATensor(ctx, ins[1]); + const auto& bias = buildATensor(ctx, ins[2]); + const auto& ones = buildATensor(ctx, ins[3]); + const auto& offset = buildATensor(ctx, ins[4]); + const auto& mask = buildATensor(ctx, ins[5]); + + auto columns = buildATensor(ctx, outs[0]); + auto grad_input = buildATensor(ctx, outs[1]); + auto grad_weight = buildATensor(ctx, outs[2]); + auto grad_bias = buildATensor(ctx, outs[3]); + auto grad_offset = buildATensor(ctx, outs[4]); + auto grad_mask = buildATensor(ctx, outs[5]); + auto grad_output = buildATensor(ctx, outs[6]); + modulated_deform_conv_backward( + input, weight, bias, ones, offset, mask, columns, grad_input, grad_weight, + grad_bias, grad_offset, grad_mask, grad_output, kernel_h, kernel_w, + stride_h, stride_w, pad_h, pad_w, dilation_h, dilation_w, group, + deformable_group, with_bias); +} +PARROTS_EXTENSION_REGISTER(modulated_deform_conv_forward) + .attr("kernel_h") + .attr("kernel_w") + .attr("stride_h") + .attr("stride_w") + .attr("pad_h") + .attr("pad_w") + .attr("dilation_h") + .attr("dilation_w") + .attr("group") + .attr("deformable_group") + .attr("with_bias") + .input(6) + .output(2) + .apply(modulated_deform_conv_forward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(modulated_deform_conv_forward_cuda_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(modulated_deform_conv_backward) + .attr("kernel_h") + .attr("kernel_w") + .attr("stride_h") + .attr("stride_w") + .attr("pad_h") + .attr("pad_w") + .attr("dilation_h") + .attr("dilation_w") + .attr("group") + .attr("deformable_group") + .attr("with_bias") + .input(6) + .output(7) + .apply(modulated_deform_conv_backward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(modulated_deform_conv_backward_cuda_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_pytorch.h new file mode 100644 index 000000000..12f686861 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_pytorch.h @@ -0,0 +1,21 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef MODULATED_DEFORM_CONV_PYTORCH_H +#define MODULATED_DEFORM_CONV_PYTORCH_H +#include +using namespace at; + +void modulated_deform_conv_forward( + Tensor input, Tensor weight, Tensor bias, Tensor ones, Tensor offset, + Tensor mask, Tensor output, Tensor columns, int kernel_h, int kernel_w, + const int stride_h, const int stride_w, const int pad_h, const int pad_w, + const int dilation_h, const int dilation_w, const int group, + const int deformable_group, const bool with_bias); + +void modulated_deform_conv_backward( + Tensor input, Tensor weight, Tensor bias, Tensor ones, Tensor offset, + Tensor mask, Tensor columns, Tensor grad_input, Tensor grad_weight, + Tensor grad_bias, Tensor grad_offset, Tensor grad_mask, Tensor grad_output, + int kernel_h, int kernel_w, int stride_h, int stride_w, int pad_h, + int pad_w, int dilation_h, int dilation_w, int group, int deformable_group, + const bool with_bias); +#endif // MODULATED_DEFORM_CONV_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn.cpp new file mode 100644 index 000000000..25c8f6209 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn.cpp @@ -0,0 +1,60 @@ +/*! +************************************************************************************************** +* Deformable DETR +* Copyright (c) 2020 SenseTime. All Rights Reserved. +* Licensed under the Apache License, Version 2.0 [see LICENSE for details] +************************************************************************************************** +* Modified from +*https://github.com/chengdazhi/Deformable-Convolution-V2-PyTorch/tree/pytorch_1.0.0 +************************************************************************************************** +*/ + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +Tensor ms_deform_attn_impl_forward(const Tensor &value, + const Tensor &spatial_shapes, + const Tensor &level_start_index, + const Tensor &sampling_loc, + const Tensor &attn_weight, + const int im2col_step) { + return DISPATCH_DEVICE_IMPL(ms_deform_attn_impl_forward, value, + spatial_shapes, level_start_index, sampling_loc, + attn_weight, im2col_step); +} + +void ms_deform_attn_impl_backward( + const Tensor &value, const Tensor &spatial_shapes, + const Tensor &level_start_index, const Tensor &sampling_loc, + const Tensor &attn_weight, const Tensor &grad_output, Tensor &grad_value, + Tensor &grad_sampling_loc, Tensor &grad_attn_weight, + const int im2col_step) { + DISPATCH_DEVICE_IMPL(ms_deform_attn_impl_backward, value, spatial_shapes, + level_start_index, sampling_loc, attn_weight, + grad_output, grad_value, grad_sampling_loc, + grad_attn_weight, im2col_step); +} + +Tensor ms_deform_attn_forward(const Tensor &value, const Tensor &spatial_shapes, + const Tensor &level_start_index, + const Tensor &sampling_loc, + const Tensor &attn_weight, + const int im2col_step) { + at::DeviceGuard guard(value.device()); + return ms_deform_attn_impl_forward(value, spatial_shapes, level_start_index, + sampling_loc, attn_weight, im2col_step); +} + +void ms_deform_attn_backward(const Tensor &value, const Tensor &spatial_shapes, + const Tensor &level_start_index, + const Tensor &sampling_loc, + const Tensor &attn_weight, + const Tensor &grad_output, Tensor &grad_value, + Tensor &grad_sampling_loc, + Tensor &grad_attn_weight, const int im2col_step) { + at::DeviceGuard guard(value.device()); + ms_deform_attn_impl_backward(value, spatial_shapes, level_start_index, + sampling_loc, attn_weight, grad_output, + grad_value, grad_sampling_loc, grad_attn_weight, + im2col_step); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn_parrots.cpp new file mode 100644 index 000000000..a3ad786a8 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn_parrots.cpp @@ -0,0 +1,69 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include + +#include +#include +#include +using namespace at; +using namespace parrots; + +Tensor ms_deform_attn_forward(const Tensor &value, const Tensor &spatial_shapes, + const Tensor &level_start_index, + const Tensor &sampling_loc, + const Tensor &attn_weight, const int im2col_step); + +void ms_deform_attn_backward(const Tensor &value, const Tensor &spatial_shapes, + const Tensor &level_start_index, + const Tensor &sampling_loc, + const Tensor &attn_weight, + const Tensor &grad_output, Tensor &grad_value, + Tensor &grad_sampling_loc, + Tensor &grad_attn_weight, const int im2col_step); + +void ms_deform_attn_forward_parrots(CudaContext &ctx, const SSElement &attr, + const OperatorBase::in_list_t &ins, + OperatorBase::out_list_t &outs) { + int im2col_step; + SSAttrs(attr).get("im2col_step", im2col_step).done(); + const auto &value = buildATensor(ctx, ins[0]); + const auto &spatial_shapes = buildATensor(ctx, ins[1]); + const auto &level_start_index = buildATensor(ctx, ins[2]); + const auto &sampling_loc = buildATensor(ctx, ins[3]); + const auto &attn_weight = buildATensor(ctx, ins[4]); + auto out = ms_deform_attn_forward(value, spatial_shapes, level_start_index, + sampling_loc, attn_weight, im2col_step); + updateDArray(ctx, out, outs[0]); +} + +void ms_deform_attn_backward_parrots(CudaContext &ctx, const SSElement &attr, + const OperatorBase::in_list_t &ins, + OperatorBase::out_list_t &outs) { + int im2col_step; + SSAttrs(attr).get("im2col_step", im2col_step).done(); + const auto &value = buildATensor(ctx, ins[0]); + const auto &spatial_shapes = buildATensor(ctx, ins[1]); + const auto &level_start_index = buildATensor(ctx, ins[2]); + const auto &sampling_loc = buildATensor(ctx, ins[3]); + const auto &attn_weight = buildATensor(ctx, ins[4]); + const auto &grad_output = buildATensor(ctx, ins[5]); + auto grad_value = buildATensor(ctx, outs[0]); + auto grad_sampling_loc = buildATensor(ctx, outs[1]); + auto grad_attn_weight = buildATensor(ctx, outs[2]); + ms_deform_attn_backward(value, spatial_shapes, level_start_index, + sampling_loc, attn_weight, grad_output, grad_value, + grad_sampling_loc, grad_attn_weight, im2col_step); +} + +PARROTS_EXTENSION_REGISTER(ms_deform_attn_forward) + .attr("im2col_step") + .input(5) + .output(1) + .apply(ms_deform_attn_forward_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(ms_deform_attn_backward) + .attr("im2col_step") + .input(6) + .output(3) + .apply(ms_deform_attn_backward_parrots) + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms.cpp new file mode 100644 index 000000000..199d8af23 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms.cpp @@ -0,0 +1,33 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +Tensor nms_impl(Tensor boxes, Tensor scores, float iou_threshold, int offset) { + return DISPATCH_DEVICE_IMPL(nms_impl, boxes, scores, iou_threshold, offset); +} + +Tensor softnms_impl(Tensor boxes, Tensor scores, Tensor dets, + float iou_threshold, float sigma, float min_score, + int method, int offset) { + return DISPATCH_DEVICE_IMPL(softnms_impl, boxes, scores, dets, iou_threshold, + sigma, min_score, method, offset); +} + +std::vector > nms_match_impl(Tensor dets, + float iou_threshold) { + return DISPATCH_DEVICE_IMPL(nms_match_impl, dets, iou_threshold); +} + +Tensor nms(Tensor boxes, Tensor scores, float iou_threshold, int offset) { + return nms_impl(boxes, scores, iou_threshold, offset); +} + +Tensor softnms(Tensor boxes, Tensor scores, Tensor dets, float iou_threshold, + float sigma, float min_score, int method, int offset) { + return softnms_impl(boxes, scores, dets, iou_threshold, sigma, min_score, + method, offset); +} + +std::vector > nms_match(Tensor dets, float iou_threshold) { + return nms_match_impl(dets, iou_threshold); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_parrots.cpp new file mode 100644 index 000000000..db8b5f16e --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_parrots.cpp @@ -0,0 +1,140 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "nms_pytorch.h" + +using namespace parrots; + +// Tensor nms(Tensor boxes, Tensor scores, float iou_threshold, int offset); +template +void nms_parrots(T& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float iou_threshold; + int offset; + SSAttrs(attr) + .get("iou_threshold", iou_threshold) + .get("offset", offset) + .done(); + at::Tensor boxes, scores; + boxes = buildATensor(ctx, ins[0]); + scores = buildATensor(ctx, ins[1]); + auto out = nms(boxes, scores, iou_threshold, offset); + updateDArray(ctx, out, outs[0]); +} + +/*Tensor softnms(Tensor boxes, Tensor scores, Tensor dets, float iou_threshold, + * float sigma, float min_score, int method, int offset);*/ +template +void softnms_parrots(T& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float iou_threshold, sigma, min_score; + int method, offset; + SSAttrs(attr) + .get("iou_threshold", iou_threshold) + .get("sigma", sigma) + .get("min_score", min_score) + .get("method", method) + .get("offset", offset) + .done(); + at::Tensor boxes, scores, dets; + boxes = buildATensor(ctx, ins[0]); + scores = buildATensor(ctx, ins[1]); + dets = buildATensor(ctx, ins[2]); + auto out = softnms(boxes, scores, dets, iou_threshold, sigma, min_score, + method, offset); + updateDArray(ctx, out, outs[0]); +} + +// std::vector > nms_match(Tensor dets, float iou_threshold); +template +void nms_match_parrots(T& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float iou_threshold; + SSAttrs(attr).get("iou_threshold", iou_threshold).done(); + at::Tensor dets; + dets = buildATensor(ctx, ins[0]); + auto out = nms_match(dets, iou_threshold); + int n = out.size(), m = 0; + for (int i = 0; i < n; ++i) + if (m < out[i].size()) m = out[i].size(); + auto options = torch::TensorOptions().dtype(at::kInt); + auto tensor = torch::zeros({n, m}, options); + for (int i = 0; i < n; i++) + tensor.slice(0, i, i + 1) = + torch::from_blob(out[i].data(), {out[i].size()}, options); + updateDArray(ctx, tensor, outs[0]); +} + +/*Tensor nms_rotated(const Tensor dets, const Tensor scores, const Tensor order, + * const Tensor dets_sorted, const float iou_threshold, + * const int multi_label);*/ +template +void nms_rotated_parrots(T& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float iou_threshold; + int multi_label; + SSAttrs(attr) + .get("iou_threshold", iou_threshold) + .get("multi_label", multi_label) + .done(); + at::Tensor dets, scores, order, dets_sorted; + dets = buildATensor(ctx, ins[0]); + scores = buildATensor(ctx, ins[1]); + order = buildATensor(ctx, ins[2]); + dets_sorted = buildATensor(ctx, ins[3]); + auto out = + nms_rotated(dets, scores, order, dets_sorted, iou_threshold, multi_label); + updateDArray(ctx, out, outs[0]); +} + +PARROTS_EXTENSION_REGISTER(nms) + .attr("iou_threshold") + .attr("offset") + .input(2) + .output(1) + .apply(nms_parrots) +#ifdef MMCV_WITH_CUDA + .apply(nms_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(softnms) + .attr("iou_threshold") + .attr("sigma") + .attr("min_score") + .attr("method") + .attr("offset") + .input(3) + .output(1) + .apply(softnms_parrots) +#ifdef MMCV_WITH_CUDA + .apply(softnms_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(nms_match) + .attr("iou_threshold") + .input(1) + .output(1) + .apply(nms_match_parrots) +#ifdef MMCV_WITH_CUDA + .apply(nms_match_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(nms_rotated) + .attr("multi_label") + .attr("iou_threshold") + .input(4) + .output(1) + .apply(nms_rotated_parrots) +#ifdef MMCV_WITH_CUDA + .apply(nms_rotated_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_pytorch.h new file mode 100644 index 000000000..78c680e57 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_pytorch.h @@ -0,0 +1,18 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef NMS_PYTORCH_H +#define NMS_PYTORCH_H +#include + +at::Tensor nms(at::Tensor boxes, at::Tensor scores, float iou_threshold, + int offset); + +at::Tensor softnms(at::Tensor boxes, at::Tensor scores, at::Tensor dets, + float iou_threshold, float sigma, float min_score, + int method, int offset); + +std::vector > nms_match(at::Tensor dets, float iou_threshold); + +at::Tensor nms_rotated(const at::Tensor dets, const at::Tensor scores, + const at::Tensor order, const at::Tensor dets_sorted, + const float iou_threshold, const int multi_label); +#endif // NMS_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_rotated.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_rotated.cpp new file mode 100644 index 000000000..e4ef676a9 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_rotated.cpp @@ -0,0 +1,32 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +// modified from +// https://github.com/facebookresearch/detectron2/blob/master/detectron2/layers/csrc/nms_rotated/nms_rotated.h +#include "pytorch_cpp_helper.hpp" + +Tensor nms_rotated_cpu(const Tensor dets, const Tensor scores, + const float iou_threshold); + +#ifdef MMCV_WITH_CUDA +Tensor nms_rotated_cuda(const Tensor dets, const Tensor scores, + const Tensor order, const Tensor dets_sorted, + const float iou_threshold, const int multi_label); +#endif + +// Interface for Python +// inline is needed to prevent multiple function definitions when this header is +// included by different cpps +Tensor nms_rotated(const Tensor dets, const Tensor scores, const Tensor order, + const Tensor dets_sorted, const float iou_threshold, + const int multi_label) { + assert(dets.device().is_cuda() == scores.device().is_cuda()); + if (dets.device().is_cuda()) { +#ifdef MMCV_WITH_CUDA + return nms_rotated_cuda(dets, scores, order, dets_sorted, iou_threshold, + multi_label); +#else + AT_ERROR("Not compiled with GPU support"); +#endif + } + + return nms_rotated_cpu(dets, scores, iou_threshold); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group.cpp new file mode 100644 index 000000000..2bf8c8bbf --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group.cpp @@ -0,0 +1,26 @@ +// Copyright (c) OpenMMLab. All rights reserved +// It is modified from https://github.com/WenmuZhou/PAN.pytorch + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +std::vector> pixel_group_impl( + Tensor score, Tensor mask, Tensor embedding, Tensor kernel_label, + Tensor kernel_contour, int kernel_region_num, float dis_threshold) { + return DISPATCH_DEVICE_IMPL(pixel_group_impl, score, mask, embedding, + kernel_label, kernel_contour, kernel_region_num, + dis_threshold); +} + +std::vector> pixel_group( + Tensor score, Tensor mask, Tensor embedding, Tensor kernel_label, + Tensor kernel_contour, int kernel_region_num, float distance_threshold) { + score = score.contiguous(); + mask = mask.contiguous(); + embedding = embedding.contiguous(); + kernel_label = kernel_label.contiguous(); + kernel_contour = kernel_contour.contiguous(); + + return pixel_group_impl(score, mask, embedding, kernel_label, kernel_contour, + kernel_region_num, distance_threshold); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_parrots.cpp new file mode 100644 index 000000000..bd863a4e1 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_parrots.cpp @@ -0,0 +1,54 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "pixel_group_pytorch.h" + +using namespace parrots; +using namespace std; + +template +void pixel_group_parrots(T& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int kernel_region_num; + float distance_threshold; + SSAttrs(attr) + .get("kernel_region_num", kernel_region_num) + .get("distance_threshold", distance_threshold) + .done(); + at::Tensor score; + at::Tensor mask; + at::Tensor embedding; + at::Tensor kernel_label; + at::Tensor kernel_contour; + score = buildATensor(ctx, ins[0]); + mask = buildATensor(ctx, ins[1]); + embedding = buildATensor(ctx, ins[2]); + kernel_label = buildATensor(ctx, ins[3]); + kernel_contour = buildATensor(ctx, ins[4]); + auto out = pixel_group(score, mask, embedding, kernel_label, kernel_contour, + kernel_region_num, distance_threshold); + int n = out.size(); + std::vector out_tensor; + for (int i = 0; i < n; ++i) out_tensor.push_back(float(out[i].size())); + for (int i = 0; i < n; ++i) + out_tensor.insert(out_tensor.end(), out[i].begin(), out[i].end()); + auto options = torch::TensorOptions().dtype(at::kFloat); + auto tensor = torch::zeros({1, out_tensor.size()}, options); + tensor.slice(0, 0, 1) = + torch::from_blob(out_tensor.data(), {out_tensor.size()}, options); + updateDArray(ctx, tensor, outs[0]); +} + +PARROTS_EXTENSION_REGISTER(pixel_group) + .attr("kernel_region_num") + .attr("distance_threshold") + .input(5) + .output(1) + .apply(pixel_group_parrots) +#ifdef MMCV_WITH_CUDA + .apply(pixel_group_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_pytorch.h new file mode 100644 index 000000000..1686ef3ee --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_pytorch.h @@ -0,0 +1,11 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef PIXEL_GROUP_PYTORCH_H +#define PIXEL_GROUP_PYTORCH_H +#include +using namespace at; + +std::vector> pixel_group( + Tensor score, Tensor mask, Tensor embedding, Tensor kernel_label, + Tensor kernel_contour, int kernel_region_num, float distance_threshold); + +#endif // PIXEL_GROUP_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes.cpp new file mode 100644 index 000000000..540da9403 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes.cpp @@ -0,0 +1,44 @@ +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void points_in_boxes_part_forward_impl(int batch_size, int boxes_num, + int pts_num, const Tensor boxes, + const Tensor pts, + Tensor box_idx_of_points) { + DISPATCH_DEVICE_IMPL(points_in_boxes_part_forward_impl, batch_size, boxes_num, + pts_num, boxes, pts, box_idx_of_points); +} + +void points_in_boxes_all_forward_impl(int batch_size, int boxes_num, + int pts_num, const Tensor boxes, + const Tensor pts, + Tensor box_idx_of_points) { + DISPATCH_DEVICE_IMPL(points_in_boxes_all_forward_impl, batch_size, boxes_num, + pts_num, boxes, pts, box_idx_of_points); +} + +void points_in_boxes_part_forward(Tensor boxes_tensor, Tensor pts_tensor, + Tensor box_idx_of_points_tensor) { + // params boxes: (B, N, 7) [x, y, z, x_size, y_size, z_size, rz] in LiDAR + // coordinate, z is the bottom center, each box params pts: (B, npoints, 3) + // [x, y, z] in LiDAR coordinate params boxes_idx_of_points: (B, npoints), + // default -1 + int batch_size = boxes_tensor.size(0); + int boxes_num = boxes_tensor.size(1); + int pts_num = pts_tensor.size(1); + points_in_boxes_part_forward_impl(batch_size, boxes_num, pts_num, + boxes_tensor, pts_tensor, + box_idx_of_points_tensor); +} + +void points_in_boxes_all_forward(Tensor boxes_tensor, Tensor pts_tensor, + Tensor box_idx_of_points_tensor) { + // params boxes: (B, N, 7) [x, y, z, x_size, y_size, z_size, rz] in LiDAR + // coordinate, z is the bottom center. params pts: (B, npoints, 3) [x, y, z] + // in LiDAR coordinate params boxes_idx_of_points: (B, npoints), default -1 + int batch_size = boxes_tensor.size(0); + int boxes_num = boxes_tensor.size(1); + int pts_num = pts_tensor.size(1); + points_in_boxes_all_forward_impl(batch_size, boxes_num, pts_num, boxes_tensor, + pts_tensor, box_idx_of_points_tensor); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_parrots.cpp new file mode 100644 index 000000000..afd2b0eb2 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_parrots.cpp @@ -0,0 +1,64 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "points_in_boxes_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void points_in_boxes_part_forward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto boxes_tensor = buildATensor(ctx, ins[0]); + auto pts_tensor = buildATensor(ctx, ins[1]); + + auto box_idx_of_points_tensor = buildATensor(ctx, outs[0]); + + points_in_boxes_part_forward(boxes_tensor, pts_tensor, + box_idx_of_points_tensor); +} + +void points_in_boxes_all_forward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto boxes_tensor = buildATensor(ctx, ins[0]); + auto pts_tensor = buildATensor(ctx, ins[1]); + + auto box_idx_of_points_tensor = buildATensor(ctx, outs[0]); + + points_in_boxes_all_forward(boxes_tensor, pts_tensor, + box_idx_of_points_tensor); +} + +PARROTS_EXTENSION_REGISTER(points_in_boxes_part_forward) + .input(2) + .output(1) + .apply(points_in_boxes_part_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(points_in_boxes_all_forward) + .input(2) + .output(1) + .apply(points_in_boxes_all_forward_cuda_parrots) + .done(); +#endif + +void points_in_boxes_forward_cpu_parrots(HostContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto boxes_tensor = buildATensor(ctx, ins[0]); + auto pts_tensor = buildATensor(ctx, ins[1]); + + auto pts_indices_tensor = buildATensor(ctx, outs[0]); + + points_in_boxes_cpu_forward(boxes_tensor, pts_tensor, pts_indices_tensor); +} + +PARROTS_EXTENSION_REGISTER(points_in_boxes_cpu_forward) + .input(2) + .output(1) + .apply(points_in_boxes_forward_cpu_parrots) + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_pytorch.h new file mode 100644 index 000000000..f3e465e3c --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_pytorch.h @@ -0,0 +1,16 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef POINTS_IN_BOXES_PYTORCH_H +#define POINTS_IN_BOXES_PYTORCH_H +#include +using namespace at; + +void points_in_boxes_part_forward(Tensor boxes_tensor, Tensor pts_tensor, + Tensor box_idx_of_points_tensor); + +void points_in_boxes_all_forward(Tensor boxes_tensor, Tensor pts_tensor, + Tensor box_idx_of_points_tensor); + +void points_in_boxes_cpu_forward(Tensor boxes_tensor, Tensor pts_tensor, + Tensor pts_indices_tensor); + +#endif // POINTS_IN_BOXES_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons.cpp new file mode 100644 index 000000000..75a93dcef --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons.cpp @@ -0,0 +1,15 @@ +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void points_in_polygons_forward_impl(const Tensor points, const Tensor polygons, + Tensor output, const int rows, + const int cols) { + DISPATCH_DEVICE_IMPL(points_in_polygons_forward_impl, points, polygons, + output, rows, cols); +} + +void points_in_polygons_forward(Tensor points, Tensor polygons, Tensor output) { + int rows = points.size(0); + int cols = polygons.size(0); + points_in_polygons_forward_impl(points, polygons, output, rows, cols); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_parrots.cpp new file mode 100644 index 000000000..d52018e64 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_parrots.cpp @@ -0,0 +1,28 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "points_in_polygons_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void points_in_polygons_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto points = buildATensor(ctx, ins[0]); + auto polygons = buildATensor(ctx, ins[1]); + + auto output = buildATensor(ctx, outs[0]); + + points_in_polygons_forward(points, polygons, output); +} + +PARROTS_EXTENSION_REGISTER(points_in_polygons_forward) + .input(2) + .output(1) + .apply(points_in_polygons_cuda_parrots) + .done(); + +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_pytorch.h new file mode 100644 index 000000000..042678143 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_pytorch.h @@ -0,0 +1,9 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef POINTS_IN_POLYGONS_PYTORCH_H +#define POINTS_IN_POLYGONS_PYTORCH_H +#include +using namespace at; + +void points_in_polygons_forward(Tensor points, Tensor polygons, Tensor output); + +#endif // POINTS_IN_POLYGONS_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool.cpp new file mode 100644 index 000000000..00db84a15 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool.cpp @@ -0,0 +1,47 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void prroi_pool_forward_impl(Tensor input, Tensor rois, Tensor output, + int pooled_height, int pooled_width, + float spatial_scale) { + DISPATCH_DEVICE_IMPL(prroi_pool_forward_impl, input, rois, output, + pooled_height, pooled_width, spatial_scale); +} + +void prroi_pool_backward_impl(Tensor grad_output, Tensor rois, + Tensor grad_input, int pooled_height, + int pooled_width, float spatial_scale) { + DISPATCH_DEVICE_IMPL(prroi_pool_backward_impl, grad_output, rois, grad_input, + pooled_height, pooled_width, spatial_scale); +} + +void prroi_pool_coor_backward_impl(Tensor output, Tensor grad_output, + Tensor input, Tensor rois, Tensor grad_rois, + int pooled_height, int pooled_width, + float spatial_scale) { + DISPATCH_DEVICE_IMPL(prroi_pool_coor_backward_impl, output, grad_output, + input, rois, grad_rois, pooled_height, pooled_width, + spatial_scale); +} + +void prroi_pool_forward(Tensor input, Tensor rois, Tensor output, + int pooled_height, int pooled_width, + float spatial_scale) { + prroi_pool_forward_impl(input, rois, output, pooled_height, pooled_width, + spatial_scale); +} + +void prroi_pool_backward(Tensor grad_output, Tensor rois, Tensor grad_input, + int pooled_height, int pooled_width, + float spatial_scale) { + prroi_pool_backward_impl(grad_output, rois, grad_input, pooled_height, + pooled_width, spatial_scale); +} + +void prroi_pool_coor_backward(Tensor output, Tensor grad_output, Tensor input, + Tensor rois, Tensor grad_rois, int pooled_height, + int pooled_width, float spatial_scale) { + prroi_pool_coor_backward_impl(output, grad_output, input, rois, grad_rois, + pooled_height, pooled_width, spatial_scale); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_parrots.cpp new file mode 100644 index 000000000..4e8295581 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_parrots.cpp @@ -0,0 +1,97 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "prroi_pool_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void prroi_pool_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + prroi_pool_forward(input, rois, output, pooled_height, pooled_width, + spatial_scale); +} + +void prroi_pool_backward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .done(); + + const auto& grad_output = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + auto grad_input = buildATensor(ctx, outs[0]); + prroi_pool_backward(grad_output, rois, grad_input, pooled_height, + pooled_width, spatial_scale); +} + +void prroi_pool_coor_backward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .done(); + + const auto& output = buildATensor(ctx, ins[0]); + const auto& grad_output = buildATensor(ctx, ins[1]); + const auto& input = buildATensor(ctx, ins[2]); + const auto& rois = buildATensor(ctx, ins[3]); + auto grad_rois = buildATensor(ctx, outs[0]); + prroi_pool_coor_backward(output, grad_output, input, rois, grad_rois, + pooled_height, pooled_width, spatial_scale); +} + +PARROTS_EXTENSION_REGISTER(prroi_pool_forward) + .attr("pooled_height") + .attr("pooled_width") + .attr("spatial_scale") + .input(2) + .output(1) + .apply(prroi_pool_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(prroi_pool_backward) + .attr("pooled_height") + .attr("pooled_width") + .attr("spatial_scale") + .input(2) + .output(1) + .apply(prroi_pool_backward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(prroi_pool_coor_backward) + .attr("pooled_height") + .attr("pooled_width") + .attr("spatial_scale") + .input(4) + .output(1) + .apply(prroi_pool_coor_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_pytorch.h new file mode 100644 index 000000000..451b01dd5 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_pytorch.h @@ -0,0 +1,19 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef PRROI_POOL_PYTORCH_H +#define PRROI_POOL_PYTORCH_H +#include +using namespace at; + +void prroi_pool_forward(Tensor input, Tensor rois, Tensor output, + int pooled_height, int pooled_width, + float spatial_scale); + +void prroi_pool_backward(Tensor grad_output, Tensor rois, Tensor grad_input, + int pooled_height, int pooled_width, + float spatial_scale); + +void prroi_pool_coor_backward(Tensor output, Tensor grad_output, Tensor input, + Tensor rois, Tensor grad_rois, int pooled_height, + int pooled_width, float spatial_scale); + +#endif // PRROI_POOL_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask.cpp new file mode 100644 index 000000000..6064c9ba5 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask.cpp @@ -0,0 +1,41 @@ +// Copyright (c) OpenMMLab. All rights reserved +// Modified from +// https://github.com/hszhao/semseg/blob/master/lib/psa/src +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void psamask_forward_impl(const int psa_type, const Tensor input, Tensor output, + const int num_, const int h_feature, + const int w_feature, const int h_mask, + const int w_mask, const int half_h_mask, + const int half_w_mask) { + DISPATCH_DEVICE_IMPL(psamask_forward_impl, psa_type, input, output, num_, + h_feature, w_feature, h_mask, w_mask, half_h_mask, + half_w_mask); +} + +void psamask_backward_impl(const int psa_type, const Tensor grad_output, + Tensor grad_input, const int num_, + const int h_feature, const int w_feature, + const int h_mask, const int w_mask, + const int half_h_mask, const int half_w_mask) { + DISPATCH_DEVICE_IMPL(psamask_backward_impl, psa_type, grad_output, grad_input, + num_, h_feature, w_feature, h_mask, w_mask, half_h_mask, + half_w_mask); +} + +void psamask_forward(const Tensor input, Tensor output, const int psa_type, + const int num_, const int h_feature, const int w_feature, + const int h_mask, const int w_mask, const int half_h_mask, + const int half_w_mask) { + psamask_forward_impl(psa_type, input, output, num_, h_feature, w_feature, + h_mask, w_mask, half_h_mask, half_w_mask); +} + +void psamask_backward(Tensor grad_output, const Tensor grad_input, + const int psa_type, const int num_, const int h_feature, + const int w_feature, const int h_mask, const int w_mask, + const int half_h_mask, const int half_w_mask) { + psamask_backward_impl(psa_type, grad_output, grad_input, num_, h_feature, + w_feature, h_mask, w_mask, half_h_mask, half_w_mask); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_parrots.cpp new file mode 100644 index 000000000..f67102d02 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_parrots.cpp @@ -0,0 +1,129 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "psamask_pytorch.h" +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void psamask_forward_cuda_parrots(CudaContext &ctx, const SSElement &attr, + const OperatorBase::in_list_t &ins, + OperatorBase::out_list_t &outs) { + int psa_type, num_, h_feature, w_feature, h_mask, w_mask, half_h_mask, + half_w_mask; + SSAttrs(attr) + .get("psa_type", psa_type) + .get("num_", num_) + .get("h_feature", h_feature) + .get("w_feature", w_feature) + .get("h_mask", h_mask) + .get("w_mask", w_mask) + .get("half_h_mask", half_h_mask) + .get("half_w_mask", half_w_mask) + .done(); + const auto &input = buildATensor(ctx, ins[0]); + auto output = buildATensor(ctx, outs[0]); + psamask_forward_cuda(psa_type, input, output, num_, h_feature, w_feature, + h_mask, w_mask, half_h_mask, half_w_mask); +} + +void psamask_backward_cuda_parrots(CudaContext &ctx, const SSElement &attr, + const OperatorBase::in_list_t &ins, + OperatorBase::out_list_t &outs) { + int psa_type, num_, h_feature, w_feature, h_mask, w_mask, half_h_mask, + half_w_mask; + SSAttrs(attr) + .get("psa_type", psa_type) + .get("num_", num_) + .get("h_feature", h_feature) + .get("w_feature", w_feature) + .get("h_mask", h_mask) + .get("w_mask", w_mask) + .get("half_h_mask", half_h_mask) + .get("half_w_mask", half_w_mask) + .done(); + + const auto &grad_output = buildATensor(ctx, ins[0]); + auto grad_input = buildATensor(ctx, outs[0]); + psamask_backward_cuda(psa_type, grad_output, grad_input, num_, h_feature, + w_feature, h_mask, w_mask, half_h_mask, half_w_mask); +} +#endif + +void psamask_forward_cpu_parrots(HostContext &ctx, const SSElement &attr, + const OperatorBase::in_list_t &ins, + OperatorBase::out_list_t &outs) { + int psa_type, num_, h_feature, w_feature, h_mask, w_mask, half_h_mask, + half_w_mask; + SSAttrs(attr) + .get("psa_type", psa_type) + .get("num_", num_) + .get("h_feature", h_feature) + .get("w_feature", w_feature) + .get("h_mask", h_mask) + .get("w_mask", w_mask) + .get("half_h_mask", half_h_mask) + .get("half_w_mask", half_w_mask) + .done(); + const auto &input = buildATensor(ctx, ins[0]); + auto output = buildATensor(ctx, outs[0]); + psamask_forward_cpu(psa_type, input, output, num_, h_feature, w_feature, + h_mask, w_mask, half_h_mask, half_w_mask); +} + +void psamask_backward_cpu_parrots(HostContext &ctx, const SSElement &attr, + const OperatorBase::in_list_t &ins, + OperatorBase::out_list_t &outs) { + int psa_type, num_, h_feature, w_feature, h_mask, w_mask, half_h_mask, + half_w_mask; + SSAttrs(attr) + .get("psa_type", psa_type) + .get("num_", num_) + .get("h_feature", h_feature) + .get("w_feature", w_feature) + .get("h_mask", h_mask) + .get("w_mask", w_mask) + .get("half_h_mask", half_h_mask) + .get("half_w_mask", half_w_mask) + .done(); + + const auto &grad_output = buildATensor(ctx, ins[0]); + auto grad_input = buildATensor(ctx, outs[0]); + psamask_backward_cpu(psa_type, grad_output, grad_input, num_, h_feature, + w_feature, h_mask, w_mask, half_h_mask, half_w_mask); +} + +PARROTS_EXTENSION_REGISTER(psamask_forward) + .attr("psa_type") + .attr("num_") + .attr("h_feature") + .attr("w_feature") + .attr("h_mask") + .attr("w_mask") + .attr("half_h_mask") + .attr("half_w_mask") + .input(1) + .output(1) + .apply(psamask_forward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(psamask_forward_cuda_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(psamask_backward) + .attr("psa_type") + .attr("num_") + .attr("h_feature") + .attr("w_feature") + .attr("h_mask") + .attr("w_mask") + .attr("half_h_mask") + .attr("half_w_mask") + .input(1) + .output(1) + .apply(psamask_backward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(psamask_backward_cuda_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_pytorch.h new file mode 100644 index 000000000..c3f0579ef --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_pytorch.h @@ -0,0 +1,31 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef PSAMASK_PYTORCH_H +#define PSAMASK_PYTORCH_H +#include +using namespace at; + +#ifdef MMCV_WITH_CUDA +void psamask_forward_cuda(const int psa_type, const Tensor input, Tensor output, + const int num_, const int h_feature, + const int w_feature, const int h_mask, + const int w_mask, const int half_h_mask, + const int half_w_mask); + +void psamask_backward_cuda(const int psa_type, const Tensor grad_output, + Tensor grad_input, const int num_, + const int h_feature, const int w_feature, + const int h_mask, const int w_mask, + const int half_h_mask, const int half_w_mask); +#endif +void psamask_forward_cpu(const int psa_type, const Tensor input, Tensor output, + const int num_, const int h_feature, + const int w_feature, const int h_mask, + const int w_mask, const int half_h_mask, + const int half_w_mask); + +void psamask_backward_cpu(const int psa_type, const Tensor grad_output, + Tensor grad_input, const int num_, + const int h_feature, const int w_feature, + const int h_mask, const int w_mask, + const int half_h_mask, const int half_w_mask); +#endif // PSAMASK_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated.cpp new file mode 100644 index 000000000..81ffa9fd6 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated.cpp @@ -0,0 +1,42 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void riroi_align_rotated_forward_impl(Tensor features, Tensor rois, + Tensor output, int pooled_height, + int pooled_width, float spatial_scale, + int num_samples, int num_orientations, + bool clockwise) { + DISPATCH_DEVICE_IMPL(riroi_align_rotated_forward_impl, features, rois, output, + pooled_height, pooled_width, spatial_scale, num_samples, + num_orientations, clockwise); +} + +void riroi_align_rotated_backward_impl(Tensor top_grad, Tensor rois, + Tensor bottom_grad, int pooled_height, + int pooled_width, float spatial_scale, + int num_samples, int num_orientations, + bool clockwise) { + DISPATCH_DEVICE_IMPL(riroi_align_rotated_backward_impl, top_grad, rois, + bottom_grad, pooled_height, pooled_width, spatial_scale, + num_samples, num_orientations, clockwise); +} + +void riroi_align_rotated_forward(Tensor features, Tensor rois, Tensor output, + int pooled_height, int pooled_width, + float spatial_scale, int num_samples, + int num_orientations, bool clockwise) { + riroi_align_rotated_forward_impl(features, rois, output, pooled_height, + pooled_width, spatial_scale, num_samples, + num_orientations, clockwise); +} + +void riroi_align_rotated_backward(Tensor top_grad, Tensor rois, + Tensor bottom_grad, int pooled_height, + int pooled_width, float spatial_scale, + int num_samples, int num_orientations, + bool clockwise) { + riroi_align_rotated_backward_impl(top_grad, rois, bottom_grad, pooled_height, + pooled_width, spatial_scale, num_samples, + num_orientations, clockwise); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_parrots.cpp new file mode 100644 index 000000000..5eb340ce4 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_parrots.cpp @@ -0,0 +1,86 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "riroi_align_rotated_pytorch.h" +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void riroi_align_rotated_forward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + int sample_num; + int num_orientations; + bool clockwise; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .get("num_samples", sample_num) + .get("num_orientations", num_orientations) + .get("clockwise", clockwise) + .done(); + + auto input = buildATensor(ctx, ins[0]); + auto rois = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + riroi_align_rotated_forward(input, rois, output, pooled_height, pooled_width, + spatial_scale, sample_num, num_orientations, + clockwise); +} + +void riroi_align_rotated_backward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + int sample_num; + int num_orientations; + bool clockwise; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .get("num_samples", sample_num) + .get("num_orientations", num_orientations) + .get("clockwise", clockwise) + .done(); + + auto grad_output = buildATensor(ctx, ins[0]); + auto rois = buildATensor(ctx, ins[1]); + auto grad_input = buildATensor(ctx, outs[0]); + riroi_align_rotated_backward(grad_output, rois, grad_input, pooled_height, + pooled_width, spatial_scale, sample_num, + num_orientations, clockwise); +} + +PARROTS_EXTENSION_REGISTER(riroi_align_rotated_forward) + .attr("pooled_height") + .attr("pooled_width") + .attr("spatial_scale") + .attr("num_samples") + .attr("num_orientations") + .attr("clockwise") + .input(2) + .output(1) + .apply(riroi_align_rotated_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(riroi_align_rotated_backward) + .attr("pooled_height") + .attr("pooled_width") + .attr("spatial_scale") + .attr("num_samples") + .attr("num_orientations") + .attr("clockwise") + .input(2) + .output(1) + .apply(riroi_align_rotated_backward_cuda_parrots) + .done(); + +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_pytorch.h new file mode 100644 index 000000000..49a30bffa --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_pytorch.h @@ -0,0 +1,18 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef RIROI_ALIGN_ROTATED_PYTORCH_H +#define RIROI_ALIGN_ROTATED_PYTORCH_H +#include +using namespace at; + +void riroi_align_rotated_forward(Tensor features, Tensor rois, Tensor output, + int pooled_height, int pooled_width, + float spatial_scale, int num_samples, + int num_orientations, bool clockwise); + +void riroi_align_rotated_backward(Tensor top_grad, Tensor rois, + Tensor bottom_grad, int pooled_height, + int pooled_width, float spatial_scale, + int num_samples, int num_orientations, + bool clockwise); + +#endif // RIROI_ALIGN_ROTATED_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align.cpp new file mode 100644 index 000000000..6e7077397 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align.cpp @@ -0,0 +1,41 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void roi_align_forward_impl(Tensor input, Tensor rois, Tensor output, + Tensor argmax_y, Tensor argmax_x, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned) { + DISPATCH_DEVICE_IMPL(roi_align_forward_impl, input, rois, output, argmax_y, + argmax_x, aligned_height, aligned_width, spatial_scale, + sampling_ratio, pool_mode, aligned); +} + +void roi_align_backward_impl(Tensor grad_output, Tensor rois, Tensor argmax_y, + Tensor argmax_x, Tensor grad_input, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned) { + DISPATCH_DEVICE_IMPL(roi_align_backward_impl, grad_output, rois, argmax_y, + argmax_x, grad_input, aligned_height, aligned_width, + spatial_scale, sampling_ratio, pool_mode, aligned); +} + +void roi_align_forward(Tensor input, Tensor rois, Tensor output, + Tensor argmax_y, Tensor argmax_x, int aligned_height, + int aligned_width, float spatial_scale, + int sampling_ratio, int pool_mode, bool aligned) { + roi_align_forward_impl(input, rois, output, argmax_y, argmax_x, + aligned_height, aligned_width, spatial_scale, + sampling_ratio, pool_mode, aligned); +} + +void roi_align_backward(Tensor grad_output, Tensor rois, Tensor argmax_y, + Tensor argmax_x, Tensor grad_input, int aligned_height, + int aligned_width, float spatial_scale, + int sampling_ratio, int pool_mode, bool aligned) { + roi_align_backward_impl(grad_output, rois, argmax_y, argmax_x, grad_input, + aligned_height, aligned_width, spatial_scale, + sampling_ratio, pool_mode, aligned); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_parrots.cpp new file mode 100644 index 000000000..60abea092 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_parrots.cpp @@ -0,0 +1,151 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "roi_align_pytorch.h" +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void roi_align_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int aligned_height; + int aligned_width; + float spatial_scale; + int sampling_ratio; + int pool_mode; + bool aligned; + SSAttrs(attr) + .get("aligned_height", aligned_height) + .get("aligned_width", aligned_width) + .get("spatial_scale", spatial_scale) + .get("sampling_ratio", sampling_ratio) + .get("pool_mode", pool_mode) + .get("aligned", aligned) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + auto argmax_y = buildATensor(ctx, outs[1]); + auto argmax_x = buildATensor(ctx, outs[2]); + roi_align_forward_cuda(input, rois, output, argmax_y, argmax_x, + aligned_height, aligned_width, spatial_scale, + sampling_ratio, pool_mode, aligned); +} + +void roi_align_backward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int aligned_height; + int aligned_width; + float spatial_scale; + int sampling_ratio; + int pool_mode; + bool aligned; + SSAttrs(attr) + .get("aligned_height", aligned_height) + .get("aligned_width", aligned_width) + .get("spatial_scale", spatial_scale) + .get("sampling_ratio", sampling_ratio) + .get("pool_mode", pool_mode) + .get("aligned", aligned) + .done(); + + const auto& grad_output = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + const auto& argmax_y = buildATensor(ctx, ins[2]); + const auto& argmax_x = buildATensor(ctx, ins[3]); + auto grad_input = buildATensor(ctx, outs[0]); + roi_align_backward_cuda(grad_output, rois, argmax_y, argmax_x, grad_input, + aligned_height, aligned_width, spatial_scale, + sampling_ratio, pool_mode, aligned); +} +#endif + +void roi_align_forward_cpu_parrots(HostContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int aligned_height; + int aligned_width; + float spatial_scale; + int sampling_ratio; + int pool_mode; + bool aligned; + SSAttrs(attr) + .get("aligned_height", aligned_height) + .get("aligned_width", aligned_width) + .get("spatial_scale", spatial_scale) + .get("sampling_ratio", sampling_ratio) + .get("pool_mode", pool_mode) + .get("aligned", aligned) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + auto argmax_y = buildATensor(ctx, outs[1]); + auto argmax_x = buildATensor(ctx, outs[2]); + roi_align_forward_cpu(input, rois, output, argmax_y, argmax_x, aligned_height, + aligned_width, spatial_scale, sampling_ratio, pool_mode, + aligned); +} + +void roi_align_backward_cpu_parrots(HostContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int aligned_height; + int aligned_width; + float spatial_scale; + int sampling_ratio; + int pool_mode; + bool aligned; + SSAttrs(attr) + .get("aligned_height", aligned_height) + .get("aligned_width", aligned_width) + .get("spatial_scale", spatial_scale) + .get("sampling_ratio", sampling_ratio) + .get("pool_mode", pool_mode) + .get("aligned", aligned) + .done(); + + const auto& grad_output = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + const auto& argmax_y = buildATensor(ctx, ins[2]); + const auto& argmax_x = buildATensor(ctx, ins[3]); + auto grad_input = buildATensor(ctx, outs[0]); + roi_align_backward_cpu(grad_output, rois, argmax_y, argmax_x, grad_input, + aligned_height, aligned_width, spatial_scale, + sampling_ratio, pool_mode, aligned); +} + +PARROTS_EXTENSION_REGISTER(roi_align_forward) + .attr("aligned_height") + .attr("aligned_width") + .attr("spatial_scale") + .attr("sampling_ratio") + .attr("pool_mode") + .attr("aligned") + .input(2) + .output(3) + .apply(roi_align_forward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(roi_align_forward_cuda_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(roi_align_backward) + .attr("aligned_height") + .attr("aligned_width") + .attr("spatial_scale") + .attr("sampling_ratio") + .attr("pool_mode") + .attr("aligned") + .input(4) + .output(1) + .apply(roi_align_backward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(roi_align_backward_cuda_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_pytorch.h new file mode 100644 index 000000000..4c6016098 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_pytorch.h @@ -0,0 +1,32 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef ROI_ALIGN_PYTORCH_H +#define ROI_ALIGN_PYTORCH_H +#include +using namespace at; + +#ifdef MMCV_WITH_CUDA +void roi_align_forward_cuda(Tensor input, Tensor rois, Tensor output, + Tensor argmax_y, Tensor argmax_x, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned); + +void roi_align_backward_cuda(Tensor grad_output, Tensor rois, Tensor argmax_y, + Tensor argmax_x, Tensor grad_input, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned); +#endif + +void roi_align_forward_cpu(Tensor input, Tensor rois, Tensor output, + Tensor argmax_y, Tensor argmax_x, int aligned_height, + int aligned_width, float spatial_scale, + int sampling_ratio, int pool_mode, bool aligned); + +void roi_align_backward_cpu(Tensor grad_output, Tensor rois, Tensor argmax_y, + Tensor argmax_x, Tensor grad_input, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + int pool_mode, bool aligned); + +#endif // ROI_ALIGN_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated.cpp new file mode 100644 index 000000000..5ef691ada --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated.cpp @@ -0,0 +1,41 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void roi_align_rotated_forward_impl(Tensor features, Tensor rois, Tensor output, + int aligned_height, int aligned_width, + float spatial_scale, int sample_ratio, + bool aligned, bool clockwise) { + DISPATCH_DEVICE_IMPL(roi_align_rotated_forward_impl, features, rois, output, + aligned_height, aligned_width, spatial_scale, + sample_ratio, aligned, clockwise); +} + +void roi_align_rotated_backward_impl(Tensor top_grad, Tensor rois, + Tensor bottom_grad, int aligned_height, + int aligned_width, float spatial_scale, + int sample_ratio, bool aligned, + bool clockwise) { + DISPATCH_DEVICE_IMPL(roi_align_rotated_backward_impl, top_grad, rois, + bottom_grad, aligned_height, aligned_width, + spatial_scale, sample_ratio, aligned, clockwise); +} + +void roi_align_rotated_forward(Tensor input, Tensor rois, Tensor output, + int aligned_height, int aligned_width, + float spatial_scale, int sampling_ratio, + bool aligned, bool clockwise) { + roi_align_rotated_forward_impl(input, rois, output, aligned_height, + aligned_width, spatial_scale, sampling_ratio, + aligned, clockwise); +} + +void roi_align_rotated_backward(Tensor top_grad, Tensor rois, + Tensor bottom_grad, int aligned_height, + int aligned_width, float spatial_scale, + int sampling_ratio, bool aligned, + bool clockwise) { + roi_align_rotated_backward_impl(top_grad, rois, bottom_grad, aligned_height, + aligned_width, spatial_scale, sampling_ratio, + aligned, clockwise); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_parrots.cpp new file mode 100644 index 000000000..9386250a2 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_parrots.cpp @@ -0,0 +1,147 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "roi_align_rotated_pytorch.h" +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void roi_align_rotated_forward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + int sampling_ratio; + bool aligned; + bool clockwise; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .get("sampling_ratio", sampling_ratio) + .get("aligned", aligned) + .get("clockwise", clockwise) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + roi_align_rotated_forward_cuda(input, rois, output, pooled_height, + pooled_width, spatial_scale, sampling_ratio, + aligned, clockwise); +} + +void roi_align_rotated_backward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + int sampling_ratio; + bool aligned; + bool clockwise; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .get("sampling_ratio", sampling_ratio) + .get("aligned", aligned) + .get("clockwise", clockwise) + .done(); + + const auto& grad_output = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + auto grad_input = buildATensor(ctx, outs[0]); + roi_align_rotated_backward_cuda(grad_output, rois, grad_input, pooled_height, + pooled_width, spatial_scale, sampling_ratio, + aligned, clockwise); +} +#endif + +void roi_align_rotated_forward_cpu_parrots(HostContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + int sampling_ratio; + bool aligned; + bool clockwise; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .get("sampling_ratio", sampling_ratio) + .get("aligned", aligned) + .get("clockwise", clockwise) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + roi_align_rotated_forward_cpu(input, rois, output, pooled_height, + pooled_width, spatial_scale, sampling_ratio, + aligned, clockwise); +} + +void roi_align_rotated_backward_cpu_parrots(HostContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + int sampling_ratio; + bool aligned; + bool clockwise; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .get("sampling_ratio", sampling_ratio) + .get("aligned", aligned) + .get("clockwise", clockwise) + .done(); + + const auto& grad_output = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + auto grad_input = buildATensor(ctx, outs[0]); + roi_align_rotated_backward_cpu(grad_output, rois, grad_input, pooled_height, + pooled_width, spatial_scale, sampling_ratio, + aligned, clockwise); +} + +PARROTS_EXTENSION_REGISTER(roi_align_rotated_forward) + .attr("pooled_height") + .attr("pooled_width") + .attr("spatial_scale") + .attr("sampling_ratio") + .attr("aligned") + .attr("clockwise") + .input(2) + .output(1) + .apply(roi_align_rotated_forward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(roi_align_rotated_forward_cuda_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(roi_align_rotated_backward) + .attr("pooled_height") + .attr("pooled_width") + .attr("spatial_scale") + .attr("sampling_ratio") + .attr("aligned") + .attr("clockwise") + .input(2) + .output(1) + .apply(roi_align_rotated_backward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(roi_align_rotated_backward_cuda_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_pytorch.h new file mode 100644 index 000000000..8136b56d1 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_pytorch.h @@ -0,0 +1,31 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef ROI_ALIGN_ROTATED_PYTORCH_H +#define ROI_ALIGN_ROTATED_PYTORCH_H +#include +using namespace at; + +#ifdef MMCV_WITH_CUDA +void roi_align_rotated_forward_cuda(Tensor input, Tensor rois, Tensor output, + int pooled_height, int pooled_width, + float spatial_scale, int sampling_ratio, + bool aligned, bool clockwise); + +void roi_align_rotated_backward_cuda(Tensor grad_output, Tensor rois, + Tensor bottom_grad, int pooled_height, + int pooled_width, float spatial_scale, + int sampling_ratio, bool aligned, + bool clockwise); +#endif + +void roi_align_rotated_forward_cpu(Tensor input, Tensor rois, Tensor output, + int pooled_height, int pooled_width, + float spatial_scale, int sampling_ratio, + bool aligned, bool clockwise); + +void roi_align_rotated_backward_cpu(Tensor grad_output, Tensor rois, + Tensor bottom_grad, int pooled_height, + int pooled_width, float spatial_scale, + int sampling_ratio, bool aligned, + bool clockwise); + +#endif // ROI_ALIGN_ROTATED_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool.cpp new file mode 100644 index 000000000..bba90b806 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool.cpp @@ -0,0 +1,31 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void roi_pool_forward_impl(Tensor input, Tensor rois, Tensor output, + Tensor argmax, int pooled_height, int pooled_width, + float spatial_scale) { + DISPATCH_DEVICE_IMPL(roi_pool_forward_impl, input, rois, output, argmax, + pooled_height, pooled_width, spatial_scale); +} + +void roi_pool_backward_impl(Tensor grad_output, Tensor rois, Tensor argmax, + Tensor grad_input, int pooled_height, + int pooled_width, float spatial_scale) { + DISPATCH_DEVICE_IMPL(roi_pool_backward_impl, grad_output, rois, argmax, + grad_input, pooled_height, pooled_width, spatial_scale); +} + +void roi_pool_forward(Tensor input, Tensor rois, Tensor output, Tensor argmax, + int pooled_height, int pooled_width, + float spatial_scale) { + roi_pool_forward_impl(input, rois, output, argmax, pooled_height, + pooled_width, spatial_scale); +} + +void roi_pool_backward(Tensor grad_output, Tensor rois, Tensor argmax, + Tensor grad_input, int pooled_height, int pooled_width, + float spatial_scale) { + roi_pool_backward_impl(grad_output, rois, argmax, grad_input, pooled_height, + pooled_width, spatial_scale); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_parrots.cpp new file mode 100644 index 000000000..0acde4a41 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_parrots.cpp @@ -0,0 +1,67 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "roi_pool_pytorch.h" +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void roi_pool_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + auto argmax = buildATensor(ctx, outs[1]); + roi_pool_forward_cuda(input, rois, output, argmax, pooled_height, + pooled_width, spatial_scale); +} + +void roi_pool_backward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pooled_height; + int pooled_width; + float spatial_scale; + SSAttrs(attr) + .get("pooled_height", pooled_height) + .get("pooled_width", pooled_width) + .get("spatial_scale", spatial_scale) + .done(); + + const auto& grad_output = buildATensor(ctx, ins[0]); + const auto& rois = buildATensor(ctx, ins[1]); + const auto& argmax = buildATensor(ctx, ins[2]); + auto grad_input = buildATensor(ctx, outs[0]); + roi_pool_backward_cuda(grad_output, rois, argmax, grad_input, pooled_height, + pooled_width, spatial_scale); +} + +PARROTS_EXTENSION_REGISTER(roi_pool_forward) + .attr("pooled_height") + .attr("pooled_width") + .attr("spatial_scale") + .input(2) + .output(2) + .apply(roi_pool_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(roi_pool_backward) + .attr("pooled_height") + .attr("pooled_width") + .attr("spatial_scale") + .input(3) + .output(1) + .apply(roi_pool_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_pytorch.h new file mode 100644 index 000000000..d67a1502f --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_pytorch.h @@ -0,0 +1,16 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef ROI_POOL_PYTORCH_H +#define ROI_POOL_PYTORCH_H +#include +using namespace at; + +#ifdef MMCV_WITH_CUDA +void roi_pool_forward_cuda(Tensor input, Tensor rois, Tensor output, + Tensor argmax, int pooled_height, int pooled_width, + float spatial_scale); + +void roi_pool_backward_cuda(Tensor grad_output, Tensor rois, Tensor argmax, + Tensor grad_input, int pooled_height, + int pooled_width, float spatial_scale); +#endif +#endif // ROI_POOL_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d.cpp new file mode 100644 index 000000000..6cf9cf094 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d.cpp @@ -0,0 +1,72 @@ +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void roiaware_pool3d_forward_impl(int boxes_num, int pts_num, int channels, + int max_pts_each_voxel, int out_x, int out_y, + int out_z, const Tensor rois, + const Tensor pts, const Tensor pts_feature, + Tensor argmax, Tensor pts_idx_of_voxels, + Tensor pooled_features, int pool_method) { + DISPATCH_DEVICE_IMPL(roiaware_pool3d_forward_impl, boxes_num, pts_num, + channels, max_pts_each_voxel, out_x, out_y, out_z, rois, + pts, pts_feature, argmax, pts_idx_of_voxels, + pooled_features, pool_method); +} + +void roiaware_pool3d_backward_impl(int boxes_num, int out_x, int out_y, + int out_z, int channels, + int max_pts_each_voxel, + const Tensor pts_idx_of_voxels, + const Tensor argmax, const Tensor grad_out, + Tensor grad_in, int pool_method) { + DISPATCH_DEVICE_IMPL(roiaware_pool3d_backward_impl, boxes_num, out_x, out_y, + out_z, channels, max_pts_each_voxel, pts_idx_of_voxels, + argmax, grad_out, grad_in, pool_method); +} + +void roiaware_pool3d_forward(Tensor rois, Tensor pts, Tensor pts_feature, + Tensor argmax, Tensor pts_idx_of_voxels, + Tensor pooled_features, int pool_method) { + // params rois: (N, 7) [x, y, z, x_size, y_size, z_size, ry] in LiDAR + // coordinate + // params pts: (npoints, 3) [x, y, z] in LiDAR coordinate + // params pts_feature: (npoints, C) + // params argmax: (N, out_x, out_y, out_z, C) + // params pts_idx_of_voxels: (N, out_x, out_y, out_z, max_pts_each_voxel) + // params pooled_features: (N, out_x, out_y, out_z, C) + // params pool_method: 0: max_pool 1: avg_pool + int boxes_num = rois.size(0); + int pts_num = pts.size(0); + int channels = pts_feature.size(1); + int max_pts_each_voxel = pts_idx_of_voxels.size(4); // index 0 is the counter + int out_x = pts_idx_of_voxels.size(1); + int out_y = pts_idx_of_voxels.size(2); + int out_z = pts_idx_of_voxels.size(3); + assert((out_x < 256) && (out_y < 256) && + (out_z < 256)); // we encode index with 8bit + + roiaware_pool3d_forward_impl(boxes_num, pts_num, channels, max_pts_each_voxel, + out_x, out_y, out_z, rois, pts, pts_feature, + argmax, pts_idx_of_voxels, pooled_features, + pool_method); +} + +void roiaware_pool3d_backward(Tensor pts_idx_of_voxels, Tensor argmax, + Tensor grad_out, Tensor grad_in, + int pool_method) { + // params pts_idx_of_voxels: (N, out_x, out_y, out_z, max_pts_each_voxel) + // params argmax: (N, out_x, out_y, out_z, C) + // params grad_out: (N, out_x, out_y, out_z, C) + // params grad_in: (npoints, C), return value + // params pool_method: 0: max_pool 1: avg_pool + int boxes_num = pts_idx_of_voxels.size(0); + int out_x = pts_idx_of_voxels.size(1); + int out_y = pts_idx_of_voxels.size(2); + int out_z = pts_idx_of_voxels.size(3); + int max_pts_each_voxel = pts_idx_of_voxels.size(4); // index 0 is the counter + int channels = grad_out.size(4); + + roiaware_pool3d_backward_impl(boxes_num, out_x, out_y, out_z, channels, + max_pts_each_voxel, pts_idx_of_voxels, argmax, + grad_out, grad_in, pool_method); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_parrots.cpp new file mode 100644 index 000000000..771d92004 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_parrots.cpp @@ -0,0 +1,58 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "roiaware_pool3d_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void roiaware_pool3d_forward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pool_method; + SSAttrs(attr).get("pool_method", pool_method).done(); + auto rois = buildATensor(ctx, ins[0]); + auto pts = buildATensor(ctx, ins[1]); + auto pts_feature = buildATensor(ctx, ins[2]); + + auto argmax = buildATensor(ctx, outs[0]); + auto pts_idx_of_voxels = buildATensor(ctx, outs[1]); + auto pooled_features = buildATensor(ctx, outs[2]); + + roiaware_pool3d_forward(rois, pts, pts_feature, argmax, pts_idx_of_voxels, + pooled_features, pool_method); +} + +void roiaware_pool3d_backward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int pool_method; + SSAttrs(attr).get("pool_method", pool_method).done(); + auto pts_idx_of_voxels = buildATensor(ctx, ins[0]); + auto argmax = buildATensor(ctx, ins[1]); + auto grad_out = buildATensor(ctx, ins[2]); + + auto grad_in = buildATensor(ctx, outs[0]); + + roiaware_pool3d_backward(pts_idx_of_voxels, argmax, grad_out, grad_in, + pool_method); +} + +PARROTS_EXTENSION_REGISTER(roiaware_pool3d_forward) + .attr("pool_method") + .input(3) + .output(3) + .apply(roiaware_pool3d_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(roiaware_pool3d_backward) + .attr("pool_method") + .input(3) + .output(1) + .apply(roiaware_pool3d_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_pytorch.h new file mode 100644 index 000000000..0b4b0402a --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_pytorch.h @@ -0,0 +1,14 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef ROIAWARE_POOL3D_PYTORCH_H +#define ROIAWARE_POOL3D_PYTORCH_H +#include +using namespace at; + +void roiaware_pool3d_forward(Tensor rois, Tensor pts, Tensor pts_feature, + Tensor argmax, Tensor pts_idx_of_voxels, + Tensor pooled_features, int pool_method); + +void roiaware_pool3d_backward(Tensor pts_idx_of_voxels, Tensor argmax, + Tensor grad_out, Tensor grad_in, int pool_method); + +#endif // ROIAWARE_POOL3D_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d.cpp new file mode 100644 index 000000000..a10080b7c --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d.cpp @@ -0,0 +1,39 @@ +/* +Modified from +https://github.com/open-mmlab/OpenPCDet/blob/master/pcdet/ops/roipoint_pool3d/src/roipoint_pool3d.cpp +Point cloud feature pooling +Written by Shaoshuai Shi +All Rights Reserved 2018. +*/ + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void roipoint_pool3d_forward_impl(int batch_size, int pts_num, int boxes_num, + int feature_in_len, int sampled_pts_num, + const Tensor xyz, const Tensor boxes3d, + const Tensor pts_feature, + Tensor pooled_features, + Tensor pooled_empty_flag) { + DISPATCH_DEVICE_IMPL(roipoint_pool3d_forward_impl, batch_size, pts_num, + boxes_num, feature_in_len, sampled_pts_num, xyz, boxes3d, + pts_feature, pooled_features, pooled_empty_flag); +} + +void roipoint_pool3d_forward(Tensor xyz, Tensor boxes3d, Tensor pts_feature, + Tensor pooled_features, Tensor pooled_empty_flag) { + // params xyz: (B, N, 3) + // params boxes3d: (B, M, 7) + // params pts_feature: (B, N, C) + // params pooled_features: (B, M, 512, 3+C) + // params pooled_empty_flag: (B, M) + int batch_size = xyz.size(0); + int pts_num = xyz.size(1); + int boxes_num = boxes3d.size(1); + int feature_in_len = pts_feature.size(2); + int sampled_pts_num = pooled_features.size(2); + + roipoint_pool3d_forward_impl(batch_size, pts_num, boxes_num, feature_in_len, + sampled_pts_num, xyz, boxes3d, pts_feature, + pooled_features, pooled_empty_flag); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_parrots.cpp new file mode 100644 index 000000000..17f549849 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_parrots.cpp @@ -0,0 +1,31 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "roipoint_pool3d_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void roipoint_pool3d_forward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + auto xyz = buildATensor(ctx, ins[0]); + auto boxes3d = buildATensor(ctx, ins[1]); + auto pts_feature = buildATensor(ctx, ins[2]); + + auto pooled_features = buildATensor(ctx, outs[0]); + auto pooled_empty_flag = buildATensor(ctx, outs[1]); + + roipoint_pool3d_forward(xyz, boxes3d, pts_feature, pooled_features, + pooled_empty_flag); +} + +PARROTS_EXTENSION_REGISTER(roipoint_pool3d_forward) + .input(3) + .output(2) + .apply(roipoint_pool3d_forward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_pytorch.h new file mode 100644 index 000000000..e5b61b0d9 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_pytorch.h @@ -0,0 +1,10 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef ROIPOINT_POOL3D_PYTORCH_H +#define ROIPOINT_POOL3D_PYTORCH_H +#include +using namespace at; + +void roipoint_pool3d_forward(Tensor xyz, Tensor boxes3d, Tensor pts_feature, + Tensor pooled_features, Tensor pooled_empty_flag); + +#endif // ROIPOINT_POOL3D_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align.cpp new file mode 100644 index 000000000..71fe0c9a0 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align.cpp @@ -0,0 +1,39 @@ +// Copyright (c) OpenMMLab. All rights reserved. +// Modified from +// https://github.com/SJTU-Thinklab-Det/r3det-on-mmdetection/blob/master/mmdet/ops/fr/src/feature_refine_cuda.cpp + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void rotated_feature_align_forward_impl(const Tensor features, + const Tensor best_bboxes, + const float spatial_scale, + const int points, Tensor output) { + DISPATCH_DEVICE_IMPL(rotated_feature_align_forward_impl, features, + best_bboxes, spatial_scale, points, output); +} + +void rotated_feature_align_backward_impl(const Tensor top_grad, + const Tensor best_bboxes, + const float spatial_scale, + const int points, Tensor bottom_grad) { + DISPATCH_DEVICE_IMPL(rotated_feature_align_backward_impl, top_grad, + best_bboxes, spatial_scale, points, bottom_grad); +} + +void rotated_feature_align_forward(const Tensor features, + const Tensor best_bboxes, Tensor output, + const float spatial_scale, + const int points) { + rotated_feature_align_forward_impl(features, best_bboxes, spatial_scale, + points, output); +} + +void rotated_feature_align_backward(const Tensor top_grad, + const Tensor best_bboxes, + Tensor bottom_grad, + const float spatial_scale, + const int points) { + rotated_feature_align_backward_impl(top_grad, best_bboxes, spatial_scale, + points, bottom_grad); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_parrots.cpp new file mode 100644 index 000000000..d4efaf1d3 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_parrots.cpp @@ -0,0 +1,99 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "rotated_feature_align_pytorch.h" +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void rotated_feature_align_forward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float spatial_scale; + int points; + SSAttrs(attr) + .get("spatial_scale", spatial_scale) + .get("points", points) + .done(); + + auto features = buildATensor(ctx, ins[0]); + auto best_bboxes = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + rotated_feature_align_forward(features, best_bboxes, output, spatial_scale, + points); +} + +void rotated_feature_align_backward_cuda_parrots( + CudaContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float spatial_scale; + int points; + SSAttrs(attr) + .get("spatial_scale", spatial_scale) + .get("points", points) + .done(); + + auto grad_output = buildATensor(ctx, ins[0]); + auto best_bboxes = buildATensor(ctx, ins[1]); + auto grad_input = buildATensor(ctx, outs[0]); + rotated_feature_align_backward(grad_output, best_bboxes, grad_input, + spatial_scale, points); +} +#endif + +void rotated_feature_align_forward_cpu_parrots( + HostContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float spatial_scale; + int points; + SSAttrs(attr) + .get("spatial_scale", spatial_scale) + .get("points", points) + .done(); + + auto features = buildATensor(ctx, ins[0]); + auto best_bboxes = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + rotated_feature_align_forward(features, best_bboxes, output, spatial_scale, + points); +} + +void rotated_feature_align_backward_cpu_parrots( + HostContext& ctx, const SSElement& attr, const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + float spatial_scale; + int points; + SSAttrs(attr) + .get("spatial_scale", spatial_scale) + .get("points", points) + .done(); + + auto grad_output = buildATensor(ctx, ins[0]); + auto best_bboxes = buildATensor(ctx, ins[1]); + auto grad_input = buildATensor(ctx, outs[0]); + rotated_feature_align_backward(grad_output, best_bboxes, grad_input, + spatial_scale, points); +} + +PARROTS_EXTENSION_REGISTER(rotated_feature_align_forward) + .attr("spatial_scale") + .attr("points") + .input(2) + .output(1) + .apply(rotated_feature_align_forward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(rotated_feature_align_forward_cuda_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(rotated_feature_align_backward) + .attr("spatial_scale") + .attr("points") + .input(2) + .output(1) + .apply(rotated_feature_align_backward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(rotated_feature_align_backward_cuda_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_pytorch.h new file mode 100644 index 000000000..9a695ee5e --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_pytorch.h @@ -0,0 +1,17 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef ROTATED_FEATURE_ALIGN_PYTORCH_H +#define ROTATED_FEATURE_ALIGN_PYTORCH_H +#include +using namespace at; + +void rotated_feature_align_forward(const Tensor features, + const Tensor best_bboxes, Tensor output, + const float spatial_scale, const int points); + +void rotated_feature_align_backward(const Tensor top_grad, + const Tensor best_bboxes, + Tensor bottom_grad, + const float spatial_scale, + const int points); + +#endif // ROTATED_FEATURE_ALIGN_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn.cpp new file mode 100644 index 000000000..fd5a51327 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn.cpp @@ -0,0 +1,69 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void sync_bn_forward_mean_impl(const Tensor input, Tensor mean) { + DISPATCH_DEVICE_IMPL(sync_bn_forward_mean_impl, input, mean); +} + +void sync_bn_forward_var_impl(const Tensor input, const Tensor mean, + Tensor var) { + DISPATCH_DEVICE_IMPL(sync_bn_forward_var_impl, input, mean, var); +} + +void sync_bn_forward_output_impl(const Tensor input, const Tensor mean, + const Tensor var, Tensor running_mean, + Tensor running_var, const Tensor weight, + const Tensor bias, Tensor norm, Tensor std, + Tensor output, float eps, float momentum, + int group_size) { + DISPATCH_DEVICE_IMPL(sync_bn_forward_output_impl, input, mean, var, + running_mean, running_var, weight, bias, norm, std, + output, eps, momentum, group_size); +} + +void sync_bn_backward_param_impl(const Tensor grad_output, const Tensor norm, + Tensor grad_weight, Tensor grad_bias) { + DISPATCH_DEVICE_IMPL(sync_bn_backward_param_impl, grad_output, norm, + grad_weight, grad_bias); +} + +void sync_bn_backward_data_impl(const Tensor grad_output, const Tensor weight, + const Tensor grad_weight, + const Tensor grad_bias, const Tensor norm, + const Tensor std, Tensor grad_input) { + DISPATCH_DEVICE_IMPL(sync_bn_backward_data_impl, grad_output, weight, + grad_weight, grad_bias, norm, std, grad_input); +} + +void sync_bn_forward_mean(const Tensor input, Tensor mean) { + sync_bn_forward_mean_impl(input, mean); +} + +void sync_bn_forward_var(const Tensor input, const Tensor mean, Tensor var) { + sync_bn_forward_var_impl(input, mean, var); +} + +void sync_bn_forward_output(const Tensor input, const Tensor mean, + const Tensor var, const Tensor weight, + const Tensor bias, Tensor running_mean, + Tensor running_var, Tensor norm, Tensor std, + Tensor output, float eps, float momentum, + int group_size) { + sync_bn_forward_output_impl(input, mean, var, running_mean, running_var, + weight, bias, norm, std, output, eps, momentum, + group_size); +} + +void sync_bn_backward_param(const Tensor grad_output, const Tensor norm, + Tensor grad_weight, Tensor grad_bias) { + sync_bn_backward_param_impl(grad_output, norm, grad_weight, grad_bias); +} + +void sync_bn_backward_data(const Tensor grad_output, const Tensor weight, + const Tensor grad_weight, const Tensor grad_bias, + const Tensor norm, const Tensor std, + Tensor grad_input) { + sync_bn_backward_data_impl(grad_output, weight, grad_weight, grad_bias, norm, + std, grad_input); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_parrots.cpp new file mode 100644 index 000000000..0b1855abd --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_parrots.cpp @@ -0,0 +1,111 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "sync_bn_pytorch.h" +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void sync_bn_forward_mean_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + const auto& input = buildATensor(ctx, ins[0]); + auto mean = buildATensor(ctx, outs[0]); + sync_bn_forward_mean_cuda(input, mean); +} + +void sync_bn_forward_var_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + const auto& input = buildATensor(ctx, ins[0]); + const auto& mean = buildATensor(ctx, ins[1]); + auto var = buildATensor(ctx, outs[0]); + sync_bn_forward_var_cuda(input, mean, var); +} + +void sync_bn_forward_output_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + size_t group_size; + float eps, momentum; + SSAttrs(attr) + .get("eps", eps) + .get("momentum", momentum) + .get("group_size", group_size) + .done(); + + const auto& input = buildATensor(ctx, ins[0]); + const auto& mean = buildATensor(ctx, ins[1]); + const auto& var = buildATensor(ctx, ins[2]); + const auto& weight = buildATensor(ctx, ins[3]); + const auto& bias = buildATensor(ctx, ins[4]); + auto running_mean = buildATensor(ctx, outs[0]); + auto running_var = buildATensor(ctx, outs[1]); + auto norm = buildATensor(ctx, outs[2]); + auto std = buildATensor(ctx, outs[3]); + auto output = buildATensor(ctx, outs[4]); + sync_bn_forward_output_cuda(input, mean, var, running_mean, running_var, + weight, bias, norm, std, output, eps, momentum, + group_size); +} + +void sync_bn_backward_param_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + const auto& grad_output = buildATensor(ctx, ins[0]); + const auto& norm = buildATensor(ctx, ins[1]); + auto grad_weight = buildATensor(ctx, outs[0]); + auto grad_bias = buildATensor(ctx, outs[1]); + sync_bn_backward_param_cuda(grad_output, norm, grad_weight, grad_bias); +} + +void sync_bn_backward_data_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + const auto& grad_output = buildATensor(ctx, ins[0]); + const auto& weight = buildATensor(ctx, ins[1]); + const auto& grad_weight = buildATensor(ctx, ins[2]); + const auto& grad_bias = buildATensor(ctx, ins[3]); + const auto& norm = buildATensor(ctx, ins[4]); + const auto& std = buildATensor(ctx, ins[5]); + auto grad_input = buildATensor(ctx, outs[0]); + sync_bn_backward_data_cuda(grad_output, weight, grad_weight, grad_bias, norm, + std, grad_input); +} + +PARROTS_EXTENSION_REGISTER(sync_bn_forward_mean) + .input(1) + .output(1) + .apply(sync_bn_forward_mean_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(sync_bn_forward_var) + .input(2) + .output(1) + .apply(sync_bn_forward_var_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(sync_bn_forward_output) + .attr("eps") + .attr("momentum") + .attr("group_size") + .input(5) + .output(5) + .apply(sync_bn_forward_output_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(sync_bn_backward_param) + .input(2) + .output(2) + .apply(sync_bn_backward_param_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(sync_bn_backward_data) + .input(6) + .output(1) + .apply(sync_bn_backward_data_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_pytorch.h new file mode 100644 index 000000000..6bd6a7fad --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_pytorch.h @@ -0,0 +1,26 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef SYNC_BN_PYTORCH_H +#define SYNC_BN_PYTORCH_H +#include +using namespace at; + +void sync_bn_forward_mean_cuda(const Tensor input, Tensor mean); + +void sync_bn_forward_var_cuda(const Tensor input, const Tensor mean, + Tensor var); + +void sync_bn_forward_output_cuda(const Tensor input, const Tensor mean, + const Tensor var, Tensor running_mean, + Tensor running_var, const Tensor weight, + const Tensor bias, Tensor norm, Tensor std, + Tensor output, float eps, float momentum, + int group_size); + +void sync_bn_backward_param_cuda(const Tensor grad_output, const Tensor norm, + Tensor grad_weight, Tensor grad_bias); + +void sync_bn_backward_data_cuda(const Tensor grad_output, const Tensor weight, + const Tensor grad_weight, + const Tensor grad_bias, const Tensor norm, + const Tensor std, Tensor grad_input); +#endif // SYNC_BN_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate.cpp new file mode 100644 index 000000000..1e0ec71bb --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate.cpp @@ -0,0 +1,33 @@ +// Modified from +// https://github.com/sshaoshuai/Pointnet2.PyTorch/tree/master/pointnet2/src/interpolate.cpp + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void three_interpolate_forward_impl(int b, int c, int m, int n, + const Tensor points, const Tensor idx, + const Tensor weight, Tensor out) { + DISPATCH_DEVICE_IMPL(three_interpolate_forward_impl, b, c, m, n, points, idx, + weight, out); +} + +void three_interpolate_backward_impl(int b, int c, int n, int m, + const Tensor grad_out, const Tensor idx, + const Tensor weight, Tensor grad_points) { + DISPATCH_DEVICE_IMPL(three_interpolate_backward_impl, b, c, n, m, grad_out, + idx, weight, grad_points); +} + +void three_interpolate_forward(Tensor points_tensor, Tensor idx_tensor, + Tensor weight_tensor, Tensor out_tensor, int b, + int c, int m, int n) { + three_interpolate_forward_impl(b, c, m, n, points_tensor, idx_tensor, + weight_tensor, out_tensor); +} + +void three_interpolate_backward(Tensor grad_out_tensor, Tensor idx_tensor, + Tensor weight_tensor, Tensor grad_points_tensor, + int b, int c, int n, int m) { + three_interpolate_backward_impl(b, c, n, m, grad_out_tensor, idx_tensor, + weight_tensor, grad_points_tensor); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_parrots.cpp new file mode 100644 index 000000000..a71a90fd1 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_parrots.cpp @@ -0,0 +1,74 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "three_interpolate_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void three_interpolate_forward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int b, c, m, n; + SSAttrs(attr) + .get("b", b) + .get("c", c) + .get("m", m) + .get("n", n) + .done(); + + auto points_tensor = buildATensor(ctx, ins[0]); + auto idx_tensor = buildATensor(ctx, ins[1]); + auto weight_tensor = buildATensor(ctx, ins[2]); + + auto out_tensor = buildATensor(ctx, outs[0]); + + three_interpolate_forward(points_tensor, idx_tensor, weight_tensor, + out_tensor, b, c, m, n); +} + +void three_interpolate_backward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int b, c, n, m; + SSAttrs(attr) + .get("b", b) + .get("c", c) + .get("n", n) + .get("m", m) + .done(); + + auto grad_out_tensor = buildATensor(ctx, ins[0]); + auto idx_tensor = buildATensor(ctx, ins[1]); + auto weight_tensor = buildATensor(ctx, ins[2]); + + auto grad_points_tensor = buildATensor(ctx, outs[0]); + + three_interpolate_backward(grad_out_tensor, idx_tensor, weight_tensor, + grad_points_tensor, b, c, n, m); +} + +PARROTS_EXTENSION_REGISTER(three_interpolate_forward) + .attr("b") + .attr("c") + .attr("m") + .attr("n") + .input(3) + .output(1) + .apply(three_interpolate_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(three_interpolate_backward) + .attr("b") + .attr("c") + .attr("n") + .attr("m") + .input(3) + .output(1) + .apply(three_interpolate_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_pytorch.h new file mode 100644 index 000000000..464c6d900 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_pytorch.h @@ -0,0 +1,14 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef THREE_INTERPOLATE_PYTORCH_H +#define THREE_INTERPOLATE_PYTORCH_H +#include +using namespace at; + +void three_interpolate_forward(Tensor points_tensor, Tensor idx_tensor, + Tensor weight_tensor, Tensor out_tensor, int b, + int c, int m, int n); + +void three_interpolate_backward(Tensor grad_out_tensor, Tensor idx_tensor, + Tensor weight_tensor, Tensor grad_points_tensor, + int b, int c, int n, int m); +#endif // THREE_INTERPOLATE_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn.cpp new file mode 100644 index 000000000..b629200c0 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn.cpp @@ -0,0 +1,18 @@ +// Modified from +// https://github.com/sshaoshuai/Pointnet2.PyTorch/tree/master/pointnet2/src/interpolate.cpp + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void three_nn_forward_impl(int b, int n, int m, const Tensor unknown, + const Tensor known, Tensor dist2, Tensor idx) { + DISPATCH_DEVICE_IMPL(three_nn_forward_impl, b, n, m, unknown, known, dist2, + idx); +} + +void three_nn_forward(Tensor unknown_tensor, Tensor known_tensor, + Tensor dist2_tensor, Tensor idx_tensor, int b, int n, + int m) { + three_nn_forward_impl(b, n, m, unknown_tensor, known_tensor, dist2_tensor, + idx_tensor); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_parrots.cpp new file mode 100644 index 000000000..c28c7d216 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_parrots.cpp @@ -0,0 +1,35 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "three_nn_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void three_nn_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int b, n, m; + SSAttrs(attr).get("b", b).get("n", n).get("m", m).done(); + + auto unknown_tensor = buildATensor(ctx, ins[0]); + auto known_tensor = buildATensor(ctx, ins[1]); + + auto dist2_tensor = buildATensor(ctx, outs[0]); + auto idx_tensor = buildATensor(ctx, outs[1]); + + three_nn_forward(unknown_tensor, known_tensor, dist2_tensor, idx_tensor, b, n, + m); +} + +PARROTS_EXTENSION_REGISTER(three_nn_forward) + .attr("b") + .attr("n") + .attr("m") + .input(2) + .output(2) + .apply(three_nn_forward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_pytorch.h new file mode 100644 index 000000000..6574fba09 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_pytorch.h @@ -0,0 +1,10 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef THREE_NN_PYTORCH_H +#define THREE_NN_PYTORCH_H +#include +using namespace at; + +void three_nn_forward(Tensor unknown_tensor, Tensor known_tensor, + Tensor dist2_tensor, Tensor idx_tensor, int b, int n, + int m); +#endif // THREE_NN_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift.cpp new file mode 100644 index 000000000..b03f58754 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift.cpp @@ -0,0 +1,20 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void tin_shift_forward_impl(Tensor input, Tensor shift, Tensor output) { + DISPATCH_DEVICE_IMPL(tin_shift_forward_impl, input, shift, output); +} + +void tin_shift_backward_impl(Tensor grad_output, Tensor shift, + Tensor grad_input) { + DISPATCH_DEVICE_IMPL(tin_shift_backward_impl, grad_output, shift, grad_input); +} + +void tin_shift_forward(Tensor input, Tensor shift, Tensor output) { + tin_shift_forward_impl(input, shift, output); +} + +void tin_shift_backward(Tensor grad_output, Tensor shift, Tensor grad_input) { + tin_shift_backward_impl(grad_output, shift, grad_input); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_parrots.cpp new file mode 100644 index 000000000..b0920928e --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_parrots.cpp @@ -0,0 +1,39 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "tin_shift_pytorch.h" +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void tin_shift_forward_cuda_parrots(CudaContext &ctx, const SSElement &attr, + const OperatorBase::in_list_t &ins, + OperatorBase::out_list_t &outs) { + const auto &input = buildATensor(ctx, ins[0]); + const auto &shift = buildATensor(ctx, ins[1]); + auto output = buildATensor(ctx, outs[0]); + tin_shift_forward_cuda(input, shift, output); +} + +void tin_shift_backward_cuda_parrots(CudaContext &ctx, const SSElement &attr, + const OperatorBase::in_list_t &ins, + OperatorBase::out_list_t &outs) { + const auto &grad_output = buildATensor(ctx, ins[0]); + const auto &shift = buildATensor(ctx, ins[1]); + auto grad_input = buildATensor(ctx, outs[0]); + tin_shift_backward_cuda(grad_output, shift, grad_input); +} + +PARROTS_EXTENSION_REGISTER(tin_shift_forward) + .input(2) + .output(1) + .apply(tin_shift_forward_cuda_parrots) + .done(); + +PARROTS_EXTENSION_REGISTER(tin_shift_backward) + .input(2) + .output(1) + .apply(tin_shift_backward_cuda_parrots) + .done(); +#endif diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_pytorch.h new file mode 100644 index 000000000..fe7238376 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_pytorch.h @@ -0,0 +1,11 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef TIN_SHIFT_PYTORCH_H +#define TIN_SHIFT_PYTORCH_H +#include +using namespace at; + +void tin_shift_forward_cuda(Tensor input, Tensor shift, Tensor output); + +void tin_shift_backward_cuda(Tensor grad_output, Tensor shift, + Tensor grad_input); +#endif // TIN_SHIFT_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d.cpp new file mode 100644 index 000000000..dd325bd78 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d.cpp @@ -0,0 +1,118 @@ +// Modified from +// https://github.com/rosinality/stylegan2-pytorch/blob/master/op/upfirdn2d.cpp + +/* +Copyright (c) 2021, NVIDIA Corporation. All rights reserved. + +NVIDIA Source Code License for StyleGAN2 with Adaptive Discriminator +Augmentation (ADA) +======================================================================= + +1. Definitions + +"Licensor" means any person or entity that distributes its Work. + +"Software" means the original work of authorship made available under +this License. + +"Work" means the Software and any additions to or derivative works of +the Software that are made available under this License. + +The terms "reproduce," "reproduction," "derivative works," and +"distribution" have the meaning as provided under U.S. copyright law; +provided, however, that for the purposes of this License, derivative +works shall not include works that remain separable from, or merely +link (or bind by name) to the interfaces of, the Work. + +Works, including the Software, are "made available" under this License +by including in or with the Work either (a) a copyright notice +referencing the applicability of this License to the Work, or (b) a +copy of this License. + +2. License Grants + + 2.1 Copyright Grant. Subject to the terms and conditions of this + License, each Licensor grants to you a perpetual, worldwide, + non-exclusive, royalty-free, copyright license to reproduce, + prepare derivative works of, publicly display, publicly perform, + sublicense and distribute its Work and any resulting derivative + works in any form. + +3. Limitations + + 3.1 Redistribution. You may reproduce or distribute the Work only + if (a) you do so under this License, (b) you include a complete + copy of this License with your distribution, and (c) you retain + without modification any copyright, patent, trademark, or + attribution notices that are present in the Work. + + 3.2 Derivative Works. You may specify that additional or different + terms apply to the use, reproduction, and distribution of your + derivative works of the Work ("Your Terms") only if (a) Your Terms + provide that the use limitation in Section 3.3 applies to your + derivative works, and (b) you identify the specific derivative + works that are subject to Your Terms. Notwithstanding Your Terms, + this License (including the redistribution requirements in Section + 3.1) will continue to apply to the Work itself. + + 3.3 Use Limitation. The Work and any derivative works thereof only + may be used or intended for use non-commercially. Notwithstanding + the foregoing, NVIDIA and its affiliates may use the Work and any + derivative works commercially. As used herein, "non-commercially" + means for research or evaluation purposes only. + + 3.4 Patent Claims. If you bring or threaten to bring a patent claim + against any Licensor (including any claim, cross-claim or + counterclaim in a lawsuit) to enforce any patents that you allege + are infringed by any Work, then your rights under this License from + such Licensor (including the grant in Section 2.1) will terminate + immediately. + + 3.5 Trademarks. This License does not grant any rights to use any + Licensor’s or its affiliates’ names, logos, or trademarks, except + as necessary to reproduce the notices described in this License. + + 3.6 Termination. If you violate any term of this License, then your + rights under this License (including the grant in Section 2.1) will + terminate immediately. + +4. Disclaimer of Warranty. + +THE WORK IS PROVIDED "AS IS" WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WARRANTIES OR CONDITIONS OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR +NON-INFRINGEMENT. YOU BEAR THE RISK OF UNDERTAKING ANY ACTIVITIES UNDER +THIS LICENSE. + +5. Limitation of Liability. + +EXCEPT AS PROHIBITED BY APPLICABLE LAW, IN NO EVENT AND UNDER NO LEGAL +THEORY, WHETHER IN TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE +SHALL ANY LICENSOR BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY DIRECT, +INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF +OR RELATED TO THIS LICENSE, THE USE OR INABILITY TO USE THE WORK +(INCLUDING BUT NOT LIMITED TO LOSS OF GOODWILL, BUSINESS INTERRUPTION, +LOST PROFITS OR DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY OTHER +COMMERCIAL DAMAGES OR LOSSES), EVEN IF THE LICENSOR HAS BEEN ADVISED OF +THE POSSIBILITY OF SUCH DAMAGES. + +======================================================================= +*/ + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +torch::Tensor upfirdn2d_op_impl(const torch::Tensor& input, + const torch::Tensor& kernel, int up_x, int up_y, + int down_x, int down_y, int pad_x0, int pad_x1, + int pad_y0, int pad_y1) { + return DISPATCH_DEVICE_IMPL(upfirdn2d_op_impl, input, kernel, up_x, up_y, + down_x, down_y, pad_x0, pad_x1, pad_y0, pad_y1); +} + +torch::Tensor upfirdn2d(const torch::Tensor& input, const torch::Tensor& kernel, + int up_x, int up_y, int down_x, int down_y, int pad_x0, + int pad_x1, int pad_y0, int pad_y1) { + return upfirdn2d_op_impl(input, kernel, up_x, up_y, down_x, down_y, pad_x0, + pad_x1, pad_y0, pad_y1); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d_parrots.cpp new file mode 100644 index 000000000..f0c50db5c --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d_parrots.cpp @@ -0,0 +1,47 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include + +#include +#include +#include +using namespace at; +using namespace parrots; + +torch::Tensor upfirdn2d(const Tensor &input, const Tensor &kernel, int up_x, + int up_y, int down_x, int down_y, int pad_x0, + int pad_x1, int pad_y0, int pad_y1); + +void upfirdn2d_parrots(CudaContext &ctx, const SSElement &attr, + const OperatorBase::in_list_t &ins, + OperatorBase::out_list_t &outs) { + int up_x, up_y, down_x, down_y, pad_x0, pad_x1, pad_y0, pad_y1; + const auto &input = buildATensor(ctx, ins[0]); + const auto &kernel = buildATensor(ctx, ins[1]); + SSAttrs(attr) + .get("up_x", up_x) + .get("up_y", up_y) + .get("down_x", down_x) + .get("down_y", down_y) + .get("pad_x0", pad_x0) + .get("pad_x1", pad_x1) + .get("pad_y0", pad_y0) + .get("pad_y1", pad_y1) + .done(); + auto out = upfirdn2d(input, kernel, up_x, up_y, down_x, down_y, pad_x0, + pad_x1, pad_y0, pad_y1); + updateDArray(ctx, out, outs[0]); +} + +PARROTS_EXTENSION_REGISTER(upfirdn2d) + .attr("up_x") + .attr("up_y") + .attr("down_x") + .attr("down_y") + .attr("pad_x0") + .attr("pad_x1") + .attr("pad_y0") + .attr("pad_y1") + .input(2) + .output(1) + .apply(upfirdn2d_parrots) + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization.cpp new file mode 100644 index 000000000..7946be617 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization.cpp @@ -0,0 +1,74 @@ +// Copyright (c) OpenMMLab. All rights reserved. +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +int hard_voxelize_forward_impl(const at::Tensor &points, at::Tensor &voxels, + at::Tensor &coors, + at::Tensor &num_points_per_voxel, + const std::vector voxel_size, + const std::vector coors_range, + const int max_points, const int max_voxels, + const int NDim = 3) { + return DISPATCH_DEVICE_IMPL(hard_voxelize_forward_impl, points, voxels, coors, + num_points_per_voxel, voxel_size, coors_range, + max_points, max_voxels, NDim); +} + +int nondeterministic_hard_voxelize_forward_impl( + const at::Tensor &points, at::Tensor &voxels, at::Tensor &coors, + at::Tensor &num_points_per_voxel, const std::vector voxel_size, + const std::vector coors_range, const int max_points, + const int max_voxels, const int NDim = 3) { + return DISPATCH_DEVICE_IMPL(nondeterministic_hard_voxelize_forward_impl, + points, voxels, coors, num_points_per_voxel, + voxel_size, coors_range, max_points, max_voxels, + NDim); +} + +void dynamic_voxelize_forward_impl(const at::Tensor &points, at::Tensor &coors, + const std::vector voxel_size, + const std::vector coors_range, + const int NDim = 3) { + DISPATCH_DEVICE_IMPL(dynamic_voxelize_forward_impl, points, coors, voxel_size, + coors_range, NDim); +} + +void hard_voxelize_forward(const at::Tensor &points, + const at::Tensor &voxel_size, + const at::Tensor &coors_range, at::Tensor &voxels, + at::Tensor &coors, at::Tensor &num_points_per_voxel, + at::Tensor &voxel_num, const int max_points, + const int max_voxels, const int NDim = 3, + const bool deterministic = true) { + int64_t *voxel_num_data = voxel_num.data_ptr(); + std::vector voxel_size_v( + voxel_size.data_ptr(), + voxel_size.data_ptr() + voxel_size.numel()); + std::vector coors_range_v( + coors_range.data_ptr(), + coors_range.data_ptr() + coors_range.numel()); + + if (deterministic) { + *voxel_num_data = hard_voxelize_forward_impl( + points, voxels, coors, num_points_per_voxel, voxel_size_v, + coors_range_v, max_points, max_voxels, NDim); + } else { + *voxel_num_data = nondeterministic_hard_voxelize_forward_impl( + points, voxels, coors, num_points_per_voxel, voxel_size_v, + coors_range_v, max_points, max_voxels, NDim); + } +} + +void dynamic_voxelize_forward(const at::Tensor &points, + const at::Tensor &voxel_size, + const at::Tensor &coors_range, at::Tensor &coors, + const int NDim = 3) { + std::vector voxel_size_v( + voxel_size.data_ptr(), + voxel_size.data_ptr() + voxel_size.numel()); + std::vector coors_range_v( + coors_range.data_ptr(), + coors_range.data_ptr() + coors_range.numel()); + dynamic_voxelize_forward_impl(points, coors, voxel_size_v, coors_range_v, + NDim); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_parrots.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_parrots.cpp new file mode 100644 index 000000000..90e2a4445 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_parrots.cpp @@ -0,0 +1,113 @@ +// Copyright (c) OpenMMLab. All rights reserved +#include +#include +#include + +#include "voxelization_pytorch.h" + +using namespace parrots; + +#ifdef MMCV_WITH_CUDA +void hard_voxelize_forward_cuda_parrots(CudaContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int max_points, max_voxels, NDim; + bool deterministic; + SSAttrs(attr) + .get("max_points", max_points) + .get("max_voxels", max_voxels) + .get("NDim", NDim) + .get("deterministic", deterministic) + .done(); + const auto& points = buildATensor(ctx, ins[0]); + const auto& voxel_size = buildATensor(ctx, ins[1]); + const auto& coors_range = buildATensor(ctx, ins[2]); + + auto voxels = buildATensor(ctx, outs[0]); + auto coors = buildATensor(ctx, outs[1]); + auto num_points_per_voxel = buildATensor(ctx, outs[2]); + auto voxel_num = buildATensor(ctx, outs[3]); + + hard_voxelize_forward(points, voxel_size, coors_range, voxels, coors, + num_points_per_voxel, voxel_num, max_points, max_voxels, + NDim, deterministic); +} + +void dynamic_voxelize_forward_cuda_parrots(CudaContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int NDim; + SSAttrs(attr).get("NDim", NDim).done(); + const auto& points = buildATensor(ctx, ins[0]); + const auto& voxel_size = buildATensor(ctx, ins[1]); + const auto& coors_range = buildATensor(ctx, ins[2]); + + auto coors = buildATensor(ctx, outs[0]); + + dynamic_voxelize_forward(points, voxel_size, coors_range, coors, NDim); +} +#endif + +void hard_voxelize_forward_cpu_parrots(HostContext& ctx, const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int max_points, max_voxels, NDim; + bool deterministic; + SSAttrs(attr) + .get("max_points", max_points) + .get("max_voxels", max_voxels) + .get("NDim", NDim) + .get("deterministic", deterministic) + .done(); + const auto& points = buildATensor(ctx, ins[0]); + const auto& voxel_size = buildATensor(ctx, ins[1]); + const auto& coors_range = buildATensor(ctx, ins[2]); + + auto voxels = buildATensor(ctx, outs[0]); + auto coors = buildATensor(ctx, outs[1]); + auto num_points_per_voxel = buildATensor(ctx, outs[2]); + auto voxel_num = buildATensor(ctx, outs[3]); + + hard_voxelize_forward(points, voxel_size, coors_range, voxels, coors, + num_points_per_voxel, voxel_num, max_points, max_voxels, + NDim, deterministic); +} + +void dynamic_voxelize_forward_cpu_parrots(HostContext& ctx, + const SSElement& attr, + const OperatorBase::in_list_t& ins, + OperatorBase::out_list_t& outs) { + int NDim; + SSAttrs(attr).get("NDim", NDim).done(); + const auto& points = buildATensor(ctx, ins[0]); + const auto& voxel_size = buildATensor(ctx, ins[1]); + const auto& coors_range = buildATensor(ctx, ins[2]); + + auto coors = buildATensor(ctx, outs[0]); + + dynamic_voxelize_forward(points, voxel_size, coors_range, coors, NDim); +} + +PARROTS_EXTENSION_REGISTER(hard_voxelize_forward) + .attr("max_points") + .attr("max_voxels") + .attr("NDim") + .attr("deterministic") + .input(3) + .output(4) + .apply(hard_voxelize_forward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(hard_voxelize_forward_cuda_parrots) +#endif + .done(); + +PARROTS_EXTENSION_REGISTER(dynamic_voxelize_forward) + .attr("NDim") + .input(3) + .output(1) + .apply(dynamic_voxelize_forward_cpu_parrots) +#ifdef MMCV_WITH_CUDA + .apply(dynamic_voxelize_forward_cuda_parrots) +#endif + .done(); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_pytorch.h b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_pytorch.h new file mode 100644 index 000000000..0019d5191 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_pytorch.h @@ -0,0 +1,20 @@ +// Copyright (c) OpenMMLab. All rights reserved +#ifndef VOXELIZATION_PYTORCH_H +#define VOXELIZATION_PYTORCH_H +#include +using namespace at; + +void hard_voxelize_forward(const at::Tensor &points, + const at::Tensor &voxel_size, + const at::Tensor &coors_range, at::Tensor &voxels, + at::Tensor &coors, at::Tensor &num_points_per_voxel, + at::Tensor &voxel_num, const int max_points, + const int max_voxels, const int NDim = 3, + const bool deterministic = true); + +void dynamic_voxelize_forward(const at::Tensor &points, + const at::Tensor &voxel_size, + const at::Tensor &coors_range, at::Tensor &coors, + const int NDim = 3); + +#endif // VOXELIZATION_PYTORCH_H diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/contour_expand.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/contour_expand.cpp old mode 100644 new mode 100755 diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp index 69a46160c..717158149 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp @@ -1409,19 +1409,18 @@ REGISTER_DEVICE_IMPL(three_interpolate_forward_impl, CUDA, REGISTER_DEVICE_IMPL(three_interpolate_backward_impl, CUDA, three_interpolate_backward_cuda); -// void ThreeNNForwardCUDAKernelLauncher(int b, int n, int m, const Tensor unknown, -// const Tensor known, Tensor dist2, -// Tensor idx); +void ThreeNNForwardCUDAKernelLauncher(int b, int n, int m, const Tensor unknown, + const Tensor known, Tensor dist2, + Tensor idx); -// void three_nn_forward_cuda(int b, int n, int m, const Tensor unknown, -// const Tensor known, Tensor dist2, Tensor idx) { -// ThreeNNForwardCUDAKernelLauncher(b, n, m, unknown, known, dist2, idx); -// }; - -// void three_nn_forward_impl(int b, int n, int m, const Tensor unknown, -// const Tensor known, Tensor dist2, Tensor idx); -// REGISTER_DEVICE_IMPL(three_nn_forward_impl, CUDA, three_nn_forward_cuda); +void three_nn_forward_cuda(int b, int n, int m, const Tensor unknown, + const Tensor known, Tensor dist2, Tensor idx) { + ThreeNNForwardCUDAKernelLauncher(b, n, m, unknown, known, dist2, idx); +}; +void three_nn_forward_impl(int b, int n, int m, const Tensor unknown, + const Tensor known, Tensor dist2, Tensor idx); +REGISTER_DEVICE_IMPL(three_nn_forward_impl, CUDA, three_nn_forward_cuda); void TINShiftForwardCUDAKernelLauncher(Tensor input, Tensor shift, Tensor output); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.cu b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.cu index 6ec314911..6b1392733 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.cu +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.cu @@ -8,8 +8,11 @@ #include "pytorch_cuda_helper.hpp" inline int opt_n_threads(int work_size) { +#if defined(__ILUVATAR__) + const int pow_2 = std::log(static_cast(work_size)) / std::log(2.0); +#else const int pow_2 = std::log(static_cast(work_size)) / std::log(2.0); - +#endif return std::max(std::min(1 << pow_2, 1024), 1); } diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/three_nn_cuda.cu b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/three_nn_cuda.cu new file mode 100644 index 000000000..91c68829b --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/three_nn_cuda.cu @@ -0,0 +1,35 @@ +// Modified from +// https://github.com/sshaoshuai/Pointnet2.PyTorch/tree/master/pointnet2/src/interpolate_gpu.cu + +#include +#include +#include + +#include "pytorch_cuda_helper.hpp" +#include "three_nn_cuda_kernel.cuh" + +void ThreeNNForwardCUDAKernelLauncher(int b, int n, int m, const Tensor unknown, + const Tensor known, Tensor dist2, + Tensor idx) { + // unknown: (B, N, 3) + // known: (B, M, 3) + // output: + // dist2: (B, N, 3) + // idx: (B, N, 3) + + at::cuda::CUDAGuard device_guard(unknown.device()); + cudaStream_t stream = at::cuda::getCurrentCUDAStream(); + + // blockIdx.x(col), blockIdx.y(row) + dim3 blocks(GET_BLOCKS(n, THREADS_PER_BLOCK), b); + dim3 threads(THREADS_PER_BLOCK); + + AT_DISPATCH_FLOATING_TYPES_AND_HALF( + unknown.scalar_type(), "three_nn_forward_cuda_kernel", [&] { + three_nn_forward_cuda_kernel<<>>( + b, n, m, unknown.data_ptr(), known.data_ptr(), + dist2.data_ptr(), idx.data_ptr()); + }); + + AT_CUDA_CHECK(cudaGetLastError()); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mps/bbox_overlaps_mps.mm b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mps/bbox_overlaps_mps.mm new file mode 100644 index 000000000..cad6a41a0 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mps/bbox_overlaps_mps.mm @@ -0,0 +1,99 @@ +// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +#include "pytorch_device_registry.hpp" + +#include "MPSLibrary.h" +#include "MPSStream.h" +#include "MPSUtils.h" + +using at::Tensor; + +const static std::string kSourceCode = R"( +#include +#include +using namespace metal; + +kernel void bbox_overlap_mps_kernel(constant const float4* bboxes1, + constant const float4* bboxes2, + device float* ious, + constant int& num_bbox1, + constant int& num_bbox2, + constant int& mode, + constant bool& aligned, + constant int& offset, + uint index [[thread_position_in_grid]]) +{ + int base1 = index; + int base2 = index; + if(!aligned){ + base1 = index / num_bbox2; + base2 = index % num_bbox2; + } + + const float f_offset = float(offset); + + const float4 b1 = bboxes1[base1]; + const float b1_area = (b1[2]-b1[0]+f_offset)*(b1[3]-b1[1]+f_offset); + + const float4 b2 = bboxes2[base2]; + const float b2_area = (b2[2]-b2[0]+f_offset)*(b2[3]-b2[1]+f_offset); + + const float2 left_top = fmax(b1.xy, b2.xy); + const float2 right_bottom = fmin(b1.zw, b2.zw); + const float2 wh = fmax(right_bottom - left_top + f_offset, 0.0f); + const float interS = wh.x * wh.y; + + const float baseS = + fmax(mode == 0 ? b1_area + b2_area - interS : b1_area, f_offset); + ious[index] = interS / baseS; +} +)"; + +void BBoxOverlapsMPSKernelLauncher(const Tensor bboxes1, const Tensor bboxes2, Tensor ious, + const int mode, const bool aligned, const int offset) { + // get stream + auto stream = at::mps::getCurrentMPSStream(); + auto library_manager = MPSLibraryManager::getInstance(); + MPSLibrary* library; + const static std::string kLibraryName = "bbox_overlap"; + if (library_manager->hasLibrary(kLibraryName)) + library = library_manager->getLibrary(kLibraryName); + else + library = library_manager->createLibraryFromSouce(kLibraryName, kSourceCode); + auto func_pso = library->getComputePipelineState("bbox_overlap_mps_kernel"); + + // create command buffer and encoder + MTLCommandBuffer_t command_buffer = stream->commandBuffer(); + MTLComputeCommandEncoder_t compute_encoder = [command_buffer computeCommandEncoder]; + + // set pso and buffer + int output_size = ious.numel(); + int num_bbox1 = bboxes1.size(0); + int num_bbox2 = bboxes2.size(0); + int num_elements = output_size; + setMTLArgs(compute_encoder, func_pso, bboxes1, bboxes2, ious, num_bbox1, num_bbox2, mode, aligned, + offset); + + // set grid size + MTLSize grid_size = MTLSizeMake(num_elements, 1, 1); + NSUInteger thread_group_size_x = func_pso.maxTotalThreadsPerThreadgroup; + if (thread_group_size_x > num_elements) { + thread_group_size_x = num_elements; + } + MTLSize thread_group_size = MTLSizeMake(thread_group_size_x, 1, 1); + + // encoding + [compute_encoder dispatchThreads:grid_size threadsPerThreadgroup:thread_group_size]; + [compute_encoder endEncoding]; + + // commit, not sure if flush is required + stream->commit(false); +} + +void bbox_overlaps_mps(const Tensor bboxes1, const Tensor bboxes2, Tensor ious, const int mode, + const bool aligned, const int offset) { + BBoxOverlapsMPSKernelLauncher(bboxes1, bboxes2, ious, mode, aligned, offset); +} + +void bbox_overlaps_impl(const Tensor bboxes1, const Tensor bboxes2, Tensor ious, const int mode, + const bool aligned, const int offset); +REGISTER_DEVICE_IMPL(bbox_overlaps_impl, MPS, bbox_overlaps_mps); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/deform_roi_pool.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/deform_roi_pool.cpp new file mode 100644 index 000000000..0e9f2ee7a --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/deform_roi_pool.cpp @@ -0,0 +1,63 @@ +#include "pytorch_npu_helper.hpp" + +using namespace NPU_NAME_SPACE; +using namespace std; + +void deform_roi_pool_forward_impl(Tensor input, Tensor rois, Tensor offset, + Tensor output, int pooled_height, + int pooled_width, float spatial_scale, + int sampling_ratio, float gamma); + +void deform_roi_pool_backward_impl(Tensor grad_output, Tensor input, + Tensor rois, Tensor offset, + Tensor grad_input, Tensor grad_offset, + int pooled_height, int pooled_width, + float spatial_scale, int sampling_ratio, + float gamma); + +void deform_roi_pool_forward_npu(Tensor input, Tensor rois, Tensor offset, + Tensor output, int pooled_height, + int pooled_width, float spatial_scale, + int sampling_ratio, float gamma) { + c10::SmallVector output_sizes = {pooled_height, pooled_width}; + at::IntArrayRef output_size = at::IntArrayRef(output_sizes); + int64_t sampling_ratio_ = (int64_t)sampling_ratio; + OpCommand cmd; + cmd.Name("DeformableRoiPool") + .Input(input) + .Input(rois) + .Input(offset) + .Output(output) + .Attr("spatial_scale", spatial_scale) + .Attr("output_size", output_size) + .Attr("sampling_ratio", sampling_ratio_) + .Attr("gamma", gamma) + .Run(); +} + +void deform_roi_pool_backward_npu(Tensor grad_output, Tensor input, Tensor rois, + Tensor offset, Tensor grad_input, + Tensor grad_offset, int pooled_height, + int pooled_width, float spatial_scale, + int sampling_ratio, float gamma) { + c10::SmallVector output_sizes = {pooled_height, pooled_width}; + at::IntArrayRef output_size = at::IntArrayRef(output_sizes); + int64_t sampling_ratio_ = (int64_t)sampling_ratio; + OpCommand cmd; + cmd.Name("DeformableRoiPoolGrad") + .Input(grad_input) + .Input(input) + .Input(rois) + .Input(offset) + .Output(grad_output) + .Output(grad_offset) + .Attr("output_size", output_size) + .Attr("spatial_scale", spatial_scale) + .Attr("sample_ratio", sampling_ratio_) + .Attr("gamma", gamma) + .Run(); +} + +REGISTER_NPU_IMPL(deform_roi_pool_forward_impl, deform_roi_pool_forward_npu); + +REGISTER_NPU_IMPL(deform_roi_pool_backward_impl, deform_roi_pool_backward_npu); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/focal_loss_npu.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/focal_loss_npu.cpp new file mode 100644 index 000000000..c949bf953 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/focal_loss_npu.cpp @@ -0,0 +1,162 @@ +#include "pytorch_npu_helper.hpp" + +using namespace NPU_NAME_SPACE; +using namespace std; + +void sigmoid_focal_loss_forward_npu(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha) { + int64_t n_class = input.size(1); + at::Tensor target_y = at::ones_like(input); + if (n_class == 1) { + target_y = at::reshape(target, input.sizes()); + target_y = at::mul(target_y, -1.0); + target_y = at::add(target_y, 1.0); + } else { + target_y = at_npu::native::NPUNativeFunctions::one_hot(target, n_class); + } + target_y = + at_npu::native::NPUNativeFunctions::npu_dtype_cast(target_y, at::kInt); + int64_t weight_size = weight.size(0); + at::Tensor weight_y = at::ones_like(input); + if (weight_size > 0) { + weight_y = at_npu::native::NPUNativeFunctions::npu_broadcast(weight, + input.sizes()); + } + OpCommand cmd; + string reduction = "none"; + cmd.Name("SigmoidFocalLoss") + .Input(input) + .Input(target_y) + .Input(weight_y) + .Output(output) + .Attr("gamma", gamma) + .Attr("alpha", alpha) + .Attr("reduction", reduction) + .Run(); +} + +void sigmoid_focal_loss_forward_impl(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha); + +void sigmoid_focal_loss_backward_npu(Tensor input, Tensor target, Tensor weight, + Tensor grad_input, float gamma, + float alpha) { + int64_t n_class = input.size(1); + at::Tensor target_y = at::ones_like(input); + if (n_class == 1) { + target_y = at::reshape(target, input.sizes()); + } else { + target_y = at_npu::native::NPUNativeFunctions::one_hot(target, n_class); + target_y = at::mul(target_y, -1.0); + target_y = at::add(target_y, 1.0); + } + target_y = + at_npu::native::NPUNativeFunctions::npu_dtype_cast(target_y, at::kInt); + at::Tensor grad_up = at::ones_like(input); + int64_t weight_size = weight.size(0); + at::Tensor weight_y = at::ones_like(input); + if (weight_size > 0) { + weight_y = at_npu::native::NPUNativeFunctions::npu_broadcast(weight, + input.sizes()); + } + OpCommand cmd; + string reduction = "none"; + cmd.Name("SigmoidFocalLossGrad") + .Input(input) + .Input(target_y) + .Input(grad_up) + .Input(weight_y) + .Output(grad_input) + .Attr("gamma", gamma) + .Attr("alpha", alpha) + .Attr("reduction", reduction) + .Run(); +} + +void sigmoid_focal_loss_backward_impl(Tensor input, Tensor target, + Tensor weight, Tensor grad_input, + float gamma, float alpha); + +void softmax_focal_loss_forward_npu(Tensor input, Tensor target, Tensor weight, + Tensor output, float gamma, float alpha) { + int64_t n_class = input.size(1); + at::Tensor target_y = + at_npu::native::NPUNativeFunctions::one_hot(target, n_class); + target_y = + at_npu::native::NPUNativeFunctions::npu_dtype_cast(target_y, at::kInt); + int64_t weight_size = weight.size(0); + at::Tensor weight_y = at::ones_like(input); + if (weight_size > 0) { + weight_y = at_npu::native::NPUNativeFunctions::npu_broadcast(weight, + input.sizes()); + } + at::Tensor op_output = at::ones_like(input); + OpCommand cmd; + string reduction = "none"; + cmd.Name("SoftmaxFocalLoss") + .Input(input) + .Input(target_y) + .Input(weight_y) + .Output(op_output) + .Attr("gamma", gamma) + .Attr("alpha", alpha) + .Attr("reduction", reduction) + .Run(); + int64_t n_batch = input.size(0); + c10::SmallVector offsets = {0, 0}; + c10::SmallVector sizes = {n_batch, 1}; + at::IntArrayRef offset = at::IntArrayRef(offsets); + at::IntArrayRef size = at::IntArrayRef(sizes); + at_npu::native::NPUNativeFunctions::npu_slice_out(op_output, offset, size, + output); +} + +void softmax_focal_loss_forward_impl(Tensor input, Tensor target, Tensor weight, + Tensor grad_input, float gamma, + float alpha); + +void softmax_focal_loss_backward_npu(Tensor input, Tensor target, Tensor weight, + Tensor buff, Tensor grad_input, + float gamma, float alpha) { + int64_t n_class = input.size(1); + at::Tensor target_y = + at_npu::native::NPUNativeFunctions::one_hot(target, n_class); + target_y = + at_npu::native::NPUNativeFunctions::npu_dtype_cast(target_y, at::kInt); + at::Tensor grad_up = at::ones_like(input); + int64_t weight_size = weight.size(0); + at::Tensor weight_y = at::ones_like(input); + if (weight_size > 0) { + weight_y = at_npu::native::NPUNativeFunctions::npu_broadcast(weight, + input.sizes()); + } + OpCommand cmd; + string reduction = "none"; + cmd.Name("SoftmaxFocalLossGrad") + .Input(input) + .Input(target_y) + .Input(grad_up) + .Input(weight_y) + .Output(grad_input) + .Attr("gamma", gamma) + .Attr("alpha", alpha) + .Attr("reduction", reduction) + .Run(); +} + +void softmax_focal_loss_backward_impl(Tensor input, Tensor target, + Tensor weight, Tensor buff, + Tensor grad_input, float gamma, + float alpha); + +REGISTER_NPU_IMPL(sigmoid_focal_loss_forward_impl, + sigmoid_focal_loss_forward_npu); + +REGISTER_NPU_IMPL(sigmoid_focal_loss_backward_impl, + sigmoid_focal_loss_backward_npu); + +REGISTER_NPU_IMPL(softmax_focal_loss_forward_impl, + softmax_focal_loss_forward_npu); + +REGISTER_NPU_IMPL(softmax_focal_loss_backward_impl, + softmax_focal_loss_backward_npu); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/fused_bias_leakyrelu_npu.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/fused_bias_leakyrelu_npu.cpp new file mode 100644 index 000000000..cd052b586 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/fused_bias_leakyrelu_npu.cpp @@ -0,0 +1,54 @@ +#include "pytorch_npu_helper.hpp" + +using namespace NPU_NAME_SPACE; +using namespace std; + +Tensor fused_bias_leakyrelu_op_impl(const Tensor &input, const Tensor &bias, + const Tensor &refer, int act, int grad, + float alpha, float scale); + +Tensor fused_bias_leakyrelu_npu(const Tensor &input, const Tensor &bias, + const Tensor &refer, int act, int grad, + float alpha, float scale) { + at::Tensor py = at::empty_like(input); + // forward + if (grad == 0) { + auto input_size = input.sizes(); + int input_length = input_size.size(); + c10::SmallVector input_size_tmp; + input_size_tmp = array_to_small_vector(input_size); + if (input_length > 1) { + for (int i = 0; i < input_length; i++) { + if (i != 1) { + input_size_tmp[i] = 1; + } + } + } + at::Tensor bias_tmp = at::reshape(bias, input_size_tmp); + at::Tensor bias_ = at_npu::native::NPUNativeFunctions::npu_broadcast( + bias_tmp, input.sizes()); + OpCommand cmd; + cmd.Name("FusedBiasLeakyRelu") + .Input(input) + .Input(bias_) + .Output(py) + .Attr("scale", scale) + .Attr("negative_slope", alpha) + .Run(); + } + + // backward + if (grad == 1) { + OpCommand cmd; + cmd.Name("FusedBiasLeakyReluGrad") + .Input(input) + .Input(refer) + .Output(py) + .Attr("scale", scale) + .Attr("negative_slope", alpha) + .Run(); + } + return py; +} + +REGISTER_NPU_IMPL(fused_bias_leakyrelu_op_impl, fused_bias_leakyrelu_npu); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/nms_npu.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/nms_npu.cpp new file mode 100644 index 000000000..2f86893ea --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/nms_npu.cpp @@ -0,0 +1,45 @@ +#include "pytorch_npu_helper.hpp" + +using namespace NPU_NAME_SPACE; +using namespace std; + +Tensor nms_npu(Tensor boxes, Tensor scores, float iou_threshold, int offset) { + at::Tensor boxed_offest = at_npu::native::OpPreparation::ApplyTensor(boxes); + at::Tensor ones_tensor = + at_npu::native::OpPreparation::ApplyTensor(boxes).fill_(1); + at::add_out(boxed_offest, boxes, ones_tensor, offset); + at::Tensor iou_threshold_y = at_npu::native::OpPreparation::ApplyTensor( + {}, boxes.options().dtype(at::kFloat), boxes) + .fill_(iou_threshold); + at::Tensor scores_threshold_y = + at_npu::native::OpPreparation::ApplyTensor( + {}, boxes.options().dtype(at::kFloat), boxes) + .fill_(0); + at::Tensor max_outputsize_y = at_npu::native::OpPreparation::ApplyTensor( + {}, boxes.options().dtype(at::kInt), boxes) + .fill_(boxes.size(0)); + c10::SmallVector outputsize = {boxes.size(0)}; + at::Tensor output = at_npu::native::OpPreparation::ApplyTensor( + outputsize, boxes.options().dtype(at::kInt), boxes) + .fill_(-1); + OpCommand cmd; + cmd.Name("NonMaxSuppressionV3") + .Input(boxes) + .Input(scores) + .Input(max_outputsize_y) + .Input(iou_threshold_y) + .Input(scores_threshold_y) + .Output(output) + .Run(); + auto outputsizeBool = at::gt(output, -1); + auto outputsizeInt = outputsizeBool.to(at::ScalarType::Int); + auto countLen = at::sum(outputsizeInt, at::ScalarType::Int); + at::Tensor actual_output = output.slice(0, 0, countLen.item().toLong()); + actual_output = at_npu::native::NPUNativeFunctions::npu_dtype_cast( + actual_output, at::kLong); + return actual_output; +} + +Tensor nms_impl(Tensor boxes, Tensor scores, float iou_threshold, int offset); + +REGISTER_NPU_IMPL(nms_impl, nms_npu); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/psa_mask_npu.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/psa_mask_npu.cpp new file mode 100644 index 000000000..44ddb5431 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/psa_mask_npu.cpp @@ -0,0 +1,75 @@ +#include "pytorch_npu_helper.hpp" + +using namespace NPU_NAME_SPACE; +using namespace std; + +void psamask_forward_npu(const int psa_type, const Tensor x, Tensor y, + const int num, const int h_feature, + const int w_feature, const int h_mask, + const int w_mask, const int half_h_mask, + const int half_w_mask) { + int64_t psa_type_i64 = psa_type; + int64_t num_i64 = num; + int64_t h_feature_i64 = h_feature; + int64_t w_feature_i64 = w_feature; + int64_t h_mask_i64 = h_mask; + int64_t w_mask_i64 = w_mask; + int64_t half_h_mask_i64 = half_h_mask; + int64_t half_w_mask_i64 = half_w_mask; + OpCommand cmd; + cmd.Name("PSAMask") + .Input(x) + .Output(y) + .Attr("psa_type", psa_type_i64) + .Attr("num", num_i64) + .Attr("h_feature", h_feature_i64) + .Attr("w_feature", w_feature_i64) + .Attr("h_mask", h_mask_i64) + .Attr("w_mask", w_mask_i64) + .Attr("half_h_mask", half_h_mask_i64) + .Attr("half_w_mask", half_w_mask_i64) + .Run(); +} + +void psamask_forward_impl(const int psa_type, const Tensor x, Tensor y, + const int num, const int h_feature, + const int w_feature, const int h_mask, + const int w_mask, const int half_h_mask, + const int half_w_mask); + +void psamask_backward_npu(const int psa_type, const Tensor y_grad, + Tensor x_grad, const int num, const int h_feature, + const int w_feature, const int h_mask, + const int w_mask, const int half_h_mask, + const int half_w_mask) { + int64_t psa_type_i64 = psa_type; + int64_t num_i64 = num; + int64_t h_feature_i64 = h_feature; + int64_t w_feature_i64 = w_feature; + int64_t h_mask_i64 = h_mask; + int64_t w_mask_i64 = w_mask; + int64_t half_h_mask_i64 = half_h_mask; + int64_t half_w_mask_i64 = half_w_mask; + OpCommand cmd; + cmd.Name("PSAMaskGrad") + .Input(y_grad) + .Output(x_grad) + .Attr("psa_type", psa_type_i64) + .Attr("num", num_i64) + .Attr("h_feature", h_feature_i64) + .Attr("w_feature", w_feature_i64) + .Attr("h_mask", h_mask_i64) + .Attr("w_mask", w_mask_i64) + .Attr("half_h_mask", half_h_mask_i64) + .Attr("half_w_mask", half_w_mask_i64) + .Run(); +} + +void psamask_backward_impl(const int psa_type, const Tensor y_grad, + Tensor x_grad, const int num, const int h_feature, + const int w_feature, const int h_mask, + const int w_mask, const int half_h_mask, + const int half_w_mask); + +REGISTER_NPU_IMPL(psamask_forward_impl, psamask_forward_npu); +REGISTER_NPU_IMPL(psamask_backward_impl, psamask_backward_npu); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/roi_pool_npu.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/roi_pool_npu.cpp new file mode 100644 index 000000000..36bd9c7a8 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/roi_pool_npu.cpp @@ -0,0 +1,34 @@ +#include "pytorch_npu_helper.hpp" + +using namespace NPU_NAME_SPACE; +using namespace std; + +void roi_pool_forward_npu(Tensor input, Tensor rois, Tensor output, + Tensor argmax, int pooled_height, int pooled_width, + float spatial_scale) { + int64_t pooled_height_64 = pooled_height; + int64_t pooled_width_64 = pooled_width; + int64_t pooled_channel = 1; + at::Tensor roi_actual_num = at_npu::native::OpPreparation::ApplyTensor( + {}, rois.options().dtype(at::kInt), rois); + + OpCommand cmd; + cmd.Name("RoiPoolingWithArgMax") + .Input(input) + .Input(rois) + .Input(roi_actual_num) + .Output(output) + .Output(argmax) + .Attr("pooled_h", pooled_height_64) + .Attr("pooled_w", pooled_width_64) + .Attr("spatial_scale_h", spatial_scale) + .Attr("spatial_scale_w", spatial_scale) + .Attr("pool_channel", pooled_channel) + .Run(); +} + +void roi_pool_forward_impl(Tensor input, Tensor rois, Tensor output, + Tensor argmax, int pooled_height, int pooled_width, + float spatial_scale); + +REGISTER_NPU_IMPL(roi_pool_forward_impl, roi_pool_forward_npu); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pixel_group.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pixel_group.cpp old mode 100644 new mode 100755 diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp index 2cf9507fe..4efd3fd84 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp @@ -118,9 +118,9 @@ void three_interpolate_backward(Tensor grad_out_tensor, Tensor idx_tensor, Tensor weight_tensor, Tensor grad_points_tensor, int b, int c, int n, int m); -// void three_nn_forward(Tensor unknown_tensor, Tensor known_tensor, -// Tensor dist2_tensor, Tensor idx_tensor, int b, int n, -// int m); +void three_nn_forward(Tensor unknown_tensor, Tensor known_tensor, + Tensor dist2_tensor, Tensor idx_tensor, int b, int n, + int m); void bbox_overlaps(const Tensor bboxes1, const Tensor bboxes2, Tensor ious, const int mode, const bool aligned, const int offset); @@ -568,10 +568,10 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { py::arg("idx_tensor"), py::arg("weight_tensor"), py::arg("grad_points_tensor"), py::arg("b"), py::arg("c"), py::arg("n"), py::arg("m")); -// m.def("three_nn_forward", &three_nn_forward, "three_nn_forward", -// py::arg("unknown_tensor"), py::arg("known_tensor"), -// py::arg("dist2_tensor"), py::arg("idx_tensor"), py::arg("b"), -// py::arg("n"), py::arg("m")); + m.def("three_nn_forward", &three_nn_forward, "three_nn_forward", + py::arg("unknown_tensor"), py::arg("known_tensor"), + py::arg("dist2_tensor"), py::arg("idx_tensor"), py::arg("b"), + py::arg("n"), py::arg("m")); m.def("bbox_overlaps", &bbox_overlaps, "bbox_overlaps", py::arg("bboxes1"), py::arg("bboxes2"), py::arg("ious"), py::arg("mode"), py::arg("aligned"), py::arg("offset")); diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/three_nn.cpp b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/three_nn.cpp new file mode 100644 index 000000000..b629200c0 --- /dev/null +++ b/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/three_nn.cpp @@ -0,0 +1,18 @@ +// Modified from +// https://github.com/sshaoshuai/Pointnet2.PyTorch/tree/master/pointnet2/src/interpolate.cpp + +#include "pytorch_cpp_helper.hpp" +#include "pytorch_device_registry.hpp" + +void three_nn_forward_impl(int b, int n, int m, const Tensor unknown, + const Tensor known, Tensor dist2, Tensor idx) { + DISPATCH_DEVICE_IMPL(three_nn_forward_impl, b, n, m, unknown, known, dist2, + idx); +} + +void three_nn_forward(Tensor unknown_tensor, Tensor known_tensor, + Tensor dist2_tensor, Tensor idx_tensor, int b, int n, + int m) { + three_nn_forward_impl(b, n, m, unknown_tensor, known_tensor, dist2_tensor, + idx_tensor); +} diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/points_in_polygons.py b/cv/distiller/CWD/mmcv/mmcv/ops/points_in_polygons.py index 62d0dbdc9..1c07aba10 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/points_in_polygons.py +++ b/cv/distiller/CWD/mmcv/mmcv/ops/points_in_polygons.py @@ -32,7 +32,7 @@ def points_in_polygons(points: Tensor, polygons: Tensor) -> Tensor: 'polygons dimension should be 8, ' \ f'but got unexpected shape {polygons.shape[1]}' output = torch.full([points.shape[0], polygons.shape[0]], - 0.).cuda().float() + 0.).float().cuda() ext_module.points_in_polygons_forward(points.contiguous(), polygons.contiguous(), output) return output diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/three_nn.py b/cv/distiller/CWD/mmcv/mmcv/ops/three_nn.py index 07e8de15c..d41b9789c 100644 --- a/cv/distiller/CWD/mmcv/mmcv/ops/three_nn.py +++ b/cv/distiller/CWD/mmcv/mmcv/ops/three_nn.py @@ -48,4 +48,4 @@ class ThreeNN(Function): return None, None -three_nn = ThreeNN.apply \ No newline at end of file +three_nn = ThreeNN.apply diff --git a/cv/distiller/CWD/mmcv/tests/data/scripts/hello.py b/cv/distiller/CWD/mmcv/tests/data/scripts/hello.py old mode 100644 new mode 100755 diff --git a/cv/distiller/CWD/mmcv/tests/data/sparse_flow.png b/cv/distiller/CWD/mmcv/tests/data/sparse_flow.png old mode 100644 new mode 100755 diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_ball_query.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_ball_query.py index d3fc7912c..41376d687 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_ball_query.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_ball_query.py @@ -89,9 +89,9 @@ def test_stack_ball_query(): [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]).cuda() assert torch.all(idx == expected_idx) - xyz = xyz.double() - new_xyz = new_xyz.double() - expected_idx = expected_idx.double() + xyz = xyz.float() + new_xyz = new_xyz.float() + expected_idx = expected_idx.float() idx = ball_query(0, 0.2, 5, xyz, new_xyz, xyz_batch_cnt, new_xyz_batch_cnt) assert torch.all(idx == expected_idx) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_bezier_align.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_bezier_align.py index b86812ace..2f05b75b2 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_bezier_align.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_bezier_align.py @@ -27,7 +27,7 @@ outputs = ([[[[1., 1.75, 3.5, 5.25], [2.5, 3.25, 5., 6.75], marks=pytest.mark.skipif( not IS_CUDA_AVAILABLE, reason='requires CUDA support')) ]) -@pytest.mark.parametrize('dtype', [torch.float, torch.double, torch.half]) +@pytest.mark.parametrize('dtype', [torch.float, torch.float, torch.half]) def test_bezieralign(device, dtype): try: from mmcv.ops import bezier_align diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_bilinear_grid_sample.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_bilinear_grid_sample.py index 8f43d4ff2..87264fb89 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_bilinear_grid_sample.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_bilinear_grid_sample.py @@ -26,16 +26,16 @@ class TestBilinearGridSample: ref_out.data.detach().cpu().numpy(), precision) def test_bilinear_grid_sample(self): - self._test_bilinear_grid_sample(torch.double, False) - self._test_bilinear_grid_sample(torch.double, True) self._test_bilinear_grid_sample(torch.float, False) self._test_bilinear_grid_sample(torch.float, True) self._test_bilinear_grid_sample(torch.float, False) + self._test_bilinear_grid_sample(torch.float, True) + self._test_bilinear_grid_sample(torch.float, False) + self._test_bilinear_grid_sample(torch.float, True, 5) + self._test_bilinear_grid_sample(torch.float, False, 10) + self._test_bilinear_grid_sample(torch.float, True, -6) + self._test_bilinear_grid_sample(torch.float, False, -10) self._test_bilinear_grid_sample(torch.float, True, 5) self._test_bilinear_grid_sample(torch.float, False, 10) self._test_bilinear_grid_sample(torch.float, True, -6) self._test_bilinear_grid_sample(torch.float, False, -10) - self._test_bilinear_grid_sample(torch.double, True, 5) - self._test_bilinear_grid_sample(torch.double, False, 10) - self._test_bilinear_grid_sample(torch.double, True, -6) - self._test_bilinear_grid_sample(torch.double, False, -10) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_border_align.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_border_align.py index 71518ce96..8d8dc3242 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_border_align.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_border_align.py @@ -85,7 +85,7 @@ def _test_border_align_allclose(device, dtype, pool_size): @pytest.mark.parametrize('device', ['cuda']) -@pytest.mark.parametrize('dtype', [torch.float, torch.half, torch.double]) +@pytest.mark.parametrize('dtype', [torch.float, torch.half, torch.float]) @pytest.mark.parametrize('pool_size', [1, 2]) def test_border_align(device, dtype, pool_size): _test_border_align_allclose(device, dtype, pool_size) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_carafe.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_carafe.py index 02d00f1ff..4a3809f4c 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_carafe.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_carafe.py @@ -14,10 +14,10 @@ class TestCarafe: return from mmcv.ops import CARAFENaive feat = torch.randn( - 2, 64, 3, 3, requires_grad=True, device='cuda').double() + 2, 64, 3, 3, requires_grad=True, device='cuda').float() mask = torch.randn( 2, 100, 6, 6, requires_grad=True, - device='cuda').sigmoid().double() + device='cuda').sigmoid().float() gradcheck(CARAFENaive(5, 4, 2), (feat, mask), atol=1e-4, eps=1e-4) def test_carafe_gradcheck(self): @@ -25,10 +25,10 @@ class TestCarafe: return from mmcv.ops import CARAFE feat = torch.randn( - 2, 64, 3, 3, requires_grad=True, device='cuda').double() + 2, 64, 3, 3, requires_grad=True, device='cuda').float() mask = torch.randn( 2, 100, 6, 6, requires_grad=True, - device='cuda').sigmoid().double() + device='cuda').sigmoid().float() gradcheck(CARAFE(5, 4, 2), (feat, mask), atol=1e-4, eps=1e-4) @pytest.mark.parametrize('device', [ diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_convex_iou.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_convex_iou.py index 95dc48243..533037762 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_convex_iou.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_convex_iou.py @@ -37,9 +37,9 @@ np_expected_grad = np.asarray([[ @pytest.mark.skipif( not torch.cuda.is_available(), reason='requires CUDA support') def test_convex_iou(): - pointsets = torch.from_numpy(np_pointsets).cuda().float() - polygons = torch.from_numpy(np_polygons).cuda().float() - expected_iou = torch.from_numpy(np_expected_iou).cuda().float() + pointsets = torch.from_numpy(np_pointsets).float().cuda() + polygons = torch.from_numpy(np_polygons).float().cuda() + expected_iou = torch.from_numpy(np_expected_iou).float().cuda() assert torch.allclose( convex_iou(pointsets, polygons), expected_iou, atol=1e-3) @@ -47,10 +47,10 @@ def test_convex_iou(): @pytest.mark.skipif( not torch.cuda.is_available(), reason='requires CUDA support') def test_convex_giou(): - pointsets = torch.from_numpy(np_pointsets).cuda().float() - polygons = torch.from_numpy(np_polygons).cuda().float() - expected_giou = torch.from_numpy(np_expected_giou).cuda().float() - expected_grad = torch.from_numpy(np_expected_grad).cuda().float() + pointsets = torch.from_numpy(np_pointsets).float().cuda() + polygons = torch.from_numpy(np_polygons).float().cuda() + expected_giou = torch.from_numpy(np_expected_giou).float().cuda() + expected_grad = torch.from_numpy(np_expected_grad).float().cuda() giou, grad = convex_giou(pointsets, polygons) assert torch.allclose(giou, expected_giou, atol=1e-3) assert torch.allclose(grad, expected_grad, atol=1e-3) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_correlation.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_correlation.py index 6cf5f9f72..5e5011ae1 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_correlation.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_correlation.py @@ -42,5 +42,5 @@ class TestCorrelation: not torch.cuda.is_available(), reason='requires CUDA support') def test_correlation(self): self._test_correlation(torch.float) - self._test_correlation(torch.double) + self._test_correlation(torch.float) self._test_correlation(torch.half) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_conv.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_conv.py index 64dcccfde..9411024af 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_conv.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_conv.py @@ -178,9 +178,9 @@ class TestDeformconv: model = DeformConv2d(3, 4, 3, groups=3) def test_deformconv(self): - self._test_deformconv(torch.double, device='cpu') + self._test_deformconv(torch.float, device='cpu') self._test_deformconv(torch.float, device='cpu', threshold=1e-1) - self._test_deformconv(torch.double) + self._test_deformconv(torch.float) self._test_deformconv(torch.float) self._test_deformconv(torch.half, threshold=1e-1) # test batch_size < im2col_step diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_roi_pool.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_roi_pool.py index 346301fe4..826e1fd21 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_roi_pool.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_roi_pool.py @@ -142,7 +142,7 @@ class TestDeformRoIPool: @pytest.mark.parametrize('dtype', [ torch.float, pytest.param( - torch.double, + torch.float, marks=pytest.mark.skipif( IS_MLU_AVAILABLE, reason='MLU does not support for 64-bit floating point')), diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_group_points.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_group_points.py index 8109540ce..a6dfef5f1 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_group_points.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_group_points.py @@ -7,7 +7,7 @@ from mmcv.ops import grouping_operation @pytest.mark.skipif( not torch.cuda.is_available(), reason='requires CUDA support') -@pytest.mark.parametrize('dtype', [torch.half, torch.float, torch.double]) +@pytest.mark.parametrize('dtype', [torch.half, torch.float, torch.float]) def test_grouping_points(dtype): idx = torch.tensor([[[0, 0, 0], [3, 3, 3], [8, 8, 8], [0, 0, 0], [0, 0, 0], [0, 0, 0]], @@ -65,7 +65,7 @@ def test_grouping_points(dtype): @pytest.mark.skipif( not torch.cuda.is_available(), reason='requires CUDA support') -@pytest.mark.parametrize('dtype', [torch.half, torch.float, torch.double]) +@pytest.mark.parametrize('dtype', [torch.half, torch.float, torch.float]) def test_stack_grouping_points(dtype): idx = torch.tensor([[0, 0, 0], [3, 3, 3], [8, 8, 8], [1, 1, 1], [0, 0, 0], [2, 2, 2], [0, 0, 0], [6, 6, 6], [9, 9, 9], [0, 0, 0], diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_info.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_info.py index e3c1722eb..4f2cc23ee 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_info.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_info.py @@ -12,3 +12,5 @@ class TestInfo: ccv = get_compiling_cuda_version() assert cv is not None assert ccv is not None + + diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_iou3d.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_iou3d.py index 6bb8c1ccc..40ec90164 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_iou3d.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_iou3d.py @@ -97,7 +97,7 @@ def test_nms3d(device): # test for many boxes # In the float data type calculation process, float will be converted to - # double in CUDA kernel (https://github.com/open-mmlab/mmcv/blob + # float in CUDA kernel (https://github.com/open-mmlab/mmcv/blob # /master/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp#L61), # always use float in MLU kernel. The difference between the mentioned # above leads to different results. diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_min_area_polygons.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_min_area_polygons.py index 649bdecfd..b049e765d 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_min_area_polygons.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_min_area_polygons.py @@ -22,7 +22,7 @@ expected_polygons = np.asarray( @pytest.mark.skipif( not torch.cuda.is_available(), reason='requires CUDA support') def test_min_area_polygons(): - pointsets = torch.from_numpy(np_pointsets).cuda().float() + pointsets = torch.from_numpy(np_pointsets).float().cuda() assert np.allclose( min_area_polygons(pointsets).cpu().numpy(), diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_modulated_deform_conv.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_modulated_deform_conv.py index ee29e73eb..58a325459 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_modulated_deform_conv.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_modulated_deform_conv.py @@ -112,9 +112,9 @@ class TestMdconv: dcn_offset_b_grad, 1e-2) def test_mdconv(self): - self._test_mdconv(torch.double, device='cpu') self._test_mdconv(torch.float, device='cpu') - self._test_mdconv(torch.double) + self._test_mdconv(torch.float, device='cpu') + self._test_mdconv(torch.float) self._test_mdconv(torch.float) self._test_mdconv(torch.half) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_ms_deformable_attn.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_ms_deformable_attn.py index a29380552..04f3d0443 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_ms_deformable_attn.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_ms_deformable_attn.py @@ -89,13 +89,13 @@ def test_forward_multi_scale_deformable_attn_pytorch(): -1, keepdim=True).sum( -2, keepdim=True) - multi_scale_deformable_attn_pytorch(value.double(), shapes, - sampling_locations.double(), - attention_weights.double()).detach() + multi_scale_deformable_attn_pytorch(value.float(), shapes, + sampling_locations.float(), + attention_weights.float()).detach() @pytest.mark.skipif(not IS_CUDA_AVAILABLE, reason='requires CUDA support') -def test_forward_equal_with_pytorch_double(): +def test_forward_equal_with_pytorch_float(): N, M, D = 1, 2, 2 Lq, L, P = 2, 2, 2 shapes = torch.as_tensor([(6, 4), (3, 2)], dtype=torch.long) @@ -112,13 +112,13 @@ def test_forward_equal_with_pytorch_double(): -2, keepdim=True) im2col_step = 2 output_pytorch = multi_scale_deformable_attn_pytorch( - value.double(), shapes, sampling_locations.double(), - attention_weights.double()).detach().cpu() + value.float(), shapes, sampling_locations.float(), + attention_weights.float()).detach().cpu() output_cuda = MultiScaleDeformableAttnFunction.apply( - value.cuda().double(), shapes.cuda(), level_start_index.cuda(), - sampling_locations.cuda().double(), - attention_weights.cuda().double(), im2col_step).detach().cpu() + value.cuda().float(), shapes.cuda(), level_start_index.cuda(), + sampling_locations.cuda().float(), + attention_weights.cuda().float(), im2col_step).detach().cpu() assert torch.allclose(output_cuda, output_pytorch) max_abs_err = (output_cuda - output_pytorch).abs().max() max_rel_err = ((output_cuda - output_pytorch).abs() / @@ -181,7 +181,7 @@ def test_forward_equal_with_pytorch_float(device): @pytest.mark.parametrize('dtype', [ torch.float, pytest.param( - torch.double, + torch.float, marks=pytest.mark.skipif( IS_MLU_AVAILABLE, reason='MLU does not support for 64-bit floating point')), @@ -223,7 +223,7 @@ def test_gradient_numerical(channels, sampling_locations.requires_grad = grad_sampling_loc attention_weights.requires_grad = grad_attn_weight if device == 'cuda': - dtype = torch.double + dtype = torch.float eps = 1e-6 elif device == 'mlu': dtype = torch.float diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_onnx.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_onnx.py index 719721752..d5edc9ac4 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_onnx.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_onnx.py @@ -194,8 +194,8 @@ def test_border_align(): @pytest.mark.skipif(not torch.cuda.is_available(), reason='test requires GPU') def test_carafe(): from mmcv.ops import CARAFENaive - feat = torch.randn(2, 64, 3, 3, device='cuda').double() - mask = torch.randn(2, 100, 6, 6, device='cuda').sigmoid().double() + feat = torch.randn(2, 64, 3, 3, device='cuda').float() + mask = torch.randn(2, 100, 6, 6, device='cuda').sigmoid().float() _test_symbolic(CARAFENaive(5, 4, 2), (feat, mask), 'MMCVCARAFENaive') diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_points_in_polygons.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_points_in_polygons.py index dde8ab023..28bb8951d 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_points_in_polygons.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_points_in_polygons.py @@ -16,8 +16,8 @@ def test_points_in_polygons(): [300., 300., 600., 700., 700., 700., 700., 100.]]) expected_output = np.array([[0., 0., 0.], [0., 0., 1.], [0., 0., 0.], [1., 0., 0.], [0., 0., 0.]]) - points = torch.from_numpy(points).cuda().float() - polygons = torch.from_numpy(polygons).cuda().float() - expected_output = torch.from_numpy(expected_output).cuda().float() + points = torch.from_numpy(points).float().cuda() + polygons = torch.from_numpy(polygons).float().cuda() + expected_output = torch.from_numpy(expected_output).float().cuda() assert torch.allclose( points_in_polygons(points, polygons), expected_output, 1e-3) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align.py index 6caf5c535..fa7045c5c 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align.py @@ -107,14 +107,14 @@ def _test_roialign_allclose(device, dtype): @pytest.mark.parametrize('dtype', [ torch.float, pytest.param( - torch.double, + torch.float, marks=pytest.mark.skipif( IS_MLU_AVAILABLE, reason='MLU does not support for 64-bit floating point')), torch.half ]) def test_roialign(device, dtype): - # check double only - if dtype is torch.double: + # check float only + if dtype is torch.float: _test_roialign_gradcheck(device=device, dtype=dtype) _test_roialign_allclose(device=device, dtype=dtype) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align_rotated.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align_rotated.py index 1ad6b6e92..08038fa91 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align_rotated.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align_rotated.py @@ -138,14 +138,14 @@ def _test_roialign_rotated_allclose(device, dtype): @pytest.mark.parametrize('dtype', [ torch.float, pytest.param( - torch.double, + torch.float, marks=pytest.mark.skipif( IS_MLU_AVAILABLE, reason='MLU does not support for 64-bit floating point')), torch.half ]) def test_roialign_rotated(device, dtype): - # check double only - if dtype is torch.double: + # check float only + if dtype is torch.float: _test_roialign_rotated_gradcheck(device=device, dtype=dtype) _test_roialign_rotated_allclose(device=device, dtype=dtype) diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_pool.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_pool.py index c935c8114..275d71f53 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_pool.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_pool.py @@ -95,7 +95,7 @@ class TestRoiPool: @pytest.mark.parametrize('dtype', [ torch.float, pytest.param( - torch.double, + torch.float, marks=pytest.mark.skipif( IS_MLU_AVAILABLE, reason='MLU does not support for 64-bit floating point')), diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roiaware_pool3d.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_roiaware_pool3d.py index 2a9cbfd32..155fce664 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_roiaware_pool3d.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_roiaware_pool3d.py @@ -21,9 +21,9 @@ from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE @pytest.mark.parametrize('dtype', [ torch.float, torch.half, pytest.param( - torch.double, + torch.float, marks=pytest.mark.skipif( - IS_MLU_AVAILABLE, reason='MLU does not support for double')) + IS_MLU_AVAILABLE, reason='MLU does not support for float')) ]) def test_RoIAwarePool3d(device, dtype): roiaware_pool3d_max = RoIAwarePool3d( diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roipoint_pool3d.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_roipoint_pool3d.py index 391a0bf3a..c69a95f81 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_roipoint_pool3d.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_roipoint_pool3d.py @@ -19,9 +19,9 @@ from mmcv.utils import IS_CUDA_AVAILABLE, IS_MLU_AVAILABLE @pytest.mark.parametrize('dtype', [ torch.float, torch.half, pytest.param( - torch.double, + torch.float, marks=pytest.mark.skipif( - IS_MLU_AVAILABLE, reason='MLU does not support for double')) + IS_MLU_AVAILABLE, reason='MLU does not support for float')) ]) def test_roipoint(device, dtype): points = torch.tensor( diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_three_interpolate.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_three_interpolate.py index 51a6b8732..9f56e3ee8 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_three_interpolate.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_three_interpolate.py @@ -7,7 +7,7 @@ from mmcv.ops import three_interpolate @pytest.mark.skipif( not torch.cuda.is_available(), reason='requires CUDA support') -@pytest.mark.parametrize('dtype', [torch.half, torch.float, torch.double]) +@pytest.mark.parametrize('dtype', [torch.half, torch.float, torch.float]) def test_three_interpolate(dtype): features = torch.tensor( [[[2.4350, 4.7516, 4.4995, 2.4350, 2.4350, 2.4350], diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_tin_shift.py b/cv/distiller/CWD/mmcv/tests/test_ops/test_tin_shift.py index c8ce14465..ea684f31b 100644 --- a/cv/distiller/CWD/mmcv/tests/test_ops/test_tin_shift.py +++ b/cv/distiller/CWD/mmcv/tests/test_ops/test_tin_shift.py @@ -214,7 +214,7 @@ def _test_tinshift_assert(device, dtype): @pytest.mark.parametrize('dtype', [ torch.float, pytest.param( - torch.double, + torch.float, marks=pytest.mark.skipif( IS_MLU_AVAILABLE, reason='MLU does not support for 64-bit floating point')), -- Gitee From bf1b8a4809dd4b70df047b2356b55efbb4f5152a Mon Sep 17 00:00:00 2001 From: "yongle.wu" Date: Thu, 15 Jun 2023 05:38:29 +0000 Subject: [PATCH 5/6] modified README.md --- cv/distiller/CWD/README.md | 23 ++++++++++++++++---- cv/distiller/CWD/mmrazor/tools/dist_train.sh | 2 ++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/cv/distiller/CWD/README.md b/cv/distiller/CWD/README.md index 3302aa384..4f02782d0 100644 --- a/cv/distiller/CWD/README.md +++ b/cv/distiller/CWD/README.md @@ -11,7 +11,20 @@ Knowledge distillation (KD) has been proven to be a simple and effective tool fo ## Environment +## install libGL +yum install mesa-libGL + +## install zlib +wget http://www.zlib.net/fossils/zlib-1.2.9.tar.gz +tar xvf zlib-1.2.9.tar.gz +cd zlib-1.2.9/ +./configure && make install +cd .. +rm -rf zlib-1.2.9.tar.gz zlib-1.2.9/ + + ``` +pip3 install cityscapesscripts addict opencv-python cd mmcv bash clean_mmcv.sh bash build_mmcv.sh @@ -19,7 +32,7 @@ bash install_mmcv.sh cd ../mmrazor pip3 install -r requirements.txt pip3 install mmcls==v1.0.0rc6 -pip3 install mmsegmentation==v1.0.0rc6 +pip3 install mmsegmentation==v1.0.0 pip3 install mmengine==0.7.3 python3 setup.py develop ``` @@ -68,6 +81,8 @@ bash tools/dist_train.sh configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_psp ## Segmentation -| Location | Dataset | Teacher | Student | mIoU | mIoU(T) | mIou(S) | Config | Download | -| :------: | :--------: | :------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------: | :---: | :-----: | :-----: | :----------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| logits | cityscapes | [pspnet_r101](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes.py) | [pspnet_r18](https://github.com/open-mmlab/mmsegmentation/blob/master/configs/pspnet/pspnet_r18-d8_512x1024_80k_cityscapes.py) | 75.54 | 79.76 | 74.87 | [config](<>) | [teacher](https://download.openmmlab.com/mmsegmentation/v0.5/pspnet/pspnet_r101-d8_512x1024_80k_cityscapes/pspnet_r101-d8_512x1024_80k_cityscapes_20200606_112211-e1e1100f.pth) \|[model](https://download.openmmlab.com/mmrazor/v1/cwd/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k_mIoU-75.54_20211222-3e643f6f.pth) \| [log](https://download.openmmlab.com/mmrazor/v0.1/distill/cwd/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k/cwd_cls_head_pspnet_r101_d8_pspnet_r18_d8_512x1024_cityscapes_80k_20211212_205711.log.json) | \ No newline at end of file +| model | GPU | FP32 | +|-------------------| ----------- | ------------------------------------ | +| pspnet_r18(student) | 8 cards | Miou= 75.32 | + + diff --git a/cv/distiller/CWD/mmrazor/tools/dist_train.sh b/cv/distiller/CWD/mmrazor/tools/dist_train.sh index 4ef0ea669..a32ea3fa4 100755 --- a/cv/distiller/CWD/mmrazor/tools/dist_train.sh +++ b/cv/distiller/CWD/mmrazor/tools/dist_train.sh @@ -1,4 +1,6 @@ #!/usr/bin/env bash +# Copyright (c) 2023, Shanghai Iluvatar CoreX Semiconductor Co., Ltd. +# All Rights Reserved. CONFIG=$1 GPUS=$2 -- Gitee From 9a7564f9b0cf92f67464c34b7b4d3278d58755d9 Mon Sep 17 00:00:00 2001 From: "yongle.wu" Date: Thu, 15 Jun 2023 05:46:22 +0000 Subject: [PATCH 6/6] renamed --- cv/distiller/CWD/{ => pytorch}/README.md | 0 cv/distiller/CWD/{ => pytorch}/mmcv/.dockerignore | 0 .../CWD/{ => pytorch}/mmcv/.pre-commit-config.yaml | 0 .../CWD/{ => pytorch}/mmcv/.readthedocs.yml | 0 cv/distiller/CWD/{ => pytorch}/mmcv/CITATION.cff | 0 cv/distiller/CWD/{ => pytorch}/mmcv/CONTRIBUTING.md | 0 .../CWD/{ => pytorch}/mmcv/CONTRIBUTING_zh-CN.md | 0 cv/distiller/CWD/{ => pytorch}/mmcv/Jenkinsfile | 0 cv/distiller/CWD/{ => pytorch}/mmcv/LICENSE | 0 cv/distiller/CWD/{ => pytorch}/mmcv/LICENSES.md | 0 cv/distiller/CWD/{ => pytorch}/mmcv/MANIFEST.in | 0 cv/distiller/CWD/{ => pytorch}/mmcv/README.md | 0 cv/distiller/CWD/{ => pytorch}/mmcv/README_zh-CN.md | 0 cv/distiller/CWD/{ => pytorch}/mmcv/TERMINOLOGY.md | 0 cv/distiller/CWD/{ => pytorch}/mmcv/build_mmcv.sh | 0 cv/distiller/CWD/{ => pytorch}/mmcv/clean_mmcv.sh | 0 .../CWD/{ => pytorch}/mmcv/docker/README.md | 0 .../CWD/{ => pytorch}/mmcv/docker/dev/Dockerfile | 0 .../{ => pytorch}/mmcv/docker/release/Dockerfile | 0 .../CWD/{ => pytorch}/mmcv/docs/en/Makefile | 0 .../mmcv/docs/en/_static/community/1.png | Bin .../mmcv/docs/en/_static/community/2.png | Bin .../mmcv/docs/en/_static/community/3.png | Bin .../mmcv/docs/en/_static/css/readthedocs.css | 0 .../mmcv/docs/en/_static/flow_img2toimg1.png | Bin .../mmcv/docs/en/_static/flow_raw_images.png | Bin .../mmcv/docs/en/_static/flow_visualization.png | Bin .../mmcv/docs/en/_static/flow_warp.png | Bin .../mmcv/docs/en/_static/flow_warp_diff.png | Bin .../mmcv/docs/en/_static/image/mmcv-logo.png | Bin .../mmcv/docs/en/_static/parallel_progress.gif | Bin .../mmcv/docs/en/_static/parallel_progress.png | Bin .../{ => pytorch}/mmcv/docs/en/_static/progress.gif | Bin .../{ => pytorch}/mmcv/docs/en/_static/progress.png | Bin .../{ => pytorch}/mmcv/docs/en/_static/version.json | 0 .../mmcv/docs/en/_templates/classtemplate.rst | 0 .../{ => pytorch}/mmcv/docs/en/api/arraymisc.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/en/api/cnn.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/en/api/image.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/en/api/ops.rst | 0 .../{ => pytorch}/mmcv/docs/en/api/transforms.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/en/api/utils.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/en/api/video.rst | 0 .../mmcv/docs/en/api/visualization.rst | 0 .../mmcv/docs/en/community/contributing.md | 0 .../CWD/{ => pytorch}/mmcv/docs/en/community/pr.md | 0 .../CWD/{ => pytorch}/mmcv/docs/en/compatibility.md | 0 cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/conf.py | 0 .../mmcv/docs/en/deployment/mmcv_ops_definition.md | 0 .../CWD/{ => pytorch}/mmcv/docs/en/docutils.conf | 0 cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/faq.md | 0 .../{ => pytorch}/mmcv/docs/en/get_started/build.md | 0 .../mmcv/docs/en/get_started/installation.md | 0 .../mmcv/docs/en/get_started/introduction.md | 0 .../mmcv/docs/en/get_started/previous_versions.md | 0 .../CWD/{ => pytorch}/mmcv/docs/en/index.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/en/make.bat | 0 .../CWD/{ => pytorch}/mmcv/docs/en/mmcv-logo.png | Bin .../{ => pytorch}/mmcv/docs/en/switch_language.md | 0 .../mmcv/docs/en/understand_mmcv/cnn.md | 0 .../mmcv/docs/en/understand_mmcv/data_process.md | 0 .../mmcv/docs/en/understand_mmcv/data_transform.md | 0 .../mmcv/docs/en/understand_mmcv/ops.md | 0 .../mmcv/docs/en/understand_mmcv/visualization.md | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/Makefile | 0 .../mmcv/docs/zh_cn/_static/css/readthedocs.css | 0 .../mmcv/docs/zh_cn/_static/image/mmcv-logo.png | Bin .../mmcv/docs/zh_cn/_static/version.json | 0 .../mmcv/docs/zh_cn/_templates/classtemplate.rst | 0 .../{ => pytorch}/mmcv/docs/zh_cn/api/arraymisc.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/api/cnn.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/api/image.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/api/ops.rst | 0 .../mmcv/docs/zh_cn/api/transforms.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/api/utils.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/api/video.rst | 0 .../mmcv/docs/zh_cn/api/visualization.rst | 0 .../mmcv/docs/zh_cn/community/code_style.md | 0 .../mmcv/docs/zh_cn/community/contributing.md | 0 .../{ => pytorch}/mmcv/docs/zh_cn/community/pr.md | 0 .../{ => pytorch}/mmcv/docs/zh_cn/compatibility.md | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/conf.py | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/docutils.conf | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/faq.md | 0 .../mmcv/docs/zh_cn/get_started/article.md | 0 .../mmcv/docs/zh_cn/get_started/build.md | 0 .../mmcv/docs/zh_cn/get_started/installation.md | 0 .../mmcv/docs/zh_cn/get_started/introduction.md | 0 .../docs/zh_cn/get_started/previous_versions.md | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/index.rst | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/make.bat | 0 .../CWD/{ => pytorch}/mmcv/docs/zh_cn/mmcv-logo.png | 0 .../mmcv/docs/zh_cn/switch_language.md | 0 .../mmcv/docs/zh_cn/understand_mmcv/cnn.md | 0 .../mmcv/docs/zh_cn/understand_mmcv/data_process.md | 0 .../docs/zh_cn/understand_mmcv/data_transform.md | 0 .../mmcv/docs/zh_cn/understand_mmcv/ops.md | 0 .../docs/zh_cn/understand_mmcv/visualization.md | 0 cv/distiller/CWD/{ => pytorch}/mmcv/install_mmcv.sh | 0 .../CWD/{ => pytorch}/mmcv/mmcv/__init__.py | 0 .../{ => pytorch}/mmcv/mmcv/arraymisc/__init__.py | 0 .../mmcv/mmcv/arraymisc/quantization.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/cnn/__init__.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/cnn/alexnet.py | 0 .../{ => pytorch}/mmcv/mmcv/cnn/bricks/__init__.py | 0 .../mmcv/mmcv/cnn/bricks/activation.py | 0 .../mmcv/mmcv/cnn/bricks/context_block.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/conv.py | 0 .../mmcv/mmcv/cnn/bricks/conv2d_adaptive_padding.py | 0 .../mmcv/mmcv/cnn/bricks/conv_module.py | 0 .../{ => pytorch}/mmcv/mmcv/cnn/bricks/conv_ws.py | 0 .../cnn/bricks/depthwise_separable_conv_module.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/drop.py | 0 .../mmcv/mmcv/cnn/bricks/generalized_attention.py | 0 .../{ => pytorch}/mmcv/mmcv/cnn/bricks/hsigmoid.py | 0 .../{ => pytorch}/mmcv/mmcv/cnn/bricks/hswish.py | 0 .../{ => pytorch}/mmcv/mmcv/cnn/bricks/non_local.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/norm.py | 0 .../{ => pytorch}/mmcv/mmcv/cnn/bricks/padding.py | 0 .../{ => pytorch}/mmcv/mmcv/cnn/bricks/plugin.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/scale.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/swish.py | 0 .../mmcv/mmcv/cnn/bricks/transformer.py | 0 .../{ => pytorch}/mmcv/mmcv/cnn/bricks/upsample.py | 0 .../{ => pytorch}/mmcv/mmcv/cnn/bricks/wrappers.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/cnn/resnet.py | 0 .../{ => pytorch}/mmcv/mmcv/cnn/utils/__init__.py | 0 .../mmcv/mmcv/cnn/utils/flops_counter.py | 0 .../mmcv/mmcv/cnn/utils/fuse_conv_bn.py | 0 cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/vgg.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/image/__init__.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/image/colorspace.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/image/geometric.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/image/io.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/image/misc.py | 0 .../{ => pytorch}/mmcv/mmcv/image/photometric.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/__init__.py | 0 .../mmcv/mmcv/ops/active_rotated_filter.py | 0 .../mmcv/mmcv/ops/assign_score_withk.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/ball_query.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/bbox.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/bezier_align.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/border_align.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/box_iou_quadri.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/box_iou_rotated.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/carafe.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/cc_attention.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/chamfer_distance.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/contour_expand.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/convex_iou.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/corner_pool.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/correlation.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/README.md | 0 .../mmcv/ops/csrc/common/box_iou_rotated_utils.hpp | 0 .../cuda/active_rotated_filter_cuda_kernel.cuh | 0 .../common/cuda/assign_score_withk_cuda_kernel.cuh | 0 .../ops/csrc/common/cuda/ball_query_cuda_kernel.cuh | 0 .../csrc/common/cuda/bbox_overlaps_cuda_kernel.cuh | 0 .../csrc/common/cuda/bezier_align_cuda_kernel.cuh | 0 .../csrc/common/cuda/border_align_cuda_kernel.cuh | 0 .../ops/csrc/common/cuda/box_iou_quadri_cuda.cuh | 0 .../ops/csrc/common/cuda/box_iou_rotated_cuda.cuh | 0 .../ops/csrc/common/cuda/carafe_cuda_kernel.cuh | 0 .../csrc/common/cuda/carafe_naive_cuda_kernel.cuh | 0 .../common/cuda/chamfer_distance_cuda_kernel.cuh | 0 .../ops/csrc/common/cuda/common_cuda_helper.hpp | 0 .../ops/csrc/common/cuda/convex_iou_cuda_kernel.cuh | 0 .../mmcv/ops/csrc/common/cuda/correlation_cuda.cuh | 0 .../csrc/common/cuda/deform_conv_cuda_kernel.cuh | 0 .../common/cuda/deform_roi_pool_cuda_kernel.cuh | 0 .../common/cuda/diff_iou_rotated_cuda_kernel.cuh | 0 .../cuda/furthest_point_sample_cuda_kernel.cuh | 0 .../csrc/common/cuda/gather_points_cuda_kernel.cuh | 0 .../csrc/common/cuda/group_points_cuda_kernel.cuh | 0 .../mmcv/ops/csrc/common/cuda/iou3d_cuda_kernel.cuh | 0 .../mmcv/ops/csrc/common/cuda/knn_cuda_kernel.cuh | 0 .../csrc/common/cuda/masked_conv2d_cuda_kernel.cuh | 0 .../ops/csrc/common/cuda/min_area_polygons_cuda.cuh | 0 .../cuda/modulated_deform_conv_cuda_kernel.cuh | 0 .../csrc/common/cuda/ms_deform_attn_cuda_kernel.cuh | 0 .../mmcv/ops/csrc/common/cuda/nms_cuda_kernel.cuh | 0 .../mmcv/ops/csrc/common/cuda/nms_quadri_cuda.cuh | 0 .../mmcv/ops/csrc/common/cuda/nms_rotated_cuda.cuh | 0 .../csrc/common/cuda/parrots_cudawarpfunction.cuh | 0 .../common/cuda/points_in_boxes_cuda_kernel.cuh | 0 .../common/cuda/points_in_polygons_cuda_kernel.cuh | 0 .../ops/csrc/common/cuda/prroi_pool_cuda_kernel.cuh | 0 .../ops/csrc/common/cuda/psamask_cuda_kernel.cuh | 0 .../common/cuda/riroi_align_rotated_cuda_kernel.cuh | 0 .../ops/csrc/common/cuda/roi_align_cuda_kernel.cuh | 0 .../common/cuda/roi_align_rotated_cuda_kernel.cuh | 0 .../ops/csrc/common/cuda/roi_pool_cuda_kernel.cuh | 0 .../common/cuda/roiaware_pool3d_cuda_kernel.cuh | 0 .../common/cuda/roipoint_pool3d_cuda_kernel.cuh | 0 .../cuda/rotated_feature_align_cuda_kernel.cuh | 0 .../csrc/common/cuda/scatter_points_cuda_kernel.cuh | 0 .../common/cuda/sigmoid_focal_loss_cuda_kernel.cuh | 0 .../common/cuda/softmax_focal_loss_cuda_kernel.cuh | 0 .../common/cuda/stack_ball_query_cuda_kernel.cuh | 0 .../common/cuda/stack_group_points_cuda_kernel.cuh | 0 .../ops/csrc/common/cuda/sync_bn_cuda_kernel.cuh | 0 .../common/cuda/three_interpolate_cuda_kernel.cuh | 0 .../ops/csrc/common/cuda/three_nn_cuda_kernel.cuh | 0 .../ops/csrc/common/cuda/tin_shift_cuda_kernel.cuh | 0 .../csrc/common/cuda/voxelization_cuda_kernel.cuh | 0 .../csrc/common/mlu/bbox_overlaps_mlu_kernel.mlu | 0 .../mmcv/ops/csrc/common/mlu/carafe_mlu_kernel.mlu | 0 .../mmcv/mmcv/ops/csrc/common/mlu/carafe_utils.hpp | 0 .../mmcv/ops/csrc/common/mlu/common_mlu_helper.hpp | 0 .../csrc/common/mlu/deform_roi_pool_mlu_kernel.mlu | 0 .../common/mlu/focal_loss_sigmoid_mlu_kernel.mlu | 0 .../mmcv/ops/csrc/common/mlu/iou3d_mlu_kernel.mlu | 0 .../mmcv/mmcv/ops/csrc/common/mlu/iou3d_utils.hpp | 0 .../csrc/common/mlu/masked_conv2d_mlu_kernel.mlu | 0 .../csrc/common/mlu/ms_deform_attn_mlu_kernel.mlu | 0 .../mmcv/ops/csrc/common/mlu/nms_mlu_kernel.mlu | 0 .../mmcv/mmcv/ops/csrc/common/mlu/nms_utils.hpp | 0 .../mmcv/ops/csrc/common/mlu/psamask_mlu_kernel.mlu | 0 .../mmcv/mmcv/ops/csrc/common/mlu/psamask_utils.hpp | 0 .../ops/csrc/common/mlu/roi_align_mlu_kernel.mlu | 0 .../common/mlu/roi_align_rotated_mlu_kernel.mlu | 0 .../ops/csrc/common/mlu/roi_align_rotated_utils.hpp | 0 .../ops/csrc/common/mlu/roi_pool_mlu_kernel.mlu | 0 .../csrc/common/mlu/roiaware_pool3d_mlu_kernel.mlu | 0 .../roipoint_pool3d_large_boxes_num_mlu_kernel.mlu | 0 .../csrc/common/mlu/roipoint_pool3d_mlu_kernel.mlu | 0 .../ops/csrc/common/mlu/three_nn_mlu_kernel.mlu | 0 .../ops/csrc/common/mlu/tin_shift_mlu_kernel.mlu | 0 .../mmcv/mmcv/ops/csrc/common/mps/MPSDevice.h | 0 .../mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.h | 0 .../mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.mm | 0 .../mmcv/mmcv/ops/csrc/common/mps/MPSStream.h | 0 .../mmcv/mmcv/ops/csrc/common/mps/MPSUtils.h | 0 .../mmcv/ops/csrc/common/parrots_cpp_helper.hpp | 0 .../mmcv/ops/csrc/common/parrots_cuda_helper.hpp | 0 .../mmcv/ops/csrc/common/pytorch_cpp_helper.hpp | 0 .../mmcv/ops/csrc/common/pytorch_cuda_helper.hpp | 0 .../ops/csrc/common/pytorch_device_registry.hpp | 0 .../mmcv/ops/csrc/common/pytorch_mlu_helper.hpp | 0 .../mmcv/ops/csrc/common/pytorch_npu_helper.hpp | 0 .../mmcv/ops/csrc/parrots/active_rotated_filter.cpp | 0 .../csrc/parrots/active_rotated_filter_parrots.cpp | 0 .../csrc/parrots/active_rotated_filter_pytorch.h | 0 .../mmcv/ops/csrc/parrots/assign_score_withk.cpp | 0 .../ops/csrc/parrots/assign_score_withk_parrots.cpp | 0 .../ops/csrc/parrots/assign_score_withk_pytorch.h | 0 .../mmcv/ops/csrc/parrots/ball_query._parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/ball_query.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/ball_query_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/bbox_overlaps.cpp | 0 .../mmcv/ops/csrc/parrots/bbox_overlaps_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/bbox_overlaps_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/border_align.cpp | 0 .../mmcv/ops/csrc/parrots/border_align_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/border_align_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/box_iou_rotated.cpp | 0 .../ops/csrc/parrots/box_iou_rotated_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/box_iou_rotated_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/carafe.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/carafe_naive.cpp | 0 .../mmcv/ops/csrc/parrots/carafe_naive_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/carafe_naive_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/carafe_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/carafe_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/chamfer_distance.cpp | 0 .../ops/csrc/parrots/chamfer_distance_parrots.cpp | 0 .../ops/csrc/parrots/chamfer_distance_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/contour_expand.cpp | 0 .../ops/csrc/parrots/contour_expand_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/contour_expand_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/convex_iou.cpp | 0 .../mmcv/ops/csrc/parrots/convex_iou_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/convex_iou_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/correlation.cpp | 0 .../mmcv/ops/csrc/parrots/correlation_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/correlation_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/cudabind.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/deform_conv.cpp | 0 .../mmcv/ops/csrc/parrots/deform_conv_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/deform_conv_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/deform_roi_pool.cpp | 0 .../ops/csrc/parrots/deform_roi_pool_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/deform_roi_pool_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated.cpp | 0 .../ops/csrc/parrots/diff_iou_rotated_parrots.cpp | 0 .../ops/csrc/parrots/diff_iou_rotated_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/focal_loss.cpp | 0 .../mmcv/ops/csrc/parrots/focal_loss_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/focal_loss_pytorch.h | 0 .../mmcv/ops/csrc/parrots/furthest_point_sample.cpp | 0 .../csrc/parrots/furthest_point_sample_parrots.cpp | 0 .../csrc/parrots/furthest_point_sample_pytorch.h | 0 .../mmcv/ops/csrc/parrots/fused_bias_leakyrelu.cpp | 0 .../mmcv/ops/csrc/parrots/fused_bias_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/gather_points.cpp | 0 .../mmcv/ops/csrc/parrots/gather_points_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/gather_points_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/group_points.cpp | 0 .../mmcv/ops/csrc/parrots/group_points_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/group_points_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/info.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/iou3d.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/iou3d_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/iou3d_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/knn.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/knn_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/knn_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/masked_conv2d.cpp | 0 .../mmcv/ops/csrc/parrots/masked_conv2d_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/masked_conv2d_pytorch.h | 0 .../mmcv/ops/csrc/parrots/min_area_polygons.cpp | 0 .../ops/csrc/parrots/min_area_polygons_parrots.cpp | 0 .../ops/csrc/parrots/min_area_polygons_pytorch.h | 0 .../mmcv/ops/csrc/parrots/modulated_deform_conv.cpp | 0 .../csrc/parrots/modulated_deform_conv_parrots.cpp | 0 .../csrc/parrots/modulated_deform_conv_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/ms_deform_attn.cpp | 0 .../ops/csrc/parrots/ms_deform_attn_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/nms.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/nms_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/nms_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/nms_rotated.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/pixel_group.cpp | 0 .../mmcv/ops/csrc/parrots/pixel_group_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/pixel_group_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/points_in_boxes.cpp | 0 .../ops/csrc/parrots/points_in_boxes_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/points_in_boxes_pytorch.h | 0 .../mmcv/ops/csrc/parrots/points_in_polygons.cpp | 0 .../ops/csrc/parrots/points_in_polygons_parrots.cpp | 0 .../ops/csrc/parrots/points_in_polygons_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/prroi_pool.cpp | 0 .../mmcv/ops/csrc/parrots/prroi_pool_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/prroi_pool_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/psamask.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/psamask_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/psamask_pytorch.h | 0 .../mmcv/ops/csrc/parrots/riroi_align_rotated.cpp | 0 .../csrc/parrots/riroi_align_rotated_parrots.cpp | 0 .../ops/csrc/parrots/riroi_align_rotated_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/roi_align.cpp | 0 .../mmcv/ops/csrc/parrots/roi_align_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/roi_align_pytorch.h | 0 .../mmcv/ops/csrc/parrots/roi_align_rotated.cpp | 0 .../ops/csrc/parrots/roi_align_rotated_parrots.cpp | 0 .../ops/csrc/parrots/roi_align_rotated_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/roi_pool.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/roi_pool_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/roi_pool_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d.cpp | 0 .../ops/csrc/parrots/roiaware_pool3d_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/roiaware_pool3d_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d.cpp | 0 .../ops/csrc/parrots/roipoint_pool3d_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/roipoint_pool3d_pytorch.h | 0 .../mmcv/ops/csrc/parrots/rotated_feature_align.cpp | 0 .../csrc/parrots/rotated_feature_align_parrots.cpp | 0 .../csrc/parrots/rotated_feature_align_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/sync_bn.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/sync_bn_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/sync_bn_pytorch.h | 0 .../mmcv/ops/csrc/parrots/three_interpolate.cpp | 0 .../ops/csrc/parrots/three_interpolate_parrots.cpp | 0 .../ops/csrc/parrots/three_interpolate_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/three_nn.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/three_nn_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/three_nn_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/tin_shift.cpp | 0 .../mmcv/ops/csrc/parrots/tin_shift_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/tin_shift_pytorch.h | 0 .../mmcv/mmcv/ops/csrc/parrots/upfirdn2d.cpp | 0 .../mmcv/ops/csrc/parrots/upfirdn2d_parrots.cpp | 0 .../mmcv/mmcv/ops/csrc/parrots/voxelization.cpp | 0 .../mmcv/ops/csrc/parrots/voxelization_parrots.cpp | 0 .../mmcv/ops/csrc/parrots/voxelization_pytorch.h | 0 .../mmcv/ops/csrc/pytorch/active_rotated_filter.cpp | 0 .../mmcv/ops/csrc/pytorch/assign_score_withk.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/ball_query.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/bbox_overlaps.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/bezier_align.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/border_align.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/box_iou_quadri.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/box_iou_rotated.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/carafe.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/carafe_naive.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/chamfer_distance.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/contour_expand.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/convex_iou.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/correlation.cpp | 0 .../ops/csrc/pytorch/cpu/active_rotated_filter.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/cpu/bezier_align.cpp | 0 .../mmcv/ops/csrc/pytorch/cpu/box_iou_quadri.cpp | 0 .../mmcv/ops/csrc/pytorch/cpu/box_iou_rotated.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/cpu/deform_conv.cpp | 0 .../ops/csrc/pytorch/cpu/modulated_deform_conv.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/cpu/nms.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/cpu/nms_quadri.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/cpu/nms_rotated.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/cpu/pixel_group.cpp | 0 .../mmcv/ops/csrc/pytorch/cpu/points_in_boxes.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/cpu/psamask.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align.cpp | 0 .../mmcv/ops/csrc/pytorch/cpu/roi_align_rotated.cpp | 0 .../ops/csrc/pytorch/cpu/rotated_feature_align.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/cpu/voxelization.cpp | 0 .../csrc/pytorch/cuda/active_rotated_filter_cuda.cu | 0 .../csrc/pytorch/cuda/assign_score_withk_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/ball_query_cuda.cu | 0 .../ops/csrc/pytorch/cuda/bbox_overlaps_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/bezier_align_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/border_align_cuda.cu | 0 .../ops/csrc/pytorch/cuda/box_iou_quadri_cuda.cu | 0 .../ops/csrc/pytorch/cuda/box_iou_rotated_cuda.cu | 0 .../mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/carafe_naive_cuda.cu | 0 .../ops/csrc/pytorch/cuda/chamfer_distance_cuda.cu | 0 .../mmcv/mmcv/ops/csrc/pytorch/cuda/convex_iou.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/correlation_cuda.cu | 0 .../mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp | 0 .../mmcv/ops/csrc/pytorch/cuda/deform_conv_cuda.cu | 0 .../ops/csrc/pytorch/cuda/deform_roi_pool_cuda.cu | 0 .../ops/csrc/pytorch/cuda/diff_iou_rotated_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/focal_loss_cuda.cu | 0 .../csrc/pytorch/cuda/furthest_point_sample_cuda.cu | 0 .../csrc/pytorch/cuda/fused_bias_leakyrelu_cuda.cu | 0 .../ops/csrc/pytorch/cuda/gather_points_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/group_points_cuda.cu | 0 .../mmcv/mmcv/ops/csrc/pytorch/cuda/iou3d_cuda.cu | 0 .../mmcv/mmcv/ops/csrc/pytorch/cuda/knn_cuda.cu | 0 .../ops/csrc/pytorch/cuda/masked_conv2d_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/min_area_polygons.cu | 0 .../csrc/pytorch/cuda/modulated_deform_conv_cuda.cu | 0 .../ops/csrc/pytorch/cuda/ms_deform_attn_cuda.cu | 0 .../mmcv/mmcv/ops/csrc/pytorch/cuda/nms_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/nms_quadri_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/nms_rotated_cuda.cu | 0 .../ops/csrc/pytorch/cuda/points_in_boxes_cuda.cu | 0 .../csrc/pytorch/cuda/points_in_polygons_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/prroi_pool_cuda.cu | 0 .../mmcv/mmcv/ops/csrc/pytorch/cuda/psamask_cuda.cu | 0 .../csrc/pytorch/cuda/riroi_align_rotated_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/roi_align_cuda.cu | 0 .../ops/csrc/pytorch/cuda/roi_align_rotated_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/roi_pool_cuda.cu | 0 .../ops/csrc/pytorch/cuda/roiaware_pool3d_cuda.cu | 0 .../ops/csrc/pytorch/cuda/roipoint_pool3d_cuda.cu | 0 .../csrc/pytorch/cuda/rotated_feature_align_cuda.cu | 0 .../ops/csrc/pytorch/cuda/scatter_points_cuda.cu | 0 .../ops/csrc/pytorch/cuda/stack_ball_query_cuda.cu | 0 .../csrc/pytorch/cuda/stack_group_points_cuda.cu | 0 .../mmcv/mmcv/ops/csrc/pytorch/cuda/sync_bn_cuda.cu | 0 .../ops/csrc/pytorch/cuda/three_interpolate_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/three_nn_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/tin_shift_cuda.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/upfirdn2d_kernel.cu | 0 .../mmcv/ops/csrc/pytorch/cuda/voxelization_cuda.cu | 0 .../mmcv/mmcv/ops/csrc/pytorch/deform_conv.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/deform_roi_pool.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/diff_iou_rotated.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/focal_loss.cpp | 0 .../mmcv/ops/csrc/pytorch/furthest_point_sample.cpp | 0 .../mmcv/ops/csrc/pytorch/fused_bias_leakyrelu.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/fused_spconv_ops.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/gather_points.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/group_points.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/info.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/iou3d.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/knn.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/masked_conv2d.cpp | 0 .../mmcv/ops/csrc/pytorch/min_area_polygons.cpp | 0 .../mmcv/ops/csrc/pytorch/mlu/bbox_overlaps_mlu.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/mlu/carafe_mlu.cpp | 0 .../ops/csrc/pytorch/mlu/deform_roi_pool_mlu.cpp | 0 .../ops/csrc/pytorch/mlu/focal_loss_sigmoid_mlu.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/mlu/iou3d_mlu.cpp | 0 .../mmcv/ops/csrc/pytorch/mlu/masked_conv2d_mlu.cpp | 0 .../ops/csrc/pytorch/mlu/ms_deform_attn_mlu.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/mlu/nms_mlu.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/mlu/psamask_mlu.cpp | 0 .../mmcv/ops/csrc/pytorch/mlu/roi_align_mlu.cpp | 0 .../ops/csrc/pytorch/mlu/roi_align_rotated_mlu.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/mlu/roi_pool_mlu.cpp | 0 .../ops/csrc/pytorch/mlu/roiaware_pool3d_mlu.cpp | 0 .../ops/csrc/pytorch/mlu/roipoint_pool3d_mlu.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/mlu/three_nn_mlu.cpp | 0 .../mmcv/ops/csrc/pytorch/mlu/tin_shift_mlu.cpp | 0 .../mmcv/ops/csrc/pytorch/modulated_deform_conv.cpp | 0 .../mmcv/ops/csrc/pytorch/mps/bbox_overlaps_mps.mm | 0 .../mmcv/mmcv/ops/csrc/pytorch/ms_deform_attn.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/nms.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/nms_quadri.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/nms_rotated.cpp | 0 .../mmcv/ops/csrc/pytorch/npu/deform_roi_pool.cpp | 0 .../mmcv/ops/csrc/pytorch/npu/focal_loss_npu.cpp | 0 .../csrc/pytorch/npu/fused_bias_leakyrelu_npu.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/npu/nms_npu.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/npu/psa_mask_npu.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/npu/roi_pool_npu.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/pixel_group.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/points_in_boxes.cpp | 0 .../mmcv/ops/csrc/pytorch/points_in_polygons.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/prroi_pool.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/psamask.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/pybind.cpp | 0 .../mmcv/ops/csrc/pytorch/riroi_align_rotated.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/roi_align.cpp | 0 .../mmcv/ops/csrc/pytorch/roi_align_rotated.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/roi_pool.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/roiaware_pool3d.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/roipoint_pool3d.cpp | 0 .../mmcv/ops/csrc/pytorch/rotated_feature_align.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/scatter_points.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/sync_bn.cpp | 0 .../mmcv/ops/csrc/pytorch/three_interpolate.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/three_nn.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/tin_shift.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/upfirdn2d.cpp | 0 .../mmcv/mmcv/ops/csrc/pytorch/voxelization.cpp | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/deform_conv.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/deform_roi_pool.py | 0 .../mmcv/mmcv/ops/deprecated_wrappers.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/diff_iou_rotated.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/focal_loss.py | 0 .../mmcv/mmcv/ops/furthest_point_sample.py | 0 .../mmcv/mmcv/ops/fused_bias_leakyrelu.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/gather_points.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/group_points.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/info.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/iou3d.py | 0 cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/knn.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/masked_conv.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/merge_cells.py | 0 .../mmcv/mmcv/ops/min_area_polygons.py | 0 .../mmcv/mmcv/ops/modulated_deform_conv.py | 0 .../mmcv/mmcv/ops/multi_scale_deform_attn.py | 0 cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/nms.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/pixel_group.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/point_sample.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/points_in_boxes.py | 0 .../mmcv/mmcv/ops/points_in_polygons.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/points_sampler.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/prroi_pool.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/psa_mask.py | 0 .../mmcv/mmcv/ops/riroi_align_rotated.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/roi_align.py | 0 .../mmcv/mmcv/ops/roi_align_rotated.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/roi_pool.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/roiaware_pool3d.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/roipoint_pool3d.py | 0 .../mmcv/mmcv/ops/rotated_feature_align.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/saconv.py | 0 .../{ => pytorch}/mmcv/mmcv/ops/scatter_points.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/sync_bn.py | 0 .../mmcv/mmcv/ops/three_interpolate.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/three_nn.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/tin_shift.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/upfirdn2d.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/ops/voxelize.py | 0 .../{ => pytorch}/mmcv/mmcv/transforms/__init__.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/transforms/base.py | 0 .../{ => pytorch}/mmcv/mmcv/transforms/builder.py | 0 .../mmcv/mmcv/transforms/formatting.py | 0 .../{ => pytorch}/mmcv/mmcv/transforms/loading.py | 0 .../mmcv/mmcv/transforms/processing.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/transforms/utils.py | 0 .../{ => pytorch}/mmcv/mmcv/transforms/wrappers.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/utils/__init__.py | 0 .../{ => pytorch}/mmcv/mmcv/utils/device_type.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/utils/env.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/utils/ext_loader.py | 0 .../{ => pytorch}/mmcv/mmcv/utils/parrots_jit.py | 0 cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/version.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/video/__init__.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/video/io.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/video/optflow.py | 0 .../CWD/{ => pytorch}/mmcv/mmcv/video/processing.py | 0 .../mmcv/mmcv/visualization/__init__.py | 0 .../{ => pytorch}/mmcv/mmcv/visualization/color.py | 0 .../{ => pytorch}/mmcv/mmcv/visualization/image.py | 0 .../mmcv/mmcv/visualization/optflow.py | 0 .../CWD/{ => pytorch}/mmcv/requirements.txt | 0 .../CWD/{ => pytorch}/mmcv/requirements/build.txt | 0 .../CWD/{ => pytorch}/mmcv/requirements/docs.txt | 0 .../{ => pytorch}/mmcv/requirements/optional.txt | 0 .../CWD/{ => pytorch}/mmcv/requirements/runtime.txt | 0 .../CWD/{ => pytorch}/mmcv/requirements/test.txt | 0 cv/distiller/CWD/{ => pytorch}/mmcv/setup.cfg | 0 cv/distiller/CWD/{ => pytorch}/mmcv/setup.py | 0 .../mmcv/tests/data/batched_nms_data.pkl | Bin .../CWD/{ => pytorch}/mmcv/tests/data/color.jpg | Bin .../{ => pytorch}/mmcv/tests/data/color_exif.jpg | Bin .../CWD/{ => pytorch}/mmcv/tests/data/config/a.b.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/a.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/b.json | 0 .../{ => pytorch}/mmcv/tests/data/config/base.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/c.yaml | 0 .../{ => pytorch}/mmcv/tests/data/config/code.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/d.py | 0 .../{ => pytorch}/mmcv/tests/data/config/delete.py | 0 .../mmcv/tests/data/config/deprecated.py | 0 .../mmcv/tests/data/config/deprecated_as_base.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/e.py | 0 .../mmcv/tests/data/config/expected.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/f.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/g.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/h.py | 0 .../{ => pytorch}/mmcv/tests/data/config/i_base.py | 0 .../{ => pytorch}/mmcv/tests/data/config/i_child.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/l.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/l1.py | 0 .../{ => pytorch}/mmcv/tests/data/config/l2.yaml | 0 .../{ => pytorch}/mmcv/tests/data/config/l3.json | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/l4.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/m.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/n.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/o.json | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/p.yaml | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/q.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/r.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/s.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/t.json | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/t.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/t.yaml | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/u.json | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/u.py | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/u.yaml | 0 .../CWD/{ => pytorch}/mmcv/tests/data/config/v.py | 0 .../mmcv/tests/data/demo.lmdb/data.mdb | Bin .../mmcv/tests/data/demo.lmdb/lock.mdb | Bin .../CWD/{ => pytorch}/mmcv/tests/data/filelist.txt | 0 .../data/for_3d_ops/features_for_fps_distance.npy | Bin .../mmcv/tests/data/for_3d_ops/fps_idx.npy | Bin .../mmcv/tests/data/for_3d_ops/test_voxel.npy | Bin .../mmcv/tests/data/for_carafe/carafe_feat.bin | Bin .../mmcv/tests/data/for_carafe/carafe_feat_grad.bin | 0 .../mmcv/tests/data/for_carafe/carafe_mask.bin | Bin .../mmcv/tests/data/for_carafe/carafe_mask_grad.bin | Bin .../mmcv/tests/data/for_carafe/carafe_output.bin | Bin .../data/for_ccattention/ccattention_input.bin | Bin .../data/for_ccattention/ccattention_output.bin | Bin .../for_masked_conv2d/masked_conv2d_for_bias.npy | Bin .../for_masked_conv2d/masked_conv2d_for_input.npy | Bin .../for_masked_conv2d/masked_conv2d_for_mask.npy | Bin .../for_masked_conv2d/masked_conv2d_for_output.npy | Bin .../for_masked_conv2d/masked_conv2d_for_weight.npy | Bin .../mmcv/tests/data/for_psa_mask/psa_input.bin | Bin .../tests/data/for_psa_mask/psa_output_collect.bin | Bin .../data/for_psa_mask/psa_output_distribute.bin | Bin .../{ => pytorch}/mmcv/tests/data/for_scan/.file | 0 .../{ => pytorch}/mmcv/tests/data/for_scan/1.json | 0 .../{ => pytorch}/mmcv/tests/data/for_scan/1.txt | 0 .../{ => pytorch}/mmcv/tests/data/for_scan/2.json | 0 .../{ => pytorch}/mmcv/tests/data/for_scan/2.txt | 0 .../{ => pytorch}/mmcv/tests/data/for_scan/3.TXT | 0 .../{ => pytorch}/mmcv/tests/data/for_scan/a.bin | 0 .../mmcv/tests/data/for_scan/sub/1.json | 0 .../mmcv/tests/data/for_scan/sub/1.txt | 0 .../{ => pytorch}/mmcv/tests/data/gray_alpha.png | Bin .../CWD/{ => pytorch}/mmcv/tests/data/grayscale.jpg | Bin .../mmcv/tests/data/grayscale_dim3.jpg | Bin .../CWD/{ => pytorch}/mmcv/tests/data/mapping.txt | 0 .../CWD/{ => pytorch}/mmcv/tests/data/optflow.flo | Bin .../mmcv/tests/data/optflow_concat0.jpg | Bin .../mmcv/tests/data/optflow_concat1.jpg | Bin .../CWD/{ => pytorch}/mmcv/tests/data/palette.gif | Bin .../CWD/{ => pytorch}/mmcv/tests/data/patches/0.npy | Bin .../CWD/{ => pytorch}/mmcv/tests/data/patches/1.npy | Bin .../CWD/{ => pytorch}/mmcv/tests/data/patches/2.npy | Bin .../CWD/{ => pytorch}/mmcv/tests/data/patches/3.npy | Bin .../CWD/{ => pytorch}/mmcv/tests/data/patches/4.npy | Bin .../mmcv/tests/data/patches/pad0_0.npy | Bin .../mmcv/tests/data/patches/pad0_1.npy | Bin .../mmcv/tests/data/patches/pad0_2.npy | Bin .../mmcv/tests/data/patches/pad0_3.npy | Bin .../mmcv/tests/data/patches/pad0_4.npy | Bin .../{ => pytorch}/mmcv/tests/data/patches/pad_0.npy | Bin .../{ => pytorch}/mmcv/tests/data/patches/pad_1.npy | Bin .../{ => pytorch}/mmcv/tests/data/patches/pad_2.npy | Bin .../{ => pytorch}/mmcv/tests/data/patches/pad_3.npy | Bin .../{ => pytorch}/mmcv/tests/data/patches/pad_4.npy | Bin .../mmcv/tests/data/patches/scale_0.npy | Bin .../mmcv/tests/data/patches/scale_1.npy | Bin .../mmcv/tests/data/patches/scale_2.npy | Bin .../mmcv/tests/data/patches/scale_3.npy | Bin .../mmcv/tests/data/patches/scale_4.npy | Bin .../{ => pytorch}/mmcv/tests/data/scripts/hello.py | 0 .../{ => pytorch}/mmcv/tests/data/sparse_flow.png | Bin .../CWD/{ => pytorch}/mmcv/tests/data/test.mp4 | Bin .../mmcv/tests/data/uint16-5channel.tif | Bin .../CWD/{ => pytorch}/mmcv/tests/test_arraymisc.py | 0 .../mmcv/tests/test_cnn/test_build_layers.py | 0 .../mmcv/tests/test_cnn/test_context_block.py | 0 .../tests/test_cnn/test_conv2d_adaptive_padding.py | 0 .../mmcv/tests/test_cnn/test_conv_module.py | 0 .../test_depthwise_seperable_conv_module.py | 0 .../mmcv/tests/test_cnn/test_flops_counter.py | 0 .../mmcv/tests/test_cnn/test_fuse_conv_bn.py | 0 .../tests/test_cnn/test_generalized_attention.py | 0 .../mmcv/tests/test_cnn/test_hsigmoid.py | 0 .../mmcv/tests/test_cnn/test_hswish.py | 0 .../mmcv/tests/test_cnn/test_non_local.py | 0 .../{ => pytorch}/mmcv/tests/test_cnn/test_scale.py | 0 .../{ => pytorch}/mmcv/tests/test_cnn/test_silu.py | 0 .../{ => pytorch}/mmcv/tests/test_cnn/test_swish.py | 0 .../mmcv/tests/test_cnn/test_transformer.py | 0 .../mmcv/tests/test_cnn/test_wrappers.py | 0 .../mmcv/tests/test_image/test_colorspace.py | 0 .../mmcv/tests/test_image/test_geometric.py | 0 .../mmcv/tests/test_image/test_image_misc.py | 0 .../{ => pytorch}/mmcv/tests/test_image/test_io.py | 0 .../mmcv/tests/test_image/test_photometric.py | 0 .../{ => pytorch}/mmcv/tests/test_ops/output.pkl | Bin .../tests/test_ops/test_active_rotated_filter.py | 0 .../mmcv/tests/test_ops/test_assign_score_withk.py | 0 .../mmcv/tests/test_ops/test_ball_query.py | 0 .../{ => pytorch}/mmcv/tests/test_ops/test_bbox.py | 0 .../mmcv/tests/test_ops/test_bezier_align.py | 0 .../tests/test_ops/test_bilinear_grid_sample.py | 0 .../mmcv/tests/test_ops/test_border_align.py | 0 .../mmcv/tests/test_ops/test_box_iou_quadri.py | 0 .../mmcv/tests/test_ops/test_box_iou_rotated.py | 0 .../mmcv/tests/test_ops/test_carafe.py | 0 .../mmcv/tests/test_ops/test_cc_attention.py | 0 .../mmcv/tests/test_ops/test_chamfer_distance.py | 0 .../mmcv/tests/test_ops/test_contour_expand.py | 0 .../mmcv/tests/test_ops/test_convex_iou.py | 0 .../mmcv/tests/test_ops/test_corner_pool.py | 0 .../mmcv/tests/test_ops/test_correlation.py | 0 .../mmcv/tests/test_ops/test_deform_conv.py | 0 .../mmcv/tests/test_ops/test_deform_roi_pool.py | 0 .../mmcv/tests/test_ops/test_diff_iou_rotated.py | 0 .../mmcv/tests/test_ops/test_focal_loss.py | 0 .../tests/test_ops/test_furthest_point_sample.py | 0 .../tests/test_ops/test_fused_bias_leakyrelu.py | 0 .../mmcv/tests/test_ops/test_gather_points.py | 0 .../mmcv/tests/test_ops/test_group_points.py | 0 .../{ => pytorch}/mmcv/tests/test_ops/test_info.py | 0 .../{ => pytorch}/mmcv/tests/test_ops/test_iou3d.py | 0 .../{ => pytorch}/mmcv/tests/test_ops/test_knn.py | 0 .../mmcv/tests/test_ops/test_masked_conv2d.py | 0 .../mmcv/tests/test_ops/test_merge_cells.py | 0 .../mmcv/tests/test_ops/test_min_area_polygons.py | 0 .../tests/test_ops/test_modulated_deform_conv.py | 0 .../mmcv/tests/test_ops/test_ms_deformable_attn.py | 0 .../{ => pytorch}/mmcv/tests/test_ops/test_nms.py | 0 .../mmcv/tests/test_ops/test_nms_quadri.py | 0 .../mmcv/tests/test_ops/test_nms_rotated.py | 0 .../{ => pytorch}/mmcv/tests/test_ops/test_onnx.py | 0 .../mmcv/tests/test_ops/test_pixel_group.py | 0 .../mmcv/tests/test_ops/test_points_in_polygons.py | 0 .../mmcv/tests/test_ops/test_prroi_pool.py | 0 .../mmcv/tests/test_ops/test_psa_mask.py | 0 .../mmcv/tests/test_ops/test_riroi_align_rotated.py | 0 .../mmcv/tests/test_ops/test_roi_align.py | 0 .../mmcv/tests/test_ops/test_roi_align_rotated.py | 0 .../mmcv/tests/test_ops/test_roi_pool.py | 0 .../mmcv/tests/test_ops/test_roiaware_pool3d.py | 0 .../mmcv/tests/test_ops/test_roipoint_pool3d.py | 0 .../tests/test_ops/test_rotated_feature_align.py | 0 .../mmcv/tests/test_ops/test_saconv.py | 0 .../mmcv/tests/test_ops/test_scatter_points.py | 0 .../mmcv/tests/test_ops/test_spconv.py | 0 .../mmcv/tests/test_ops/test_syncbn.py | 0 .../mmcv/tests/test_ops/test_three_interpolate.py | 0 .../mmcv/tests/test_ops/test_three_nn.py | 0 .../mmcv/tests/test_ops/test_tin_shift.py | 0 .../mmcv/tests/test_ops/test_upfirdn2d.py | 0 .../mmcv/tests/test_ops/test_voxelization.py | 0 .../test_transforms/test_transforms_formatting.py | 0 .../test_transforms/test_transforms_loading.py | 0 .../test_transforms/test_transforms_processing.py | 0 .../test_transforms/test_transforms_wrapper.py | 0 .../{ => pytorch}/mmcv/tests/test_utils/test_env.py | 0 .../mmcv/tests/test_utils/test_parrots_jit.py | 0 .../mmcv/tests/test_video/test_optflow.py | 0 .../mmcv/tests/test_video/test_processing.py | 0 .../mmcv/tests/test_video/test_reader.py | 0 .../{ => pytorch}/mmcv/tests/test_visualization.py | 0 .../CWD/{ => pytorch}/mmrazor/.circleci/config.yml | 0 .../mmrazor/.circleci/docker/Dockerfile | 0 .../CWD/{ => pytorch}/mmrazor/.circleci/test.yml | 0 .../.dev_scripts/benchmark_summary_analyse.py | 0 .../mmrazor/.dev_scripts/benchmark_test.py | 0 .../mmrazor/.dev_scripts/benchmark_train.py | 0 .../mmrazor/.dev_scripts/meta_files_test.py | 0 .../{ => pytorch}/mmrazor/.pre-commit-config.yaml | 0 .../CWD/{ => pytorch}/mmrazor/.readthedocs.yml | 0 cv/distiller/CWD/{ => pytorch}/mmrazor/LICENSE | 0 cv/distiller/CWD/{ => pytorch}/mmrazor/MANIFEST.in | 0 cv/distiller/CWD/{ => pytorch}/mmrazor/README.md | 0 .../CWD/{ => pytorch}/mmrazor/README_zh-CN.md | 0 .../_base_/datasets/mmcls/cifar100_bs16_auto_aug.py | 0 .../datasets/mmcls/pipelines/auto_aug_cifar.py | 0 .../nas_backbones/attentive_mobilenetv3_supernet.py | 0 .../configs/_base_/nas_backbones/darts_supernet.py | 0 .../nas_backbones/dsnas_shufflenet_supernet.py | 0 .../nas_backbones/ofa_mobilenetv3_supernet.py | 0 .../_base_/nas_backbones/spos_mobilenet_supernet.py | 0 .../nas_backbones/spos_shufflenet_supernet.py | 0 .../configs/_base_/settings/cifar10_darts_subnet.py | 0 .../_base_/settings/cifar10_darts_supernet.py | 0 .../_base_/settings/imagenet_bs1024_dsnas.py | 0 .../configs/_base_/settings/imagenet_bs1024_spos.py | 0 .../_base_/settings/imagenet_bs2048_AdamW.py | 0 .../_base_/settings/imagenet_bs2048_autoslim.py | 0 .../_base_/settings/imagenet_bs2048_autoslim_pil.py | 0 .../_base_/settings/imagenet_bs2048_bignas.py | 0 .../configs/_base_/settings/imagenet_bs2048_dmcp.py | 0 .../configs/_base_/settings/imagenet_bs2048_ofa.py | 0 .../_base_/vanilla_models/wrn16_2_cifar10.py | 0 .../mmrazor/configs/distill/mmcls/abloss/README.md | 0 .../abloss_logits_resnet50_resnet18_8xb32_in1k.py | 0 ...retrain_backbone_resnet50_resnet18_8xb32_in1k.py | 0 .../configs/distill/mmcls/abloss/metafile.yml | 0 .../mmrazor/configs/distill/mmcls/byot/README.md | 0 .../mmcls/byot/byot_resnet18_8xb16_cifar100.py | 0 .../mmrazor/configs/distill/mmcls/byot/metafile.yml | 0 .../mmrazor/configs/distill/mmcls/crd/README.md | 0 .../mmcls/crd/crd_neck_r50_r18_8xb16_cifar10.py | 0 .../distill/mmcls/crd/datasets/crd_cifar10_bs16.py | 0 .../mmrazor/configs/distill/mmcls/dafl/README.md | 0 .../dafl_logits_resnet34_resnet18_8xb256_cifar10.py | 0 .../mmrazor/configs/distill/mmcls/dafl/metafile.yml | 0 .../mmrazor/configs/distill/mmcls/deit/README.md | 0 .../deit/deit-base_regnety160_pt-16xb64_in1k.py | 0 .../mmrazor/configs/distill/mmcls/deit/metafile.yml | 0 .../mmrazor/configs/distill/mmcls/dfad/README.md | 0 .../dfad_logits_resnet34_resnet18_8xb32_cifar10.py | 0 .../mmrazor/configs/distill/mmcls/dfad/metafile.yml | 0 .../mmrazor/configs/distill/mmcls/dkd/README.md | 0 .../mmcls/dkd/dkd_resnet34_resnet18_8xb32_in1k.py | 0 .../mmrazor/configs/distill/mmcls/dkd/metafile.yml | 0 .../configs/distill/mmcls/factor_transfer/README.md | 0 ...bone_resnet50_resnet18_8xb16_cifar10_pretrain.py | 0 ...ackbone_resnet50_resnet18_8xb16_cifar10_train.py | 0 .../distill/mmcls/factor_transfer/metafile.yml | 0 .../mmrazor/configs/distill/mmcls/fitnets/README.md | 0 ..._backbone_logits_resnet50_resnet18_8xb32_in1k.py | 0 .../configs/distill/mmcls/fitnets/metafile.yml | 0 .../mmrazor/configs/distill/mmcls/kd/README.md | 0 .../kd/kd_logits_resnet34_resnet18_8xb32_in1k.py | 0 .../kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py | 0 ..._logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py | 0 .../mmrazor/configs/distill/mmcls/kd/metafile.yml | 0 .../mmrazor/configs/distill/mmcls/ofd/README.md | 0 .../mmrazor/configs/distill/mmcls/ofd/metafile.yml | 0 .../ofd_backbone_resnet50_resnet18_8xb16_cifar10.py | 0 .../mmrazor/configs/distill/mmcls/rkd/README.md | 0 .../mmrazor/configs/distill/mmcls/rkd/metafile.yml | 0 .../rkd/rkd_neck_resnet34_resnet18_8xb32_in1k.py | 0 .../mmrazor/configs/distill/mmcls/wsld/README.md | 0 .../mmrazor/configs/distill/mmcls/wsld/metafile.yml | 0 .../wsld_logits_resnet34_resnet18_8xb32_in1k.py | 0 .../mmrazor/configs/distill/mmcls/zskt/README.md | 0 .../mmrazor/configs/distill/mmcls/zskt/metafile.yml | 0 ...ckbone_logits_resnet34_resnet18_8xb16_cifar10.py | 0 .../mmrazor/configs/distill/mmdet/cwd/README.md | 0 ...cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py | 0 .../cwd/cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py | 0 .../cwd/cwd_fpn_retina_r101_retina_r50_1x_coco.py | 0 ..._retina_r101_retina_r50_1x_coco_visualization.py | 0 .../mmrazor/configs/distill/mmdet/cwd/metafile.yml | 0 .../mmrazor/configs/distill/mmdet/fbkd/README.md | 0 ..._fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco.py | 0 .../mmrazor/configs/distill/mmdet/fbkd/metafile.yml | 0 .../mmrazor/configs/distill/mmdet/mgd/README.md | 0 .../mgd/mgd_fpn_retina_x101_retina_r50_2x_coco.py | 0 .../mmrazor/configs/distill/mmdet/pkd/README.md | 0 .../mmrazor/configs/distill/mmdet/pkd/metafile.yml | 0 ..._fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py | 0 .../pkd/pkd_fpn_fcos_x101_retina_r50_1x_coco.py | 0 .../pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py | 0 ..._fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py | 0 .../pkd/pkd_fpn_retina_x101_retina_r50_2x_coco.py | 0 .../mmrazor/configs/distill/mmdet3d/pkd/README.md | 0 .../configs/distill/mmdet3d/pkd/metafile.yml | 0 ...fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py | 0 .../mmrazor/configs/distill/mmseg/cwd/README.md | 0 ...d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py | 0 .../mmrazor/configs/distill/mmseg/cwd/metafile.yml | 0 .../nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml | 0 .../mmrazor/configs/nas/mmcls/autoformer/README.md | 0 .../autoformer/autoformer_search_8xb128_in1k.py | 0 .../autoformer/autoformer_subnet_8xb256_in1k.py | 0 .../autoformer/autoformer_supernet_32xb256_in1k.py | 0 .../mmrazor/configs/nas/mmcls/autoslim/README.md | 0 .../autoslim_mbv2_1.5x_search_8xb256_in1k.py | 0 ...toslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py | 0 ...oslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py | 0 ...oslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py | 0 ...oslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py | 0 .../autoslim_mbv2_1.5x_supernet_8xb256_in1k.py | 0 .../mmrazor/configs/nas/mmcls/autoslim/metafile.yml | 0 .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml | 0 .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A1.yaml | 0 .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A2.yaml | 0 .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A3.yaml | 0 .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A4.yaml | 0 .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A5.yaml | 0 .../nas/mmcls/bignas/ATTENTIVE_SUBNET_A6.yaml | 0 .../mmrazor/configs/nas/mmcls/bignas/README.md | 0 .../attentive_mobilenet_search_8xb128_in1k.py | 0 .../attentive_mobilenet_subnet_8xb256_in1k.py | 0 .../attentive_mobilenet_supernet_32xb64_in1k.py | 0 .../darts/DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml | 0 .../mmcls/darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml | 0 .../mmrazor/configs/nas/mmcls/darts/README.md | 0 .../mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py | 0 .../darts/darts_subnet_1xb96_cifar10_2.0_mmrazor.py | 0 .../darts/darts_supernet_unroll_1xb96_cifar10.py | 0 .../mmrazor/configs/nas/mmcls/darts/metafile.yml | 0 .../dsnas/DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml | 0 .../mmrazor/configs/nas/mmcls/dsnas/README.md | 0 .../nas/mmcls/dsnas/dsnas_subnet_8xb128_in1k.py | 0 .../nas/mmcls/dsnas/dsnas_supernet_8xb128_in1k.py | 0 .../mmcls/onceforall/OFA_SUBNET_NOTE8_LAT22.yaml | 0 .../mmcls/onceforall/OFA_SUBNET_NOTE8_LAT31.yaml | 0 .../mmrazor/configs/nas/mmcls/onceforall/README.md | 0 .../onceforall/ofa_mobilenet_search_8xb128_in1k.py | 0 .../onceforall/ofa_mobilenet_subnet_8xb256_in1k.py | 0 .../ofa_mobilenet_supernet_32xb64_in1k.py | 0 .../mmrazor/configs/nas/mmcls/spos/README.md | 0 .../mmrazor/configs/nas/mmcls/spos/SPOS_SUBNET.yaml | 0 .../spos/faster-rcnn_nas_backbone_fpn_1x_coco.py | 0 .../mmrazor/configs/nas/mmcls/spos/metafile.yml | 0 .../mmcls/spos/spos_mobilenet_search_8xb128_in1k.py | 0 .../mmcls/spos/spos_mobilenet_subnet_8xb128_in1k.py | 0 .../spos/spos_mobilenet_supernet_8xb128_in1k.py | 0 .../spos/spos_shufflenet_search_8xb128_in1k.py | 0 .../spos_shufflenet_search_predictor_8xb128_in1k.py | 0 .../spos/spos_shufflenet_subnet_8xb128_in1k.py | 0 .../spos/spos_shufflenet_supernet_8xb128_in1k.py | 0 .../configs/nas/mmdet/detnas/DETNAS_SUBNET.yaml | 0 .../mmrazor/configs/nas/mmdet/detnas/README.md | 0 .../detnas_frcnn_shufflenet_search_coco_1x.py | 0 .../detnas_frcnn_shufflenet_subnet_coco_1x.py | 0 .../detnas_frcnn_shufflenet_supernet_coco_1x.py | 0 .../detnas_retina_shufflenet_supernet_coco_1x.py | 0 .../detnas/detnas_shufflenet_subnet_8xb128_in1k.py | 0 .../detnas_shufflenet_supernet_8xb128_in1k.py | 0 .../mmrazor/configs/nas/mmdet/detnas/metafile.yml | 0 .../configs/pruning/base/group_fisher/README.md | 0 .../group_fisher/group_fisher_deploy_template.py | 0 .../group_fisher/group_fisher_finetune_template.py | 0 .../group_fisher/group_fisher_prune_template.py | 0 .../mmrazor/configs/pruning/mmcls/dcff/README.md | 0 .../mmcls/dcff/dcff_compact_resnet_8xb32_in1k.py | 0 .../pruning/mmcls/dcff/dcff_resnet_8xb32_in1k.py | 0 .../configs/pruning/mmcls/dcff/fix_subnet.json | 0 .../configs/pruning/mmcls/dmcp/DMCP_MBV2_100M.json | 0 .../configs/pruning/mmcls/dmcp/DMCP_R50_2G.json | 0 .../mmrazor/configs/pruning/mmcls/dmcp/README.md | 0 .../pruning/mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py | 0 .../pruning/mmcls/dmcp/dmcp_mbv2_supernet_32xb64.py | 0 .../mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py | 0 .../mmcls/dmcp/dmcp_resnet50_supernet_32xb64.py | 0 .../mmrazor/configs/pruning/mmcls/dmcp/metafile.yml | 0 .../configs/pruning/mmcls/group_fisher/README.md | 0 ...oup_fisher_act_deploy_mobilenet-v2_8xb32_in1k.py | 0 ...p_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py | 0 ...roup_fisher_act_prune_mobilenet-v2_8xb32_in1k.py | 0 ...p_fisher_flops_deploy_mobilenet-v2_8xb32_in1k.py | 0 ...fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py | 0 ...up_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py | 0 .../mmcls/group_fisher/mobilenet/metafile.yml | 0 .../pruning/mmcls/group_fisher/mobilenet/script.sh | 0 .../group_fisher_act_deploy_resnet50_8xb32_in1k.py | 0 ...group_fisher_act_finetune_resnet50_8xb32_in1k.py | 0 ..._fisher_act_finetune_resnet50_8xb32_in1k_dist.py | 0 .../group_fisher_act_prune_resnet50_8xb32_in1k.py | 0 ...group_fisher_flops_deploy_resnet50_8xb32_in1k.py | 0 ...oup_fisher_flops_finetune_resnet50_8xb32_in1k.py | 0 .../group_fisher_flops_prune_resnet50_8xb32_in1k.py | 0 .../mmcls/group_fisher/resnet50/metafile.yml | 0 .../pruning/mmcls/group_fisher/resnet50/script.sh | 0 .../mmrazor/configs/pruning/mmcls/l1-norm/README.md | 0 .../mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py | 0 .../l1-norm/l1-norm_resnet34_8xb32_in1k_a_deploy.py | 0 .../mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b.py | 0 .../l1-norm/l1-norm_resnet34_8xb32_in1k_b_deploy.py | 0 .../mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c.py | 0 .../l1-norm/l1-norm_resnet34_8xb32_in1k_c_deploy.py | 0 .../configs/pruning/mmcls/l1-norm/metafile.yml | 0 .../mmrazor/configs/pruning/mmcls/l1-norm/script.sh | 0 .../mmrazor/configs/pruning/mmdet/dcff/README.md | 0 .../dcff_compact_faster_rcnn_resnet50_8xb4_coco.py | 0 .../dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py | 0 .../mmdet/dcff/dcff_faster_rcnn_resnet50_fpn.py | 0 .../configs/pruning/mmdet/dcff/fix_subnet.json | 0 .../configs/pruning/mmdet/group_fisher/README.md | 0 ...p_fisher_act_deploy_retinanet_r50_fpn_1x_coco.py | 0 ...fisher_act_finetune_retinanet_r50_fpn_1x_coco.py | 0 ...up_fisher_act_prune_retinanet_r50_fpn_1x_coco.py | 0 ...fisher_flops_deploy_retinanet_r50_fpn_1x_coco.py | 0 ...sher_flops_finetune_retinanet_r50_fpn_1x_coco.py | 0 ..._fisher_flops_prune_retinanet_r50_fpn_1x_coco.py | 0 .../mmdet/group_fisher/retinanet/metafile.yml | 0 .../pruning/mmdet/group_fisher/retinanet/script.sh | 0 .../mmrazor/configs/pruning/mmpose/dcff/README.md | 0 .../dcff_compact_topdown_heatmap_resnet50_coco.py | 0 .../dcff/dcff_topdown_heatmap_resnet50_coco.py | 0 .../configs/pruning/mmpose/dcff/fix_subnet.json | 0 ...deploy_rtmpose-s_8xb256-420e_aic-coco-256x192.py | 0 ...her_deploy_rtmpose-s_8xb256-420e_coco-256x192.py | 0 ...netune_rtmpose-s_8xb256-420e_aic-coco-256x192.py | 0 ...r_finetune_rtmpose-s_8xb256-420e_coco-256x192.py | 0 ..._prune_rtmpose-s_8xb256-420e_aic-coco-256x192.py | 0 ...sher_prune_rtmpose-s_8xb256-420e_coco-256x192.py | 0 .../configs/pruning/mmpose/group_fisher/script.sh | 0 .../mmrazor/configs/pruning/mmseg/dcff/README.md | 0 ...ff_compact_pointrend_resnet50_8xb2_cityscapes.py | 0 .../dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py | 0 .../configs/pruning/mmseg/dcff/fix_subnet.json | 0 .../pruning/mmseg/dcff/pointrend_resnet50.py | 0 .../classification_openvino_dynamic-224x224.py | 0 ...cation_tensorrt-int8-explicit_dynamic-224x224.py | 0 .../mmdet/detection_openvino_dynamic-800x1344.py | 0 ...sorrt-int8-explicit_dynamic-320x320-1344x1344.py | 0 .../mmrazor/configs/quantization/ptq/base/README.md | 0 .../configs/quantization/ptq/base/metafile.yml | 0 .../ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py | 0 .../ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py | 0 .../ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py | 0 .../ptq_openvino_retina_r50_1x_coco_calib32xb32.py | 0 ...q_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py | 0 .../ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py | 0 .../ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py | 0 .../ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py | 0 .../ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py | 0 ...q_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py | 0 .../mmrazor/configs/quantization/qat/base/README.md | 0 .../configs/quantization/qat/base/metafile.yml | 0 .../base/qat_openvino_resnet18_10e_8xb32_in1k.py | 0 .../mmrazor/configs/quantization/qat/lsq/README.md | 0 .../lsq/lsq_openvino_resnet18_8xb32_100e_in1k.py | 0 .../qat/lsq/lsq_openvino_resnet18_8xb32_10e_in1k.py | 0 .../configs/quantization/qat/lsq/metafile.yml | 0 .../configs/vanilla/mmcls/wide-resnet/README.md | 0 .../mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py | 0 .../mmcls/wide-resnet/wrn22-w4_b16x8_cifar10.py | 0 .../mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py | 0 .../mmcls/wide-resnet/wrn40-w2_b16x8_cifar10.py | 0 .../CWD/{ => pytorch}/mmrazor/mmrazor/__init__.py | 0 .../mmrazor/mmrazor/datasets/__init__.py | 0 .../mmrazor/mmrazor/datasets/crd_dataset_wrapper.py | 0 .../mmrazor/mmrazor/datasets/transforms/__init__.py | 0 .../mmrazor/datasets/transforms/auto_augment.py | 0 .../mmrazor/datasets/transforms/auto_augmentv2.py | 0 .../mmrazor/datasets/transforms/formatting.py | 0 .../mmrazor/mmrazor/engine/__init__.py | 0 .../mmrazor/mmrazor/engine/hooks/__init__.py | 0 .../mmrazor/engine/hooks/dmcp_subnet_hook.py | 0 .../mmrazor/engine/hooks/dump_subnet_hook.py | 0 .../mmrazor/engine/hooks/estimate_resources_hook.py | 0 .../mmrazor/engine/hooks/group_fisher_hooks.py | 0 .../mmrazor/engine/hooks/stop_distillation_hook.py | 0 .../mmrazor/engine/hooks/visualization_hook.py | 0 .../mmrazor/mmrazor/engine/optimizers/__init__.py | 0 .../engine/optimizers/optimizer_constructor.py | 0 .../mmrazor/mmrazor/engine/runner/__init__.py | 0 .../engine/runner/autoslim_greedy_search_loop.py | 0 .../mmrazor/mmrazor/engine/runner/darts_loop.py | 0 .../mmrazor/engine/runner/distill_val_loop.py | 0 .../mmrazor/engine/runner/evolution_search_loop.py | 0 .../mmrazor/engine/runner/iteprune_val_loop.py | 0 .../mmrazor/engine/runner/quantization_loops.py | 0 .../mmrazor/engine/runner/slimmable_val_loop.py | 0 .../mmrazor/engine/runner/subnet_sampler_loop.py | 0 .../mmrazor/engine/runner/subnet_val_loop.py | 0 .../mmrazor/mmrazor/engine/runner/utils/__init__.py | 0 .../engine/runner/utils/calibrate_bn_mixin.py | 0 .../mmrazor/mmrazor/engine/runner/utils/check.py | 0 .../mmrazor/mmrazor/engine/runner/utils/genetic.py | 0 .../mmrazor/mmrazor/implementations/__init__.py | 0 .../mmrazor/implementations/pruning/__init__.py | 0 .../pruning/group_fisher/__init__.py | 0 .../pruning/group_fisher/algorithm.py | 0 .../pruning/group_fisher/counters.py | 0 .../implementations/pruning/group_fisher/hook.py | 0 .../implementations/pruning/group_fisher/mutator.py | 0 .../implementations/pruning/group_fisher/ops.py | 0 .../pruning/group_fisher/prune_deploy_sub_model.py | 0 .../pruning/group_fisher/prune_sub_model.py | 0 .../implementations/pruning/group_fisher/unit.py | 0 .../mmrazor/mmrazor/models/__init__.py | 0 .../mmrazor/mmrazor/models/algorithms/__init__.py | 0 .../mmrazor/mmrazor/models/algorithms/base.py | 0 .../mmrazor/models/algorithms/distill/__init__.py | 0 .../algorithms/distill/configurable/__init__.py | 0 .../distill/configurable/datafree_distillation.py | 0 .../distill/configurable/fpn_teacher_distill.py | 0 .../configurable/overhaul_feature_distillation.py | 0 .../algorithms/distill/configurable/self_distill.py | 0 .../distill/configurable/single_teacher_distill.py | 0 .../mmrazor/models/algorithms/nas/__init__.py | 0 .../mmrazor/models/algorithms/nas/autoformer.py | 0 .../mmrazor/models/algorithms/nas/autoslim.py | 0 .../mmrazor/mmrazor/models/algorithms/nas/bignas.py | 0 .../mmrazor/mmrazor/models/algorithms/nas/darts.py | 0 .../mmrazor/mmrazor/models/algorithms/nas/dsnas.py | 0 .../mmrazor/mmrazor/models/algorithms/nas/spos.py | 0 .../mmrazor/models/algorithms/pruning/__init__.py | 0 .../mmrazor/models/algorithms/pruning/dcff.py | 0 .../mmrazor/models/algorithms/pruning/dmcp.py | 0 .../algorithms/pruning/group_fisher_algoritho.py | 0 .../algorithms/pruning/ite_prune_algorithm.py | 0 .../models/algorithms/pruning/slimmable_network.py | 0 .../models/algorithms/quantization/__init__.py | 0 .../algorithms/quantization/mm_architecture.py | 0 .../mmrazor/models/architectures/__init__.py | 0 .../models/architectures/backbones/__init__.py | 0 .../architectures/backbones/darts_backbone.py | 0 .../backbones/searchable_autoformer.py | 0 .../backbones/searchable_mobilenet_v2.py | 0 .../backbones/searchable_mobilenet_v3.py | 0 .../backbones/searchable_shufflenet_v2.py | 0 .../models/architectures/backbones/wideresnet.py | 0 .../models/architectures/classifiers/__init__.py | 0 .../models/architectures/classifiers/image.py | 0 .../models/architectures/connectors/__init__.py | 0 .../architectures/connectors/base_connector.py | 0 .../architectures/connectors/byot_connector.py | 0 .../connectors/convmodule_connector.py | 0 .../architectures/connectors/crd_connector.py | 0 .../connectors/factor_transfer_connectors.py | 0 .../architectures/connectors/fbkd_connector.py | 0 .../architectures/connectors/mgd_connector.py | 0 .../architectures/connectors/norm_connector.py | 0 .../architectures/connectors/ofd_connector.py | 0 .../architectures/connectors/torch_connector.py | 0 .../models/architectures/dynamic_ops/__init__.py | 0 .../architectures/dynamic_ops/bricks/__init__.py | 0 .../dynamic_ops/bricks/dynamic_container.py | 0 .../dynamic_ops/bricks/dynamic_conv.py | 0 .../dynamic_ops/bricks/dynamic_embed.py | 0 .../dynamic_ops/bricks/dynamic_function.py | 0 .../dynamic_ops/bricks/dynamic_linear.py | 0 .../bricks/dynamic_multi_head_attention.py | 0 .../dynamic_ops/bricks/dynamic_norm.py | 0 .../dynamic_ops/bricks/dynamic_relative_position.py | 0 .../dynamic_ops/bricks/group_fisher_ops.py | 0 .../architectures/dynamic_ops/head/__init__.py | 0 .../dynamic_ops/head/dynamic_linear_head.py | 0 .../architectures/dynamic_ops/mixins/__init__.py | 0 .../dynamic_ops/mixins/dynamic_conv_mixins.py | 0 .../dynamic_ops/mixins/dynamic_layernorm_mixins.py | 0 .../dynamic_ops/mixins/dynamic_mixins.py | 0 .../models/architectures/generators/__init__.py | 0 .../architectures/generators/base_generator.py | 0 .../architectures/generators/dafl_generator.py | 0 .../architectures/generators/zskt_generator.py | 0 .../mmrazor/models/architectures/heads/__init__.py | 0 .../models/architectures/heads/darts_subnet_head.py | 0 .../mmrazor/models/architectures/heads/deit_head.py | 0 .../mmrazor/models/architectures/necks/__init__.py | 0 .../architectures/necks/squeezemean_with_dropout.py | 0 .../mmrazor/models/architectures/ops/__init__.py | 0 .../mmrazor/models/architectures/ops/base.py | 0 .../mmrazor/models/architectures/ops/common.py | 0 .../models/architectures/ops/darts_series.py | 0 .../models/architectures/ops/efficientnet_series.py | 0 .../mmrazor/models/architectures/ops/function.py | 0 .../models/architectures/ops/gather_tensors.py | 0 .../models/architectures/ops/mobilenet_series.py | 0 .../models/architectures/ops/shufflenet_series.py | 0 .../models/architectures/ops/transformer_series.py | 0 .../mmrazor/models/architectures/utils/__init__.py | 0 .../models/architectures/utils/mutable_register.py | 0 .../models/architectures/utils/set_dropout.py | 0 .../mmrazor/mmrazor/models/distillers/__init__.py | 0 .../mmrazor/models/distillers/base_distiller.py | 0 .../mmrazor/models/distillers/byot_distiller.py | 0 .../models/distillers/configurable_distiller.py | 0 .../mmrazor/models/distillers/ofd_distiller.py | 0 .../mmrazor/mmrazor/models/fake_quants/__init__.py | 0 .../mmrazor/mmrazor/models/fake_quants/base.py | 0 .../mmrazor/mmrazor/models/fake_quants/lsq.py | 0 .../mmrazor/models/fake_quants/torch_fake_quants.py | 0 .../mmrazor/mmrazor/models/losses/__init__.py | 0 .../mmrazor/mmrazor/models/losses/ab_loss.py | 0 .../mmrazor/mmrazor/models/losses/at_loss.py | 0 .../mmrazor/mmrazor/models/losses/crd_loss.py | 0 .../mmrazor/models/losses/cross_entropy_loss.py | 0 .../mmrazor/mmrazor/models/losses/cwd.py | 0 .../mmrazor/mmrazor/models/losses/dafl_loss.py | 0 .../mmrazor/mmrazor/models/losses/decoupled_kd.py | 0 .../mmrazor/mmrazor/models/losses/dist_loss.py | 0 .../mmrazor/models/losses/factor_transfer_loss.py | 0 .../mmrazor/mmrazor/models/losses/fbkd_loss.py | 0 .../mmrazor/models/losses/kd_soft_ce_loss.py | 0 .../mmrazor/mmrazor/models/losses/kl_divergence.py | 0 .../mmrazor/mmrazor/models/losses/l1_loss.py | 0 .../mmrazor/mmrazor/models/losses/l2_loss.py | 0 .../mmrazor/mmrazor/models/losses/mgd_loss.py | 0 .../mmrazor/mmrazor/models/losses/ofd_loss.py | 0 .../mmrazor/mmrazor/models/losses/pkd_loss.py | 0 .../mmrazor/mmrazor/models/losses/relational_kd.py | 0 .../losses/weighted_soft_label_distillation.py | 0 .../mmrazor/mmrazor/models/mutables/__init__.py | 0 .../mmrazor/mmrazor/models/mutables/base_mutable.py | 0 .../mmrazor/models/mutables/derived_mutable.py | 0 .../mutables/mutable_channel/MutableChannel.md | 0 .../models/mutables/mutable_channel/__init__.py | 0 .../mutable_channel/base_mutable_channel.py | 0 .../mutable_channel/mutable_channel_container.py | 0 .../mutable_channel/oneshot_mutable_channel.py | 0 .../mutable_channel/sequential_mutable_channel.py | 0 .../mutable_channel/simple_mutable_channel.py | 0 .../mutables/mutable_channel/units/__init__.py | 0 .../mutables/mutable_channel/units/channel_unit.py | 0 .../mutable_channel/units/dcff_channel_unit.py | 0 .../mutable_channel/units/dmcp_channel_unit.py | 0 .../mutable_channel/units/group_fisher_unit.py | 0 .../units/l1_mutable_channel_unit.py | 0 .../units/mutable_channel_unit.ipynb | 0 .../mutable_channel/units/mutable_channel_unit.py | 0 .../units/one_shot_mutable_channel_unit.py | 0 .../units/sequential_mutable_channel_unit.py | 0 .../mutable_channel/units/slimmable_channel_unit.py | 0 .../models/mutables/mutable_channel/units/utils.py | 0 .../models/mutables/mutable_module/__init__.py | 0 .../mutables/mutable_module/diff_mutable_module.py | 0 .../mutables/mutable_module/mutable_module.py | 0 .../mutable_module/one_shot_mutable_module.py | 0 .../models/mutables/mutable_value/__init__.py | 0 .../models/mutables/mutable_value/mutable_value.py | 0 .../mmrazor/mmrazor/models/mutators/__init__.py | 0 .../mmrazor/mmrazor/models/mutators/base_mutator.py | 0 .../models/mutators/channel_mutator/__init__.py | 0 .../mutators/channel_mutator/channel_mutator.ipynb | 0 .../mutators/channel_mutator/channel_mutator.py | 0 .../channel_mutator/dcff_channel_mutator.py | 0 .../channel_mutator/dmcp_channel_mutator.py | 0 .../channel_mutator/group_fisher_mutator.py | 0 .../channel_mutator/one_shot_channel_mutator.py | 0 .../channel_mutator/slimmable_channel_mutator.py | 0 .../mmrazor/mmrazor/models/mutators/group_mixin.py | 0 .../mmrazor/mmrazor/models/mutators/nas_mutator.py | 0 .../mmrazor/mmrazor/models/observers/__init__.py | 0 .../mmrazor/mmrazor/models/observers/base.py | 0 .../mmrazor/mmrazor/models/observers/lsq.py | 0 .../mmrazor/models/observers/torch_observers.py | 0 .../mmrazor/mmrazor/models/quantizers/__init__.py | 0 .../mmrazor/models/quantizers/academic_quantizer.py | 0 .../mmrazor/mmrazor/models/quantizers/base.py | 0 .../mmrazor/models/quantizers/exporters/__init__.py | 0 .../quantizers/exporters/base_quantize_exporter.py | 0 .../exporters/openvino_quantize_exporter.py | 0 .../models/quantizers/exporters/optim_utils.py | 0 .../exporters/tensorrt_quantize_exporter.py | 0 .../mmrazor/models/quantizers/native_quantizer.py | 0 .../mmrazor/models/quantizers/openvino_quantizer.py | 0 .../mmrazor/models/quantizers/tensorrt_quantizer.py | 0 .../mmrazor/mmrazor/models/task_modules/__init__.py | 0 .../models/task_modules/delivery/__init__.py | 0 .../task_modules/delivery/delivery_manager.py | 0 .../task_modules/delivery/distill_delivery.py | 0 .../delivery/function_outputs_delivery.py | 0 .../delivery/method_outputs_delivery.py | 0 .../models/task_modules/demo_inputs/__init__.py | 0 .../task_modules/demo_inputs/default_demo_inputs.py | 0 .../models/task_modules/demo_inputs/demo_inputs.py | 0 .../task_modules/demo_inputs/mmpose_demo_input.py | 0 .../task_modules/demo_inputs/mmseg_demo_input.py | 0 .../models/task_modules/estimators/__init__.py | 0 .../task_modules/estimators/base_estimator.py | 0 .../task_modules/estimators/counters/__init__.py | 0 .../estimators/counters/flops_params_counter.py | 0 .../estimators/counters/latency_counter.py | 0 .../estimators/counters/op_counters/__init__.py | 0 .../op_counters/activation_layer_counter.py | 0 .../estimators/counters/op_counters/base_counter.py | 0 .../counters/op_counters/conv_layer_counter.py | 0 .../counters/op_counters/deconv_layer_counter.py | 0 .../counters/op_counters/group_fisher_counters.py | 0 .../counters/op_counters/linear_layer_counter.py | 0 .../counters/op_counters/norm_layer_counter.py | 0 .../counters/op_counters/pooling_layer_counter.py | 0 .../counters/op_counters/upsample_layer_counter.py | 0 .../task_modules/estimators/resource_estimator.py | 0 .../models/task_modules/predictor/__init__.py | 0 .../task_modules/predictor/handler/__init__.py | 0 .../task_modules/predictor/handler/base_handler.py | 0 .../task_modules/predictor/handler/carts_handler.py | 0 .../task_modules/predictor/handler/gp_handler.py | 0 .../task_modules/predictor/handler/mlp_handler.py | 0 .../task_modules/predictor/handler/rbf_handler.py | 0 .../task_modules/predictor/metric_predictor.py | 0 .../models/task_modules/recorder/__init__.py | 0 .../models/task_modules/recorder/base_recorder.py | 0 .../recorder/function_inputs_recorder.py | 0 .../recorder/function_outputs_recorder.py | 0 .../task_modules/recorder/method_inputs_recorder.py | 0 .../recorder/method_outputs_recorder.py | 0 .../task_modules/recorder/module_inputs_recorder.py | 0 .../recorder/module_outputs_recorder.py | 0 .../models/task_modules/recorder/param_recorder.py | 0 .../task_modules/recorder/recorder_manager.py | 0 .../mmrazor/models/task_modules/tracer/__init__.py | 0 .../models/task_modules/tracer/backward_tracer.py | 0 .../models/task_modules/tracer/channel_analyzer.py | 0 .../models/task_modules/tracer/fx/__init__.py | 0 .../models/task_modules/tracer/fx/custom_tracer.py | 0 .../models/task_modules/tracer/fx/graph_utils.py | 0 .../mmrazor/models/task_modules/tracer/fx_tracer.py | 0 .../task_modules/tracer/loss_calculator/__init__.py | 0 .../cascade_encoder_decoder_loss_calculator.py | 0 .../image_classifier_loss_calculator.py | 0 .../single_stage_detector_loss_calculator.py | 0 .../tracer/loss_calculator/sum_loss_calculator.py | 0 .../top_down_pose_estimator_loss_calculator.py | 0 .../two_stage_detector_loss_calculator.py | 0 .../mmrazor/models/task_modules/tracer/parsers.py | 0 .../mmrazor/models/task_modules/tracer/path.py | 0 .../mmrazor/mmrazor/models/utils/__init__.py | 0 .../models/utils/expandable_utils/__init__.py | 0 .../mmrazor/models/utils/expandable_utils/ops.py | 0 .../mmrazor/models/utils/expandable_utils/tools.py | 0 .../mmrazor/models/utils/expandable_utils/unit.py | 0 .../mmrazor/mmrazor/models/utils/make_divisible.py | 0 .../mmrazor/mmrazor/models/utils/misc.py | 0 .../mmrazor/mmrazor/models/utils/optim_wrapper.py | 0 .../mmrazor/mmrazor/models/utils/parse_values.py | 0 .../mmrazor/models/utils/quantization_util.py | 0 .../mmrazor/mmrazor/models/utils/utils.py | 0 .../mmrazor/mmrazor/registry/__init__.py | 0 .../mmrazor/mmrazor/registry/registry.py | 0 .../mmrazor/mmrazor/structures/__init__.py | 0 .../mmrazor/mmrazor/structures/graph/__init__.py | 0 .../mmrazor/mmrazor/structures/graph/base_graph.py | 0 .../mmrazor/structures/graph/channel_flow.py | 0 .../mmrazor/structures/graph/channel_graph.py | 0 .../mmrazor/structures/graph/channel_nodes.py | 0 .../mmrazor/structures/graph/module_graph.py | 0 .../mmrazor/structures/graph/pseudo_fx_graph.py | 0 .../mmrazor/structures/quantization/__init__.py | 0 .../quantization/backend_config/__init__.py | 0 .../quantization/backend_config/academic.py | 0 .../backend_config/common_operator_config_utils.py | 0 .../quantization/backend_config/mapping.py | 0 .../quantization/backend_config/native.py | 0 .../quantization/backend_config/openvino.py | 0 .../quantization/backend_config/tensorrt.py | 0 .../mmrazor/structures/quantization/qconfig.py | 0 .../mmrazor/mmrazor/structures/subnet/__init__.py | 0 .../mmrazor/mmrazor/structures/subnet/candidate.py | 0 .../mmrazor/mmrazor/structures/subnet/fix_subnet.py | 0 .../mmrazor/mmrazor/testing/__init__.py | 0 .../mmrazor/testing/_fast_stop_training_hook.py | 0 .../mmrazor/mmrazor/testing/_fx_models.py | 0 .../{ => pytorch}/mmrazor/mmrazor/utils/__init__.py | 0 .../mmrazor/mmrazor/utils/index_dict.py | 0 .../mmrazor/mmrazor/utils/log_tools.py | 0 .../CWD/{ => pytorch}/mmrazor/mmrazor/utils/misc.py | 0 .../mmrazor/mmrazor/utils/placeholder.py | 0 .../mmrazor/mmrazor/utils/runtime_info.py | 0 .../mmrazor/mmrazor/utils/setup_env.py | 0 .../{ => pytorch}/mmrazor/mmrazor/utils/typing.py | 0 .../CWD/{ => pytorch}/mmrazor/mmrazor/version.py | 0 .../mmrazor/mmrazor/visualization/__init__.py | 0 .../mmrazor/visualization/local_visualizer.py | 0 .../CWD/{ => pytorch}/mmrazor/model-index.yml | 0 .../CWD/{ => pytorch}/mmrazor/requirements.txt | 0 .../CWD/{ => pytorch}/mmrazor/requirements/docs.txt | 0 .../mmrazor/requirements/mminstall.txt | 0 .../{ => pytorch}/mmrazor/requirements/optional.txt | 0 .../mmrazor/requirements/readthedocs.txt | 0 .../{ => pytorch}/mmrazor/requirements/runtime.txt | 0 .../{ => pytorch}/mmrazor/requirements/tests.txt | 0 .../mmrazor/resources/design_and_implement.png | Bin .../mmrazor/resources/mmrazor-logo.png | Bin .../mmrazor/resources/qq_group_qrcode.jpg | Bin .../resources/xiaozhushou_weixin_qrcode.jpeg | Bin .../mmrazor/resources/zhihu_qrcode.jpg | Bin cv/distiller/CWD/{ => pytorch}/mmrazor/setup.cfg | 0 cv/distiller/CWD/{ => pytorch}/mmrazor/setup.py | 0 .../CWD/{ => pytorch}/mmrazor/tests/__init__.py | 0 .../{ => pytorch}/mmrazor/tests/data/MBV2_220M.yaml | 0 .../{ => pytorch}/mmrazor/tests/data/MBV2_320M.yaml | 0 .../{ => pytorch}/mmrazor/tests/data/MBV2_530M.yaml | 0 .../tests/data/MBV2_slimmable_channel_config.json | 0 .../mmrazor/tests/data/MBV2_slimmable_config.json | 0 .../{ => pytorch}/mmrazor/tests/data/__init__.py | 0 .../CWD/{ => pytorch}/mmrazor/tests/data/color.jpeg | Bin .../mmrazor/tests/data/concat_subnet1.yaml | 0 .../mmrazor/tests/data/concat_subnet2.yaml | 0 .../mmrazor/tests/data/dataset/a/1.JPG | 0 .../mmrazor/tests/data/dataset/ann.json | 0 .../mmrazor/tests/data/dataset/ann.txt | 0 .../mmrazor/tests/data/dataset/b/2.jpeg | 0 .../mmrazor/tests/data/dataset/b/subb/3.jpg | 0 .../mmrazor/tests/data/dataset/classes.txt | 0 .../mmrazor/tests/data/dataset/multi_label_ann.json | 0 .../mmrazor/tests/data/model_library.py | 0 .../CWD/{ => pytorch}/mmrazor/tests/data/models.py | 0 .../{ => pytorch}/mmrazor/tests/data/subnet1.yaml | 0 .../{ => pytorch}/mmrazor/tests/data/subnet2.yaml | 0 .../data/test_models/test_algorithm/MBV2_220M.yaml | 0 .../data/test_models/test_mutator/subnet1.json | 0 .../test_models/test_subnet/mockmodel_subnet.yaml | 0 .../data/test_models/test_task_modules/mmcls_cfg.py | 0 .../test_registry/registry_architecture_config.py | 0 .../data/test_registry/registry_subnet_config.py | 0 .../mmrazor/tests/data/test_registry/subnet.json | 0 .../mmrazor/tests/data/tracer_passed_models.py | 0 .../mmrazor/tests/test_core/__init__.py | 0 .../test_core/test_delivers/test_deliver_manager.py | 0 .../test_delivers/test_function_outputs_deliver.py | 0 .../test_delivers/test_method_outputs_deliver.py | 0 .../tests/test_core/test_delivers/toy_module.py | 0 .../mmrazor/tests/test_core/test_graph/__init__.py | 0 .../tests/test_core/test_graph/test_channel_flow.py | 0 .../test_core/test_graph/test_channel_graph.py | 0 .../tests/test_core/test_graph/test_graph.py | 0 .../test_core/test_graph/test_prune_tracer_model.py | 0 .../test_core/test_recorders/test_base_recorder.py | 0 .../test_recorders/test_func_inputs_recorder.py | 0 .../test_recorders/test_func_outputs_recorder.py | 0 .../test_recorders/test_method_inputs_recorder.py | 0 .../test_recorders/test_method_outputs_recorder.py | 0 .../test_recorders/test_module_recorders.py | 0 .../test_core/test_recorders/test_param_recorder.py | 0 .../test_recorders/test_recorder_manager.py | 0 .../tests/test_core/test_recorders/toy_mod.py | 0 .../mmrazor/tests/test_core/test_tracer/__init__.py | 0 .../test_core/test_tracer/test_backward_tracer.py | 0 .../tests/test_core/test_tracer/test_fx_tracer.py | 0 .../test_core/test_tracer/test_loss_calculator.py | 0 .../test_core/test_tracer/test_prune_tracer.py | 0 .../CWD/{ => pytorch}/mmrazor/tests/test_data.py | 0 .../mmrazor/tests/test_datasets/test_datasets.py | 0 .../test_transforms/test_formatting.py | 0 .../CWD/{ => pytorch}/mmrazor/tests/test_doc.py | 0 .../test_hooks/test_stop_distillation_hook.py | 0 .../test_hooks/test_visualization_hook.py | 0 .../mmrazor/tests/test_impl/__init__.py | 0 .../tests/test_impl/test_pruning/__init__.py | 0 .../test_pruning/test_group_fisher/__init__.py | 0 .../test_group_fisher/test_algorithm.py | 0 .../test_prune_deploy_sub_model.py | 0 .../test_group_fisher/test_prune_sub_model.py | 0 .../test_pruning/test_group_fisher/test_unit.py | 0 .../mmrazor/tests/test_models/__init__.py | 0 .../tests/test_models/test_algorithms/__init__.py | 0 .../test_models/test_algorithms/test_autoformer.py | 0 .../test_models/test_algorithms/test_autoslim.py | 0 .../test_algorithms/test_base_algorithm.py | 0 .../test_models/test_algorithms/test_bignas.py | 0 .../tests/test_models/test_algorithms/test_darts.py | 0 .../test_algorithms/test_datafree_distill.py | 0 .../test_algorithms/test_dcff_network.py | 0 .../tests/test_models/test_algorithms/test_dmcp.py | 0 .../tests/test_models/test_algorithms/test_dsnas.py | 0 .../test_algorithms/test_general_quant.py | 0 .../test_algorithms/test_mm_architecture.py | 0 .../test_models/test_algorithms/test_ofd_algo.py | 0 .../test_algorithms/test_prune_algorithm.py | 0 .../test_algorithms/test_self_distill.py | 0 .../test_algorithms/test_single_teacher_distill.py | 0 .../test_algorithms/test_slimmable_network.py | 0 .../tests/test_models/test_algorithms/test_spos.py | 0 .../tests/test_models/test_algorithms/toy_models.py | 0 .../test_backbones/test_autoformerbackbone.py | 0 .../test_backbones/test_dartsbackbone.py | 0 .../test_backbones/test_searchable_mobilenet_v2.py | 0 .../test_backbones/test_searchable_mobilenet_v3.py | 0 .../test_backbones/test_searchable_shufflenet_v2.py | 0 .../test_architectures/test_backbones/utils.py | 0 .../test_connectors/test_connectors.py | 0 .../test_architectures/test_dynamic_op/__init__.py | 0 .../test_dynamic_op/test_bricks/__init__.py | 0 .../test_bricks/test_dynamic_attention.py | 0 .../test_bricks/test_dynamic_container.py | 0 .../test_bricks/test_dynamic_conv.py | 0 .../test_bricks/test_dynamic_embed.py | 0 .../test_bricks/test_dynamic_layernorm.py | 0 .../test_bricks/test_dynamic_linear.py | 0 .../test_bricks/test_dynamic_norm.py | 0 .../test_bricks/test_dynamic_relative_position.py | 0 .../test_bricks/test_dynamic_resizer.py | 0 .../test_architectures/test_dynamic_op/utils.py | 0 .../test_generators/test_generators.py | 0 .../test_classifier/test_imageclassifier.py | 0 .../test_distillers/test_byot_distill.py | 0 .../test_distillers/test_configurable_distill.py | 0 .../test_fake_quants/test_lsq_fake_quants.py | 0 .../test_fake_quants/test_torch_fake_quants.py | 0 .../test_losses/test_distillation_losses.py | 0 .../test_models/test_losses/test_general_losses.py | 0 .../tests/test_models/test_mutables/__init__.py | 0 .../test_mutables/test_derived_mutable.py | 0 .../test_mutables/test_diffchoiceroute.py | 0 .../tests/test_models/test_mutables/test_diffop.py | 0 .../test_mutables/test_gumbelchoiceroute.py | 0 .../test_mutables/test_mutable_channel/__init__.py | 0 .../test_mutable_channel/test_mutable_channels.py | 0 .../test_sequential_mutable_channel.py | 0 .../test_mutable_channel/test_units/__init__.py | 0 .../test_units/test_dcff_channel_unit.py | 0 .../test_units/test_l1_mutable_channel_unit.py | 0 .../test_units/test_mutable_channel_units.py | 0 .../test_one_shot_mutable_channel_unit.py | 0 .../test_sequential_mutable_channel_unit.py | 0 .../test_models/test_mutables/test_mutable_value.py | 0 .../test_models/test_mutables/test_onehotop.py | 0 .../test_models/test_mutables/test_oneshotop.py | 0 .../test_sequential_mutable_channel.py | 0 .../tests/test_models/test_mutators/__init__.py | 0 .../test_mutators/test_channel_mutator.py | 0 .../test_models/test_mutators/test_dcff_mutator.py | 0 .../test_models/test_mutators/test_dmcp_mutator.py | 0 .../test_models/test_mutators/test_nas_mutator.py | 0 .../test_models/test_observers/test_lsq_observer.py | 0 .../test_observers/test_torch_observers.py | 0 .../test_quantizers/test_academic_quantizer.py | 0 .../test_models/test_quantizers/test_exporter.py | 0 .../test_quantizers/test_native_quantizer.py | 0 .../test_quantizers/test_openvino_quantizer.py | 0 .../test_quantizers/test_tensorrt_quantizer.py | 0 .../tests/test_models/test_subnet/test_candidate.py | 0 .../test_models/test_subnet/test_fix_subnet.py | 0 .../tests/test_models/test_task_modules/__init__.py | 0 .../test_task_modules/test_custom_tracer.py | 0 .../test_task_modules/test_demo_inputs/__init__.py | 0 .../test_demo_inputs/test_demo_inputs.py | 0 .../test_estimators/test_flops_params.py | 0 .../test_task_modules/test_graph_utils.py | 0 .../test_predictors/test_metric_predictor.py | 0 .../tests/test_models/test_utils/__init__.py | 0 .../test_utils/test_expandable_utils/__init__.py | 0 .../test_utils/test_expandable_utils/test_expand.py | 0 .../mmrazor/tests/test_registry/test_registry.py | 0 .../test_autoslim_greedy_search_loop.py | 0 .../mmrazor/tests/test_runners/test_darts_loop.py | 0 .../tests/test_runners/test_distill_val_loop.py | 0 .../test_runners/test_evolution_search_loop.py | 0 .../tests/test_runners/test_quantization_loop.py | 0 .../tests/test_runners/test_subnet_sampler_loop.py | 0 .../test_utils/test_calibrate_bn_mixin.py | 0 .../tests/test_runners/test_utils/test_check.py | 0 .../tests/test_runners/test_utils/test_genetic.py | 0 .../tests/test_structures/test_backendconfig.py | 0 .../mmrazor/tests/test_structures/test_qconfig.py | 0 .../mmrazor/tests/test_tools/__init__.py | 0 .../mmrazor/tests/test_tools/test_tools.py | 0 .../mmrazor/tests/test_utils/test_index_dict.py | 0 .../mmrazor/tests/test_utils/test_placeholder.py | 0 .../tests/test_visualizer/test_visualizer.py | 0 .../{ => pytorch}/mmrazor/tests/utils/__init__.py | 0 .../mmrazor/tests/utils/set_dist_env.py | 0 .../mmrazor/tests/utils/set_torch_thread.py | 0 .../mmrazor/tools/dataset_converters/cityscapes.py | 0 .../CWD/{ => pytorch}/mmrazor/tools/dist_test.sh | 0 .../CWD/{ => pytorch}/mmrazor/tools/dist_train.sh | 0 .../mmrazor/tools/misc/print_config.py | 0 .../convert_attentivenas_nas_ckpt.py | 0 .../model_converters/convert_bignas_gml_ckpt.py | 0 .../tools/model_converters/convert_kd_ckpt.py | 0 .../model_converters/convert_kd_ckpt_to_student.py | 0 .../tools/model_converters/convert_ofa_ckpt.py | 0 .../tools/model_converters/convert_quant_ckpt.py | 0 .../model_converters/convert_supernet2subnet.py | 0 .../mmrazor/tools/model_converters/publish_model.py | 0 .../mmrazor/tools/pruning/get_channel_units.py | 0 .../mmrazor/tools/pruning/get_flops.py | 0 .../mmrazor/tools/pruning/get_l1_prune_config.py | 0 .../pruning/get_static_model_from_algorithm.py | 0 cv/distiller/CWD/{ => pytorch}/mmrazor/tools/ptq.py | 0 .../CWD/{ => pytorch}/mmrazor/tools/slurm_test.sh | 0 .../CWD/{ => pytorch}/mmrazor/tools/slurm_train.sh | 0 .../CWD/{ => pytorch}/mmrazor/tools/test.py | 0 .../CWD/{ => pytorch}/mmrazor/tools/train.py | 0 .../mmrazor/tools/visualizations/demo.jpg | Bin .../visualizations/feature_diff_visualization.py | 0 .../tools/visualizations/feature_visualization.py | 0 .../backbone_feature_diff_visualization.py | 0 .../vis_configs/backbone_feature_visualization.py | 0 .../vis_configs/fpn_feature_diff_visualization.py | 0 .../vis_configs/fpn_feature_visualization.py | 0 .../mmrazor/tools/visualizations/vis_scheduler.py | 0 1580 files changed, 0 insertions(+), 0 deletions(-) rename cv/distiller/CWD/{ => pytorch}/README.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/.dockerignore (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/.pre-commit-config.yaml (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/.readthedocs.yml (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/CITATION.cff (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/CONTRIBUTING.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/CONTRIBUTING_zh-CN.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/Jenkinsfile (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/LICENSE (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/LICENSES.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/MANIFEST.in (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/README.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/README_zh-CN.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/TERMINOLOGY.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/build_mmcv.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmcv/clean_mmcv.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmcv/docker/README.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docker/dev/Dockerfile (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docker/release/Dockerfile (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/Makefile (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/community/1.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/community/2.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/community/3.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/css/readthedocs.css (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/flow_img2toimg1.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/flow_raw_images.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/flow_visualization.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/flow_warp.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/flow_warp_diff.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/image/mmcv-logo.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/parallel_progress.gif (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/parallel_progress.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/progress.gif (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/progress.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_static/version.json (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/_templates/classtemplate.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/api/arraymisc.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/api/cnn.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/api/image.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/api/ops.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/api/transforms.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/api/utils.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/api/video.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/api/visualization.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/community/contributing.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/community/pr.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/compatibility.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/conf.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/deployment/mmcv_ops_definition.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/docutils.conf (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/faq.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/get_started/build.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/get_started/installation.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/get_started/introduction.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/get_started/previous_versions.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/index.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/make.bat (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/mmcv-logo.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/switch_language.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/understand_mmcv/cnn.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/understand_mmcv/data_process.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/understand_mmcv/data_transform.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/understand_mmcv/ops.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/en/understand_mmcv/visualization.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/Makefile (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/_static/css/readthedocs.css (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/_static/image/mmcv-logo.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/_static/version.json (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/_templates/classtemplate.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/api/arraymisc.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/api/cnn.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/api/image.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/api/ops.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/api/transforms.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/api/utils.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/api/video.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/api/visualization.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/community/code_style.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/community/contributing.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/community/pr.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/compatibility.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/conf.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/docutils.conf (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/faq.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/get_started/article.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/get_started/build.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/get_started/installation.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/get_started/introduction.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/get_started/previous_versions.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/index.rst (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/make.bat (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/mmcv-logo.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/switch_language.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/understand_mmcv/cnn.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/understand_mmcv/data_process.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/understand_mmcv/data_transform.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/understand_mmcv/ops.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/docs/zh_cn/understand_mmcv/visualization.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/install_mmcv.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/__init__.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/arraymisc/__init__.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/arraymisc/quantization.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/__init__.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/alexnet.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/__init__.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/activation.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/context_block.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/conv.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/conv2d_adaptive_padding.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/conv_module.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/conv_ws.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/depthwise_separable_conv_module.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/drop.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/generalized_attention.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/hsigmoid.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/hswish.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/non_local.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/norm.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/padding.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/plugin.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/scale.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/swish.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/transformer.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/upsample.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/bricks/wrappers.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/resnet.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/utils/__init__.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/utils/flops_counter.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/utils/fuse_conv_bn.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/cnn/vgg.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/image/__init__.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/image/colorspace.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/image/geometric.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/image/io.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/image/misc.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/image/photometric.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/__init__.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/active_rotated_filter.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/assign_score_withk.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/ball_query.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/bbox.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/bezier_align.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/border_align.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/box_iou_quadri.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/box_iou_rotated.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/carafe.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/cc_attention.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/chamfer_distance.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/contour_expand.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/convex_iou.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/corner_pool.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/correlation.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/README.md (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/active_rotated_filter_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/assign_score_withk_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/ball_query_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/bbox_overlaps_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/bezier_align_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/border_align_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/box_iou_quadri_cuda.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/box_iou_rotated_cuda.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/carafe_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/carafe_naive_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/chamfer_distance_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/common_cuda_helper.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/convex_iou_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/correlation_cuda.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/deform_conv_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/deform_roi_pool_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/diff_iou_rotated_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/furthest_point_sample_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/gather_points_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/group_points_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/iou3d_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/knn_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/masked_conv2d_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/min_area_polygons_cuda.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/modulated_deform_conv_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/ms_deform_attn_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/nms_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/nms_quadri_cuda.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/nms_rotated_cuda.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/parrots_cudawarpfunction.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/points_in_boxes_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/points_in_polygons_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/prroi_pool_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/psamask_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/riroi_align_rotated_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/roi_align_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/roi_align_rotated_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/roi_pool_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/roiaware_pool3d_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/roipoint_pool3d_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/rotated_feature_align_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/scatter_points_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/sigmoid_focal_loss_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/softmax_focal_loss_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/stack_ball_query_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/stack_group_points_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/sync_bn_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/three_interpolate_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/three_nn_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/tin_shift_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/cuda/voxelization_cuda_kernel.cuh (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/bbox_overlaps_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/carafe_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/carafe_utils.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/common_mlu_helper.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/deform_roi_pool_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/focal_loss_sigmoid_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/iou3d_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/iou3d_utils.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/masked_conv2d_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/ms_deform_attn_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/nms_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/nms_utils.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/psamask_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/psamask_utils.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/roi_align_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_utils.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/roi_pool_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/roiaware_pool3d_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_large_boxes_num_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/three_nn_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mlu/tin_shift_mlu_kernel.mlu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mps/MPSDevice.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.mm (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mps/MPSStream.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/mps/MPSUtils.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/parrots_cpp_helper.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/parrots_cuda_helper.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/pytorch_cpp_helper.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/pytorch_cuda_helper.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/pytorch_device_registry.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/pytorch_mlu_helper.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/common/pytorch_npu_helper.hpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/assign_score_withk.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/ball_query._parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/ball_query.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/ball_query_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/border_align.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/border_align_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/border_align_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/carafe.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/carafe_naive.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/carafe_naive_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/carafe_naive_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/carafe_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/carafe_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/chamfer_distance.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/contour_expand.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/contour_expand_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/contour_expand_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/convex_iou.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/convex_iou_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/convex_iou_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/correlation.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/correlation_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/correlation_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/cudabind.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/deform_conv.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/deform_conv_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/deform_conv_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/focal_loss.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/focal_loss_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/focal_loss_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/fused_bias_leakyrelu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/fused_bias_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/gather_points.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/gather_points_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/gather_points_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/group_points.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/group_points_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/group_points_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/info.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/iou3d.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/iou3d_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/iou3d_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/knn.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/knn_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/knn_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/masked_conv2d.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/min_area_polygons.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/nms.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/nms_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/nms_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/nms_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/pixel_group.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/pixel_group_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/pixel_group_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/points_in_boxes.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/points_in_polygons.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/prroi_pool.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/prroi_pool_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/prroi_pool_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/psamask.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/psamask_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/psamask_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roi_align.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roi_align_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roi_align_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roi_pool.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roi_pool_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roi_pool_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/sync_bn.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/sync_bn_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/sync_bn_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/three_interpolate.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/three_interpolate_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/three_interpolate_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/three_nn.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/three_nn_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/three_nn_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/tin_shift.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/tin_shift_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/tin_shift_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/upfirdn2d.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/upfirdn2d_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/voxelization.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/voxelization_parrots.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/parrots/voxelization_pytorch.h (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/active_rotated_filter.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/assign_score_withk.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/ball_query.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/bbox_overlaps.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/bezier_align.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/border_align.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/box_iou_quadri.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/box_iou_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/carafe.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/carafe_naive.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/chamfer_distance.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/contour_expand.cpp (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/convex_iou.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/correlation.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/active_rotated_filter.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/bezier_align.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_quadri.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/deform_conv.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/modulated_deform_conv.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/nms.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_quadri.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/pixel_group.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/points_in_boxes.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/psamask.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/rotated_feature_align.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cpu/voxelization.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/active_rotated_filter_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/assign_score_withk_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/ball_query_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/bbox_overlaps_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/bezier_align_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/border_align_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_quadri_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_rotated_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_naive_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/chamfer_distance_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/convex_iou.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/correlation_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_conv_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_roi_pool_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/diff_iou_rotated_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/focal_loss_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/fused_bias_leakyrelu_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/gather_points_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/group_points_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/iou3d_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/knn_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/masked_conv2d_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/min_area_polygons.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/modulated_deform_conv_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/ms_deform_attn_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_quadri_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_rotated_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_boxes_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_polygons_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/prroi_pool_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/psamask_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/riroi_align_rotated_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_rotated_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_pool_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/roiaware_pool3d_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/roipoint_pool3d_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/rotated_feature_align_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/scatter_points_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_ball_query_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_group_points_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/sync_bn_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/three_interpolate_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/three_nn_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/tin_shift_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/upfirdn2d_kernel.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/cuda/voxelization_cuda.cu (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/deform_conv.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/deform_roi_pool.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/diff_iou_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/focal_loss.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/furthest_point_sample.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/fused_bias_leakyrelu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/fused_spconv_ops.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/gather_points.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/group_points.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/info.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/iou3d.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/knn.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/masked_conv2d.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/min_area_polygons.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/bbox_overlaps_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/carafe_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/deform_roi_pool_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/focal_loss_sigmoid_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/iou3d_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/masked_conv2d_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/ms_deform_attn_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/nms_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/psamask_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_rotated_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_pool_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/roiaware_pool3d_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/roipoint_pool3d_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/three_nn_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mlu/tin_shift_mlu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/modulated_deform_conv.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/mps/bbox_overlaps_mps.mm (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/ms_deform_attn.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/nms.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/nms_quadri.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/nms_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/npu/deform_roi_pool.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/npu/focal_loss_npu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/npu/fused_bias_leakyrelu_npu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/npu/nms_npu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/npu/psa_mask_npu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/npu/roi_pool_npu.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/pixel_group.cpp (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/points_in_boxes.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/points_in_polygons.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/prroi_pool.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/psamask.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/riroi_align_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/roi_align.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/roi_align_rotated.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/roi_pool.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/roiaware_pool3d.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/roipoint_pool3d.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/rotated_feature_align.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/scatter_points.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/sync_bn.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/three_interpolate.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/three_nn.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/tin_shift.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/upfirdn2d.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/csrc/pytorch/voxelization.cpp (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/deform_conv.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/deform_roi_pool.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/deprecated_wrappers.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/diff_iou_rotated.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/focal_loss.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/furthest_point_sample.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/fused_bias_leakyrelu.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/gather_points.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/group_points.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/info.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/iou3d.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/knn.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/masked_conv.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/merge_cells.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/min_area_polygons.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/modulated_deform_conv.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/multi_scale_deform_attn.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/nms.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/pixel_group.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/point_sample.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/points_in_boxes.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/points_in_polygons.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/points_sampler.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/prroi_pool.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/psa_mask.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/riroi_align_rotated.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/roi_align.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/roi_align_rotated.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/roi_pool.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/roiaware_pool3d.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/roipoint_pool3d.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/rotated_feature_align.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/saconv.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/scatter_points.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/sync_bn.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/three_interpolate.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/three_nn.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/tin_shift.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/upfirdn2d.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/ops/voxelize.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/transforms/__init__.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/transforms/base.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/transforms/builder.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/transforms/formatting.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/transforms/loading.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/transforms/processing.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/transforms/utils.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/transforms/wrappers.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/utils/__init__.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/utils/device_type.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/utils/env.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/utils/ext_loader.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/utils/parrots_jit.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/version.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/video/__init__.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/video/io.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/video/optflow.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/video/processing.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/visualization/__init__.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/visualization/color.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/visualization/image.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/mmcv/visualization/optflow.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/requirements.txt (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/requirements/build.txt (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/requirements/docs.txt (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/requirements/optional.txt (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/requirements/runtime.txt (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/requirements/test.txt (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/setup.cfg (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/setup.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/batched_nms_data.pkl (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/color.jpg (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/color_exif.jpg (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/a.b.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/a.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/b.json (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/base.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/c.yaml (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/code.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/d.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/delete.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/deprecated.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/deprecated_as_base.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/e.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/expected.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/f.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/g.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/h.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/i_base.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/i_child.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/l.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/l1.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/l2.yaml (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/l3.json (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/l4.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/m.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/n.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/o.json (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/p.yaml (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/q.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/r.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/s.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/t.json (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/t.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/t.yaml (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/u.json (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/u.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/u.yaml (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/config/v.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/demo.lmdb/data.mdb (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/demo.lmdb/lock.mdb (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/filelist.txt (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_3d_ops/features_for_fps_distance.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_3d_ops/fps_idx.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_3d_ops/test_voxel.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_carafe/carafe_feat.bin (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_carafe/carafe_feat_grad.bin (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_carafe/carafe_mask.bin (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_carafe/carafe_mask_grad.bin (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_carafe/carafe_output.bin (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_ccattention/ccattention_input.bin (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_ccattention/ccattention_output.bin (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_bias.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_input.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_mask.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_output.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_weight.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_psa_mask/psa_input.bin (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_psa_mask/psa_output_collect.bin (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_psa_mask/psa_output_distribute.bin (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_scan/.file (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_scan/1.json (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_scan/1.txt (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_scan/2.json (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_scan/2.txt (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_scan/3.TXT (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_scan/a.bin (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_scan/sub/1.json (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/for_scan/sub/1.txt (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/gray_alpha.png (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/grayscale.jpg (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/grayscale_dim3.jpg (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/mapping.txt (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/optflow.flo (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/optflow_concat0.jpg (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/optflow_concat1.jpg (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/palette.gif (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/0.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/1.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/2.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/3.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/4.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/pad0_0.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/pad0_1.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/pad0_2.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/pad0_3.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/pad0_4.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/pad_0.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/pad_1.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/pad_2.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/pad_3.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/pad_4.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/scale_0.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/scale_1.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/scale_2.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/scale_3.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/patches/scale_4.npy (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/scripts/hello.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/sparse_flow.png (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/test.mp4 (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/data/uint16-5channel.tif (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_arraymisc.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_build_layers.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_context_block.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_conv2d_adaptive_padding.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_conv_module.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_depthwise_seperable_conv_module.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_flops_counter.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_fuse_conv_bn.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_generalized_attention.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_hsigmoid.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_hswish.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_non_local.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_scale.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_silu.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_swish.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_transformer.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_cnn/test_wrappers.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_image/test_colorspace.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_image/test_geometric.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_image/test_image_misc.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_image/test_io.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_image/test_photometric.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/output.pkl (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_active_rotated_filter.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_assign_score_withk.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_ball_query.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_bbox.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_bezier_align.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_bilinear_grid_sample.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_border_align.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_box_iou_quadri.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_box_iou_rotated.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_carafe.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_cc_attention.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_chamfer_distance.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_contour_expand.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_convex_iou.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_corner_pool.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_correlation.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_deform_conv.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_deform_roi_pool.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_diff_iou_rotated.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_focal_loss.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_furthest_point_sample.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_fused_bias_leakyrelu.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_gather_points.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_group_points.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_info.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_iou3d.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_knn.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_masked_conv2d.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_merge_cells.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_min_area_polygons.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_modulated_deform_conv.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_ms_deformable_attn.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_nms.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_nms_quadri.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_nms_rotated.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_onnx.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_pixel_group.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_points_in_polygons.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_prroi_pool.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_psa_mask.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_riroi_align_rotated.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_roi_align.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_roi_align_rotated.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_roi_pool.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_roiaware_pool3d.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_roipoint_pool3d.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_rotated_feature_align.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_saconv.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_scatter_points.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_spconv.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_syncbn.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_three_interpolate.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_three_nn.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_tin_shift.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_upfirdn2d.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_ops/test_voxelization.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_transforms/test_transforms_formatting.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_transforms/test_transforms_loading.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_transforms/test_transforms_processing.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_transforms/test_transforms_wrapper.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_utils/test_env.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_utils/test_parrots_jit.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_video/test_optflow.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_video/test_processing.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_video/test_reader.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmcv/tests/test_visualization.py (100%) rename cv/distiller/CWD/{ => pytorch}/mmrazor/.circleci/config.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/.circleci/docker/Dockerfile (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/.circleci/test.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/.dev_scripts/benchmark_summary_analyse.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/.dev_scripts/benchmark_test.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/.dev_scripts/benchmark_train.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/.dev_scripts/meta_files_test.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/.pre-commit-config.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/.readthedocs.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/LICENSE (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/MANIFEST.in (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/README_zh-CN.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/datasets/mmcls/cifar100_bs16_auto_aug.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/datasets/mmcls/pipelines/auto_aug_cifar.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/nas_backbones/attentive_mobilenetv3_supernet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/nas_backbones/darts_supernet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/nas_backbones/dsnas_shufflenet_supernet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/nas_backbones/ofa_mobilenetv3_supernet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/nas_backbones/spos_mobilenet_supernet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/nas_backbones/spos_shufflenet_supernet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/settings/cifar10_darts_subnet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/settings/cifar10_darts_supernet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/settings/imagenet_bs1024_dsnas.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/settings/imagenet_bs1024_spos.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/settings/imagenet_bs2048_AdamW.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim_pil.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/settings/imagenet_bs2048_bignas.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/settings/imagenet_bs2048_dmcp.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/settings/imagenet_bs2048_ofa.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/_base_/vanilla_models/wrn16_2_cifar10.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/abloss/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/abloss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/abloss/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/byot/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/byot/byot_resnet18_8xb16_cifar100.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/byot/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/crd/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/crd/crd_neck_r50_r18_8xb16_cifar10.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/crd/datasets/crd_cifar10_bs16.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/dafl/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/dafl/dafl_logits_resnet34_resnet18_8xb256_cifar10.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/dafl/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/deit/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/deit/deit-base_regnety160_pt-16xb64_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/deit/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/dfad/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/dfad/dfad_logits_resnet34_resnet18_8xb32_cifar10.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/dfad/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/dkd/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/dkd/dkd_resnet34_resnet18_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/dkd/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/factor_transfer/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/factor_transfer/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/fitnets/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/fitnets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/fitnets/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/kd/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet34_resnet18_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/kd/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/ofd/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/ofd/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/rkd/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/rkd/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/wsld/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/wsld/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/wsld/wsld_logits_resnet34_resnet18_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/zskt/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/zskt/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmcls/zskt/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/cwd/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco_visualization.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/cwd/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/fbkd/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/fbkd/fbkd_fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/fbkd/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/mgd/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/mgd/mgd_fpn_retina_x101_retina_r50_2x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/pkd/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/pkd/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_fcos_x101_retina_r50_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_retina_x101_retina_r50_2x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet3d/pkd/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet3d/pkd/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmdet3d/pkd/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmseg/cwd/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/distill/mmseg/cwd/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoformer/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoformer/autoformer_search_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoformer/autoformer_subnet_8xb256_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoformer/autoformer_supernet_32xb256_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoslim/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_search_8xb256_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_supernet_8xb256_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/autoslim/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A1.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A2.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A3.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A4.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A5.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A6.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/bignas/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_search_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_supernet_32xb64_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/darts/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0_mmrazor.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/darts/darts_supernet_unroll_1xb96_cifar10.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/darts/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/dsnas/DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/dsnas/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/dsnas/dsnas_subnet_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/dsnas/dsnas_supernet_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT22.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT31.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/onceforall/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_search_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_subnet_8xb256_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_supernet_32xb64_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/spos/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/spos/SPOS_SUBNET.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/spos/faster-rcnn_nas_backbone_fpn_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/spos/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_search_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_subnet_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_supernet_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_predictor_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_subnet_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_supernet_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmdet/detnas/DETNAS_SUBNET.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmdet/detnas/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_search_coco_1x.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_subnet_coco_1x.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_supernet_coco_1x.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmdet/detnas/detnas_retina_shufflenet_supernet_coco_1x.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_subnet_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_supernet_8xb128_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/nas/mmdet/detnas/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/base/group_fisher/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/base/group_fisher/group_fisher_deploy_template.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/base/group_fisher/group_fisher_finetune_template.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/base/group_fisher/group_fisher_prune_template.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dcff/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dcff/dcff_compact_resnet_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dcff/dcff_resnet_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dcff/fix_subnet.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dmcp/DMCP_MBV2_100M.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dmcp/DMCP_R50_2G.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dmcp/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_supernet_32xb64.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_supernet_32xb64.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/dmcp/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_deploy_mobilenet-v2_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_deploy_mobilenet-v2_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/script.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_deploy_resnet50_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_prune_resnet50_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_deploy_resnet50_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_prune_resnet50_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/script.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/l1-norm/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a_deploy.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b_deploy.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c_deploy.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/l1-norm/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmcls/l1-norm/script.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/dcff/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/dcff/dcff_compact_faster_rcnn_resnet50_8xb4_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_fpn.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/dcff/fix_subnet.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/group_fisher/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_deploy_retinanet_r50_fpn_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_deploy_retinanet_r50_fpn_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/script.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmpose/dcff/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmpose/dcff/dcff_compact_topdown_heatmap_resnet50_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmpose/dcff/fix_subnet.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_aic-coco-256x192.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_coco-256x192.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmpose/group_fisher/script.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmseg/dcff/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmseg/dcff/dcff_compact_pointrend_resnet50_8xb2_cityscapes.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmseg/dcff/fix_subnet.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/pruning/mmseg/dcff/pointrend_resnet50.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_openvino_dynamic-800x1344.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_tensorrt-int8-explicit_dynamic-320x320-1344x1344.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/ptq_openvino_retina_r50_1x_coco_calib32xb32.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/qat/base/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/qat/base/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/qat/base/qat_openvino_resnet18_10e_8xb32_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/qat/lsq/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_100e_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_10e_in1k.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/quantization/qat/lsq/metafile.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/vanilla/mmcls/wide-resnet/README.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn22-w4_b16x8_cifar10.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn40-w2_b16x8_cifar10.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/datasets/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/datasets/crd_dataset_wrapper.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/datasets/transforms/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/datasets/transforms/auto_augment.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/datasets/transforms/auto_augmentv2.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/datasets/transforms/formatting.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/hooks/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/hooks/dmcp_subnet_hook.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/hooks/dump_subnet_hook.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/hooks/estimate_resources_hook.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/hooks/group_fisher_hooks.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/hooks/stop_distillation_hook.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/hooks/visualization_hook.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/optimizers/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/optimizers/optimizer_constructor.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/autoslim_greedy_search_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/darts_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/distill_val_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/evolution_search_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/iteprune_val_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/quantization_loops.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/slimmable_val_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/subnet_sampler_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/subnet_val_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/utils/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/utils/calibrate_bn_mixin.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/utils/check.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/engine/runner/utils/genetic.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/implementations/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/implementations/pruning/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/implementations/pruning/group_fisher/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/implementations/pruning/group_fisher/algorithm.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/implementations/pruning/group_fisher/counters.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/implementations/pruning/group_fisher/hook.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/implementations/pruning/group_fisher/mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/implementations/pruning/group_fisher/ops.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_deploy_sub_model.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_sub_model.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/implementations/pruning/group_fisher/unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/base.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/distill/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/distill/configurable/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/distill/configurable/datafree_distillation.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/distill/configurable/fpn_teacher_distill.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/distill/configurable/overhaul_feature_distillation.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/distill/configurable/self_distill.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/distill/configurable/single_teacher_distill.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/nas/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/nas/autoformer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/nas/autoslim.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/nas/bignas.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/nas/darts.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/nas/dsnas.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/nas/spos.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/pruning/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/pruning/dcff.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/pruning/dmcp.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/pruning/group_fisher_algoritho.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/pruning/ite_prune_algorithm.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/pruning/slimmable_network.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/quantization/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/algorithms/quantization/mm_architecture.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/backbones/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/backbones/darts_backbone.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/backbones/searchable_autoformer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v2.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v3.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/backbones/searchable_shufflenet_v2.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/backbones/wideresnet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/classifiers/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/classifiers/image.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/connectors/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/connectors/base_connector.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/connectors/byot_connector.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/connectors/convmodule_connector.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/connectors/crd_connector.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/connectors/factor_transfer_connectors.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/connectors/fbkd_connector.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/connectors/mgd_connector.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/connectors/norm_connector.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/connectors/ofd_connector.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/connectors/torch_connector.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_container.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_conv.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_embed.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_function.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_linear.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_multi_head_attention.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_norm.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_relative_position.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/group_fisher_ops.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/head/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/head/dynamic_linear_head.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_conv_mixins.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_layernorm_mixins.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_mixins.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/generators/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/generators/base_generator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/generators/dafl_generator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/generators/zskt_generator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/heads/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/heads/darts_subnet_head.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/heads/deit_head.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/necks/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/necks/squeezemean_with_dropout.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/ops/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/ops/base.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/ops/common.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/ops/darts_series.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/ops/efficientnet_series.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/ops/function.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/ops/gather_tensors.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/ops/mobilenet_series.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/ops/shufflenet_series.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/ops/transformer_series.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/utils/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/utils/mutable_register.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/architectures/utils/set_dropout.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/distillers/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/distillers/base_distiller.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/distillers/byot_distiller.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/distillers/configurable_distiller.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/distillers/ofd_distiller.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/fake_quants/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/fake_quants/base.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/fake_quants/lsq.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/fake_quants/torch_fake_quants.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/ab_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/at_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/crd_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/cross_entropy_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/cwd.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/dafl_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/decoupled_kd.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/dist_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/factor_transfer_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/fbkd_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/kd_soft_ce_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/kl_divergence.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/l1_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/l2_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/mgd_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/ofd_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/pkd_loss.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/relational_kd.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/losses/weighted_soft_label_distillation.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/base_mutable.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/derived_mutable.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/MutableChannel.md (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/base_mutable_channel.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/mutable_channel_container.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/oneshot_mutable_channel.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/sequential_mutable_channel.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/simple_mutable_channel.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/dcff_channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/dmcp_channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/group_fisher_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/l1_mutable_channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.ipynb (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/one_shot_mutable_channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/sequential_mutable_channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/slimmable_channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_channel/units/utils.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_module/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_module/diff_mutable_module.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_module/mutable_module.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_module/one_shot_mutable_module.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_value/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutables/mutable_value/mutable_value.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/base_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/channel_mutator/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.ipynb (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/channel_mutator/dcff_channel_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/channel_mutator/dmcp_channel_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/channel_mutator/group_fisher_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/channel_mutator/one_shot_channel_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/channel_mutator/slimmable_channel_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/group_mixin.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/mutators/nas_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/observers/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/observers/base.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/observers/lsq.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/observers/torch_observers.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/quantizers/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/quantizers/academic_quantizer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/quantizers/base.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/quantizers/exporters/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/quantizers/exporters/base_quantize_exporter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/quantizers/exporters/openvino_quantize_exporter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/quantizers/exporters/optim_utils.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/quantizers/exporters/tensorrt_quantize_exporter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/quantizers/native_quantizer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/quantizers/openvino_quantizer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/quantizers/tensorrt_quantizer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/delivery/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/delivery/delivery_manager.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/delivery/distill_delivery.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/delivery/function_outputs_delivery.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/delivery/method_outputs_delivery.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/demo_inputs/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/demo_inputs/default_demo_inputs.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/demo_inputs/demo_inputs.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/demo_inputs/mmpose_demo_input.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/demo_inputs/mmseg_demo_input.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/base_estimator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/flops_params_counter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/latency_counter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/activation_layer_counter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/base_counter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/conv_layer_counter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/deconv_layer_counter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/group_fisher_counters.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/linear_layer_counter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/norm_layer_counter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/pooling_layer_counter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/upsample_layer_counter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/estimators/resource_estimator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/predictor/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/predictor/handler/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/predictor/handler/base_handler.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/predictor/handler/carts_handler.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/predictor/handler/gp_handler.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/predictor/handler/mlp_handler.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/predictor/handler/rbf_handler.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/predictor/metric_predictor.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/recorder/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/recorder/base_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/recorder/function_inputs_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/recorder/function_outputs_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/recorder/method_inputs_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/recorder/method_outputs_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/recorder/module_inputs_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/recorder/module_outputs_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/recorder/param_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/recorder/recorder_manager.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/backward_tracer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/channel_analyzer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/fx/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/fx/custom_tracer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/fx/graph_utils.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/fx_tracer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/cascade_encoder_decoder_loss_calculator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/image_classifier_loss_calculator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/single_stage_detector_loss_calculator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/sum_loss_calculator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/top_down_pose_estimator_loss_calculator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/two_stage_detector_loss_calculator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/parsers.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/task_modules/tracer/path.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/utils/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/utils/expandable_utils/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/utils/expandable_utils/ops.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/utils/expandable_utils/tools.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/utils/expandable_utils/unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/utils/make_divisible.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/utils/misc.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/utils/optim_wrapper.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/utils/parse_values.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/utils/quantization_util.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/models/utils/utils.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/registry/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/registry/registry.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/graph/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/graph/base_graph.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/graph/channel_flow.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/graph/channel_graph.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/graph/channel_nodes.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/graph/module_graph.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/graph/pseudo_fx_graph.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/quantization/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/quantization/backend_config/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/quantization/backend_config/academic.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/quantization/backend_config/common_operator_config_utils.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/quantization/backend_config/mapping.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/quantization/backend_config/native.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/quantization/backend_config/openvino.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/quantization/backend_config/tensorrt.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/quantization/qconfig.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/subnet/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/subnet/candidate.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/structures/subnet/fix_subnet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/testing/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/testing/_fast_stop_training_hook.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/testing/_fx_models.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/utils/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/utils/index_dict.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/utils/log_tools.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/utils/misc.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/utils/placeholder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/utils/runtime_info.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/utils/setup_env.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/utils/typing.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/version.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/visualization/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/mmrazor/visualization/local_visualizer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/model-index.yml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/requirements.txt (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/requirements/docs.txt (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/requirements/mminstall.txt (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/requirements/optional.txt (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/requirements/readthedocs.txt (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/requirements/runtime.txt (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/requirements/tests.txt (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/resources/design_and_implement.png (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/resources/mmrazor-logo.png (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/resources/qq_group_qrcode.jpg (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/resources/xiaozhushou_weixin_qrcode.jpeg (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/resources/zhihu_qrcode.jpg (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/setup.cfg (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/setup.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/MBV2_220M.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/MBV2_320M.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/MBV2_530M.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/MBV2_slimmable_channel_config.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/MBV2_slimmable_config.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/color.jpeg (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/concat_subnet1.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/concat_subnet2.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/dataset/a/1.JPG (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/dataset/ann.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/dataset/ann.txt (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/dataset/b/2.jpeg (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/dataset/b/subb/3.jpg (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/dataset/classes.txt (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/dataset/multi_label_ann.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/model_library.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/models.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/subnet1.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/subnet2.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/test_models/test_algorithm/MBV2_220M.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/test_models/test_mutator/subnet1.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/test_models/test_subnet/mockmodel_subnet.yaml (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/test_models/test_task_modules/mmcls_cfg.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/test_registry/registry_architecture_config.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/test_registry/registry_subnet_config.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/test_registry/subnet.json (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/data/tracer_passed_models.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_delivers/test_deliver_manager.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_delivers/test_function_outputs_deliver.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_delivers/test_method_outputs_deliver.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_delivers/toy_module.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_graph/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_graph/test_channel_flow.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_graph/test_channel_graph.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_graph/test_graph.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_graph/test_prune_tracer_model.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_recorders/test_base_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_recorders/test_func_inputs_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_recorders/test_func_outputs_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_recorders/test_method_inputs_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_recorders/test_method_outputs_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_recorders/test_module_recorders.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_recorders/test_param_recorder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_recorders/test_recorder_manager.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_recorders/toy_mod.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_tracer/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_tracer/test_backward_tracer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_tracer/test_fx_tracer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_tracer/test_loss_calculator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_core/test_tracer/test_prune_tracer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_data.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_datasets/test_datasets.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_datasets/test_transforms/test_formatting.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_doc.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_engine/test_hooks/test_stop_distillation_hook.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_engine/test_hooks/test_visualization_hook.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_impl/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_impl/test_pruning/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_impl/test_pruning/test_group_fisher/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_algorithm.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_deploy_sub_model.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_sub_model.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_autoformer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_autoslim.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_base_algorithm.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_bignas.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_darts.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_datafree_distill.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_dcff_network.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_dmcp.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_dsnas.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_general_quant.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_mm_architecture.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_ofd_algo.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_prune_algorithm.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_self_distill.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_single_teacher_distill.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_slimmable_network.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/test_spos.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_algorithms/toy_models.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_backbones/test_autoformerbackbone.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_backbones/test_dartsbackbone.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v2.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v3.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_shufflenet_v2.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_backbones/utils.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_connectors/test_connectors.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_attention.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_container.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_conv.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_embed.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_layernorm.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_linear.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_norm.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_relative_position.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_resizer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_dynamic_op/utils.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_architectures/test_generators/test_generators.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_classifier/test_imageclassifier.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_distillers/test_byot_distill.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_distillers/test_configurable_distill.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_fake_quants/test_lsq_fake_quants.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_fake_quants/test_torch_fake_quants.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_losses/test_distillation_losses.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_losses/test_general_losses.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_derived_mutable.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_diffchoiceroute.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_diffop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_gumbelchoiceroute.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_mutable_channel/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_mutable_channels.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_sequential_mutable_channel.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_dcff_channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_l1_mutable_channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_mutable_channel_units.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_one_shot_mutable_channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_sequential_mutable_channel_unit.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_mutable_value.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_onehotop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_oneshotop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutables/test_sequential_mutable_channel.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutators/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutators/test_channel_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutators/test_dcff_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutators/test_dmcp_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_mutators/test_nas_mutator.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_observers/test_lsq_observer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_observers/test_torch_observers.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_quantizers/test_academic_quantizer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_quantizers/test_exporter.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_quantizers/test_native_quantizer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_quantizers/test_openvino_quantizer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_quantizers/test_tensorrt_quantizer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_subnet/test_candidate.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_subnet/test_fix_subnet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_task_modules/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_task_modules/test_custom_tracer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/test_demo_inputs.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_task_modules/test_estimators/test_flops_params.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_task_modules/test_graph_utils.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_task_modules/test_predictors/test_metric_predictor.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_utils/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_utils/test_expandable_utils/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_models/test_utils/test_expandable_utils/test_expand.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_registry/test_registry.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_runners/test_autoslim_greedy_search_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_runners/test_darts_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_runners/test_distill_val_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_runners/test_evolution_search_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_runners/test_quantization_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_runners/test_subnet_sampler_loop.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_runners/test_utils/test_calibrate_bn_mixin.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_runners/test_utils/test_check.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_runners/test_utils/test_genetic.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_structures/test_backendconfig.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_structures/test_qconfig.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_tools/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_tools/test_tools.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_utils/test_index_dict.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_utils/test_placeholder.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/test_visualizer/test_visualizer.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/utils/__init__.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/utils/set_dist_env.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tests/utils/set_torch_thread.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/dataset_converters/cityscapes.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/dist_test.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/dist_train.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/misc/print_config.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/model_converters/convert_attentivenas_nas_ckpt.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/model_converters/convert_bignas_gml_ckpt.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/model_converters/convert_kd_ckpt.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/model_converters/convert_kd_ckpt_to_student.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/model_converters/convert_ofa_ckpt.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/model_converters/convert_quant_ckpt.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/model_converters/convert_supernet2subnet.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/model_converters/publish_model.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/pruning/get_channel_units.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/pruning/get_flops.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/pruning/get_l1_prune_config.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/pruning/get_static_model_from_algorithm.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/ptq.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/slurm_test.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/slurm_train.sh (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/test.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/train.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/visualizations/demo.jpg (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/visualizations/feature_diff_visualization.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/visualizations/feature_visualization.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/visualizations/vis_configs/backbone_feature_diff_visualization.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/visualizations/vis_configs/backbone_feature_visualization.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/visualizations/vis_configs/fpn_feature_diff_visualization.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/visualizations/vis_configs/fpn_feature_visualization.py (100%) mode change 100755 => 100644 rename cv/distiller/CWD/{ => pytorch}/mmrazor/tools/visualizations/vis_scheduler.py (100%) mode change 100755 => 100644 diff --git a/cv/distiller/CWD/README.md b/cv/distiller/CWD/pytorch/README.md similarity index 100% rename from cv/distiller/CWD/README.md rename to cv/distiller/CWD/pytorch/README.md diff --git a/cv/distiller/CWD/mmcv/.dockerignore b/cv/distiller/CWD/pytorch/mmcv/.dockerignore similarity index 100% rename from cv/distiller/CWD/mmcv/.dockerignore rename to cv/distiller/CWD/pytorch/mmcv/.dockerignore diff --git a/cv/distiller/CWD/mmcv/.pre-commit-config.yaml b/cv/distiller/CWD/pytorch/mmcv/.pre-commit-config.yaml similarity index 100% rename from cv/distiller/CWD/mmcv/.pre-commit-config.yaml rename to cv/distiller/CWD/pytorch/mmcv/.pre-commit-config.yaml diff --git a/cv/distiller/CWD/mmcv/.readthedocs.yml b/cv/distiller/CWD/pytorch/mmcv/.readthedocs.yml similarity index 100% rename from cv/distiller/CWD/mmcv/.readthedocs.yml rename to cv/distiller/CWD/pytorch/mmcv/.readthedocs.yml diff --git a/cv/distiller/CWD/mmcv/CITATION.cff b/cv/distiller/CWD/pytorch/mmcv/CITATION.cff similarity index 100% rename from cv/distiller/CWD/mmcv/CITATION.cff rename to cv/distiller/CWD/pytorch/mmcv/CITATION.cff diff --git a/cv/distiller/CWD/mmcv/CONTRIBUTING.md b/cv/distiller/CWD/pytorch/mmcv/CONTRIBUTING.md similarity index 100% rename from cv/distiller/CWD/mmcv/CONTRIBUTING.md rename to cv/distiller/CWD/pytorch/mmcv/CONTRIBUTING.md diff --git a/cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md b/cv/distiller/CWD/pytorch/mmcv/CONTRIBUTING_zh-CN.md similarity index 100% rename from cv/distiller/CWD/mmcv/CONTRIBUTING_zh-CN.md rename to cv/distiller/CWD/pytorch/mmcv/CONTRIBUTING_zh-CN.md diff --git a/cv/distiller/CWD/mmcv/Jenkinsfile b/cv/distiller/CWD/pytorch/mmcv/Jenkinsfile similarity index 100% rename from cv/distiller/CWD/mmcv/Jenkinsfile rename to cv/distiller/CWD/pytorch/mmcv/Jenkinsfile diff --git a/cv/distiller/CWD/mmcv/LICENSE b/cv/distiller/CWD/pytorch/mmcv/LICENSE similarity index 100% rename from cv/distiller/CWD/mmcv/LICENSE rename to cv/distiller/CWD/pytorch/mmcv/LICENSE diff --git a/cv/distiller/CWD/mmcv/LICENSES.md b/cv/distiller/CWD/pytorch/mmcv/LICENSES.md similarity index 100% rename from cv/distiller/CWD/mmcv/LICENSES.md rename to cv/distiller/CWD/pytorch/mmcv/LICENSES.md diff --git a/cv/distiller/CWD/mmcv/MANIFEST.in b/cv/distiller/CWD/pytorch/mmcv/MANIFEST.in similarity index 100% rename from cv/distiller/CWD/mmcv/MANIFEST.in rename to cv/distiller/CWD/pytorch/mmcv/MANIFEST.in diff --git a/cv/distiller/CWD/mmcv/README.md b/cv/distiller/CWD/pytorch/mmcv/README.md similarity index 100% rename from cv/distiller/CWD/mmcv/README.md rename to cv/distiller/CWD/pytorch/mmcv/README.md diff --git a/cv/distiller/CWD/mmcv/README_zh-CN.md b/cv/distiller/CWD/pytorch/mmcv/README_zh-CN.md similarity index 100% rename from cv/distiller/CWD/mmcv/README_zh-CN.md rename to cv/distiller/CWD/pytorch/mmcv/README_zh-CN.md diff --git a/cv/distiller/CWD/mmcv/TERMINOLOGY.md b/cv/distiller/CWD/pytorch/mmcv/TERMINOLOGY.md similarity index 100% rename from cv/distiller/CWD/mmcv/TERMINOLOGY.md rename to cv/distiller/CWD/pytorch/mmcv/TERMINOLOGY.md diff --git a/cv/distiller/CWD/mmcv/build_mmcv.sh b/cv/distiller/CWD/pytorch/mmcv/build_mmcv.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmcv/build_mmcv.sh rename to cv/distiller/CWD/pytorch/mmcv/build_mmcv.sh diff --git a/cv/distiller/CWD/mmcv/clean_mmcv.sh b/cv/distiller/CWD/pytorch/mmcv/clean_mmcv.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmcv/clean_mmcv.sh rename to cv/distiller/CWD/pytorch/mmcv/clean_mmcv.sh diff --git a/cv/distiller/CWD/mmcv/docker/README.md b/cv/distiller/CWD/pytorch/mmcv/docker/README.md similarity index 100% rename from cv/distiller/CWD/mmcv/docker/README.md rename to cv/distiller/CWD/pytorch/mmcv/docker/README.md diff --git a/cv/distiller/CWD/mmcv/docker/dev/Dockerfile b/cv/distiller/CWD/pytorch/mmcv/docker/dev/Dockerfile similarity index 100% rename from cv/distiller/CWD/mmcv/docker/dev/Dockerfile rename to cv/distiller/CWD/pytorch/mmcv/docker/dev/Dockerfile diff --git a/cv/distiller/CWD/mmcv/docker/release/Dockerfile b/cv/distiller/CWD/pytorch/mmcv/docker/release/Dockerfile similarity index 100% rename from cv/distiller/CWD/mmcv/docker/release/Dockerfile rename to cv/distiller/CWD/pytorch/mmcv/docker/release/Dockerfile diff --git a/cv/distiller/CWD/mmcv/docs/en/Makefile b/cv/distiller/CWD/pytorch/mmcv/docs/en/Makefile similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/Makefile rename to cv/distiller/CWD/pytorch/mmcv/docs/en/Makefile diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/community/1.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/community/1.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/community/1.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/community/1.png diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/community/2.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/community/2.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/community/2.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/community/2.png diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/community/3.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/community/3.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/community/3.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/community/3.png diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/css/readthedocs.css b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/css/readthedocs.css similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/css/readthedocs.css rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/css/readthedocs.css diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/flow_img2toimg1.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/flow_img2toimg1.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/flow_img2toimg1.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/flow_img2toimg1.png diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/flow_raw_images.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/flow_raw_images.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/flow_raw_images.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/flow_raw_images.png diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/flow_visualization.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/flow_visualization.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/flow_visualization.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/flow_visualization.png diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/flow_warp.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/flow_warp.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/flow_warp.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/flow_warp.png diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/flow_warp_diff.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/flow_warp_diff.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/flow_warp_diff.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/flow_warp_diff.png diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/image/mmcv-logo.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/image/mmcv-logo.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/image/mmcv-logo.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/image/mmcv-logo.png diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/parallel_progress.gif b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/parallel_progress.gif similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/parallel_progress.gif rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/parallel_progress.gif diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/parallel_progress.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/parallel_progress.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/parallel_progress.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/parallel_progress.png diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/progress.gif b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/progress.gif similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/progress.gif rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/progress.gif diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/progress.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/progress.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/progress.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/progress.png diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/version.json b/cv/distiller/CWD/pytorch/mmcv/docs/en/_static/version.json similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_static/version.json rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_static/version.json diff --git a/cv/distiller/CWD/mmcv/docs/en/_templates/classtemplate.rst b/cv/distiller/CWD/pytorch/mmcv/docs/en/_templates/classtemplate.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/_templates/classtemplate.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/en/_templates/classtemplate.rst diff --git a/cv/distiller/CWD/mmcv/docs/en/api/arraymisc.rst b/cv/distiller/CWD/pytorch/mmcv/docs/en/api/arraymisc.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/api/arraymisc.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/en/api/arraymisc.rst diff --git a/cv/distiller/CWD/mmcv/docs/en/api/cnn.rst b/cv/distiller/CWD/pytorch/mmcv/docs/en/api/cnn.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/api/cnn.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/en/api/cnn.rst diff --git a/cv/distiller/CWD/mmcv/docs/en/api/image.rst b/cv/distiller/CWD/pytorch/mmcv/docs/en/api/image.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/api/image.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/en/api/image.rst diff --git a/cv/distiller/CWD/mmcv/docs/en/api/ops.rst b/cv/distiller/CWD/pytorch/mmcv/docs/en/api/ops.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/api/ops.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/en/api/ops.rst diff --git a/cv/distiller/CWD/mmcv/docs/en/api/transforms.rst b/cv/distiller/CWD/pytorch/mmcv/docs/en/api/transforms.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/api/transforms.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/en/api/transforms.rst diff --git a/cv/distiller/CWD/mmcv/docs/en/api/utils.rst b/cv/distiller/CWD/pytorch/mmcv/docs/en/api/utils.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/api/utils.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/en/api/utils.rst diff --git a/cv/distiller/CWD/mmcv/docs/en/api/video.rst b/cv/distiller/CWD/pytorch/mmcv/docs/en/api/video.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/api/video.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/en/api/video.rst diff --git a/cv/distiller/CWD/mmcv/docs/en/api/visualization.rst b/cv/distiller/CWD/pytorch/mmcv/docs/en/api/visualization.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/api/visualization.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/en/api/visualization.rst diff --git a/cv/distiller/CWD/mmcv/docs/en/community/contributing.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/community/contributing.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/community/contributing.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/community/contributing.md diff --git a/cv/distiller/CWD/mmcv/docs/en/community/pr.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/community/pr.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/community/pr.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/community/pr.md diff --git a/cv/distiller/CWD/mmcv/docs/en/compatibility.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/compatibility.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/compatibility.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/compatibility.md diff --git a/cv/distiller/CWD/mmcv/docs/en/conf.py b/cv/distiller/CWD/pytorch/mmcv/docs/en/conf.py similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/conf.py rename to cv/distiller/CWD/pytorch/mmcv/docs/en/conf.py diff --git a/cv/distiller/CWD/mmcv/docs/en/deployment/mmcv_ops_definition.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/deployment/mmcv_ops_definition.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/deployment/mmcv_ops_definition.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/deployment/mmcv_ops_definition.md diff --git a/cv/distiller/CWD/mmcv/docs/en/docutils.conf b/cv/distiller/CWD/pytorch/mmcv/docs/en/docutils.conf similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/docutils.conf rename to cv/distiller/CWD/pytorch/mmcv/docs/en/docutils.conf diff --git a/cv/distiller/CWD/mmcv/docs/en/faq.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/faq.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/faq.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/faq.md diff --git a/cv/distiller/CWD/mmcv/docs/en/get_started/build.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/get_started/build.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/get_started/build.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/get_started/build.md diff --git a/cv/distiller/CWD/mmcv/docs/en/get_started/installation.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/get_started/installation.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/get_started/installation.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/get_started/installation.md diff --git a/cv/distiller/CWD/mmcv/docs/en/get_started/introduction.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/get_started/introduction.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/get_started/introduction.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/get_started/introduction.md diff --git a/cv/distiller/CWD/mmcv/docs/en/get_started/previous_versions.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/get_started/previous_versions.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/get_started/previous_versions.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/get_started/previous_versions.md diff --git a/cv/distiller/CWD/mmcv/docs/en/index.rst b/cv/distiller/CWD/pytorch/mmcv/docs/en/index.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/index.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/en/index.rst diff --git a/cv/distiller/CWD/mmcv/docs/en/make.bat b/cv/distiller/CWD/pytorch/mmcv/docs/en/make.bat similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/make.bat rename to cv/distiller/CWD/pytorch/mmcv/docs/en/make.bat diff --git a/cv/distiller/CWD/mmcv/docs/en/mmcv-logo.png b/cv/distiller/CWD/pytorch/mmcv/docs/en/mmcv-logo.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/mmcv-logo.png rename to cv/distiller/CWD/pytorch/mmcv/docs/en/mmcv-logo.png diff --git a/cv/distiller/CWD/mmcv/docs/en/switch_language.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/switch_language.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/switch_language.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/switch_language.md diff --git a/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/cnn.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/understand_mmcv/cnn.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/understand_mmcv/cnn.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/understand_mmcv/cnn.md diff --git a/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_process.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/understand_mmcv/data_process.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_process.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/understand_mmcv/data_process.md diff --git a/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_transform.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/understand_mmcv/data_transform.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/understand_mmcv/data_transform.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/understand_mmcv/data_transform.md diff --git a/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/ops.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/understand_mmcv/ops.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/understand_mmcv/ops.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/understand_mmcv/ops.md diff --git a/cv/distiller/CWD/mmcv/docs/en/understand_mmcv/visualization.md b/cv/distiller/CWD/pytorch/mmcv/docs/en/understand_mmcv/visualization.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/en/understand_mmcv/visualization.md rename to cv/distiller/CWD/pytorch/mmcv/docs/en/understand_mmcv/visualization.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/Makefile b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/Makefile similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/Makefile rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/Makefile diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/_static/css/readthedocs.css b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/_static/css/readthedocs.css similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/_static/css/readthedocs.css rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/_static/css/readthedocs.css diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/_static/image/mmcv-logo.png b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/_static/image/mmcv-logo.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/_static/image/mmcv-logo.png rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/_static/image/mmcv-logo.png diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/_static/version.json b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/_static/version.json similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/_static/version.json rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/_static/version.json diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/_templates/classtemplate.rst b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/_templates/classtemplate.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/_templates/classtemplate.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/_templates/classtemplate.rst diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/api/arraymisc.rst b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/arraymisc.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/api/arraymisc.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/arraymisc.rst diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/api/cnn.rst b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/cnn.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/api/cnn.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/cnn.rst diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/api/image.rst b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/image.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/api/image.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/image.rst diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/api/ops.rst b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/ops.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/api/ops.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/ops.rst diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/api/transforms.rst b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/transforms.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/api/transforms.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/transforms.rst diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/api/utils.rst b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/utils.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/api/utils.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/utils.rst diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/api/video.rst b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/video.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/api/video.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/video.rst diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/api/visualization.rst b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/visualization.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/api/visualization.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/api/visualization.rst diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/community/code_style.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/community/code_style.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/community/code_style.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/community/code_style.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/community/contributing.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/community/contributing.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/community/contributing.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/community/contributing.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/community/pr.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/community/pr.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/community/pr.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/community/pr.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/compatibility.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/compatibility.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/compatibility.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/compatibility.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/conf.py b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/conf.py similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/conf.py rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/conf.py diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/docutils.conf b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/docutils.conf similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/docutils.conf rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/docutils.conf diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/faq.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/faq.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/faq.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/faq.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/get_started/article.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/get_started/article.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/get_started/article.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/get_started/article.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/get_started/build.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/get_started/build.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/get_started/build.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/get_started/build.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/get_started/installation.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/get_started/installation.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/get_started/installation.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/get_started/installation.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/get_started/introduction.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/get_started/introduction.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/get_started/introduction.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/get_started/introduction.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/get_started/previous_versions.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/get_started/previous_versions.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/get_started/previous_versions.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/get_started/previous_versions.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/index.rst b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/index.rst similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/index.rst rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/index.rst diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/make.bat b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/make.bat similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/make.bat rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/make.bat diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/mmcv-logo.png b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/mmcv-logo.png similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/mmcv-logo.png rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/mmcv-logo.png diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/switch_language.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/switch_language.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/switch_language.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/switch_language.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/cnn.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/understand_mmcv/cnn.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/cnn.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/understand_mmcv/cnn.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/data_process.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/understand_mmcv/data_process.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/data_process.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/understand_mmcv/data_process.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/data_transform.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/understand_mmcv/data_transform.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/data_transform.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/understand_mmcv/data_transform.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/ops.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/understand_mmcv/ops.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/ops.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/understand_mmcv/ops.md diff --git a/cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/visualization.md b/cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/understand_mmcv/visualization.md similarity index 100% rename from cv/distiller/CWD/mmcv/docs/zh_cn/understand_mmcv/visualization.md rename to cv/distiller/CWD/pytorch/mmcv/docs/zh_cn/understand_mmcv/visualization.md diff --git a/cv/distiller/CWD/mmcv/install_mmcv.sh b/cv/distiller/CWD/pytorch/mmcv/install_mmcv.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmcv/install_mmcv.sh rename to cv/distiller/CWD/pytorch/mmcv/install_mmcv.sh diff --git a/cv/distiller/CWD/mmcv/mmcv/__init__.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/__init__.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/__init__.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/__init__.py diff --git a/cv/distiller/CWD/mmcv/mmcv/arraymisc/__init__.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/arraymisc/__init__.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/arraymisc/__init__.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/arraymisc/__init__.py diff --git a/cv/distiller/CWD/mmcv/mmcv/arraymisc/quantization.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/arraymisc/quantization.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/arraymisc/quantization.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/arraymisc/quantization.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/__init__.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/__init__.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/__init__.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/__init__.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/alexnet.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/alexnet.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/alexnet.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/alexnet.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/__init__.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/__init__.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/__init__.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/__init__.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/activation.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/activation.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/activation.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/activation.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/context_block.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/context_block.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/context_block.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/context_block.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/conv.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/conv.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv2d_adaptive_padding.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/conv2d_adaptive_padding.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv2d_adaptive_padding.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/conv2d_adaptive_padding.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv_module.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/conv_module.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv_module.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/conv_module.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv_ws.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/conv_ws.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/conv_ws.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/conv_ws.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/depthwise_separable_conv_module.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/depthwise_separable_conv_module.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/depthwise_separable_conv_module.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/depthwise_separable_conv_module.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/drop.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/drop.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/drop.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/drop.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/generalized_attention.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/generalized_attention.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/generalized_attention.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/generalized_attention.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/hsigmoid.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/hsigmoid.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/hsigmoid.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/hsigmoid.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/hswish.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/hswish.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/hswish.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/hswish.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/non_local.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/non_local.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/non_local.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/non_local.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/norm.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/norm.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/norm.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/norm.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/padding.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/padding.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/padding.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/padding.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/plugin.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/plugin.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/plugin.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/plugin.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/scale.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/scale.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/scale.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/scale.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/swish.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/swish.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/swish.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/swish.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/transformer.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/transformer.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/transformer.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/transformer.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/upsample.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/upsample.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/upsample.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/upsample.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/bricks/wrappers.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/wrappers.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/bricks/wrappers.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/bricks/wrappers.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/resnet.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/resnet.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/resnet.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/resnet.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/utils/__init__.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/utils/__init__.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/utils/__init__.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/utils/__init__.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/utils/flops_counter.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/utils/flops_counter.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/utils/flops_counter.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/utils/flops_counter.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/utils/fuse_conv_bn.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/utils/fuse_conv_bn.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/utils/fuse_conv_bn.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/utils/fuse_conv_bn.py diff --git a/cv/distiller/CWD/mmcv/mmcv/cnn/vgg.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/vgg.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/cnn/vgg.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/cnn/vgg.py diff --git a/cv/distiller/CWD/mmcv/mmcv/image/__init__.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/image/__init__.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/image/__init__.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/image/__init__.py diff --git a/cv/distiller/CWD/mmcv/mmcv/image/colorspace.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/image/colorspace.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/image/colorspace.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/image/colorspace.py diff --git a/cv/distiller/CWD/mmcv/mmcv/image/geometric.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/image/geometric.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/image/geometric.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/image/geometric.py diff --git a/cv/distiller/CWD/mmcv/mmcv/image/io.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/image/io.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/image/io.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/image/io.py diff --git a/cv/distiller/CWD/mmcv/mmcv/image/misc.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/image/misc.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/image/misc.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/image/misc.py diff --git a/cv/distiller/CWD/mmcv/mmcv/image/photometric.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/image/photometric.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/image/photometric.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/image/photometric.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/__init__.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/__init__.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/__init__.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/__init__.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/active_rotated_filter.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/active_rotated_filter.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/active_rotated_filter.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/active_rotated_filter.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/assign_score_withk.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/assign_score_withk.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/assign_score_withk.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/assign_score_withk.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/ball_query.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/ball_query.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/ball_query.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/ball_query.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/bbox.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/bbox.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/bbox.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/bbox.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/bezier_align.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/bezier_align.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/bezier_align.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/bezier_align.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/border_align.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/border_align.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/border_align.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/border_align.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/box_iou_quadri.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/box_iou_quadri.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/box_iou_quadri.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/box_iou_quadri.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/box_iou_rotated.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/box_iou_rotated.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/box_iou_rotated.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/box_iou_rotated.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/carafe.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/carafe.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/carafe.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/carafe.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/cc_attention.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/cc_attention.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/cc_attention.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/cc_attention.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/chamfer_distance.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/chamfer_distance.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/chamfer_distance.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/chamfer_distance.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/contour_expand.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/contour_expand.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/contour_expand.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/contour_expand.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/convex_iou.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/convex_iou.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/convex_iou.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/convex_iou.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/corner_pool.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/corner_pool.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/corner_pool.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/corner_pool.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/correlation.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/correlation.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/correlation.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/correlation.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/README.md b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/README.md similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/README.md rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/README.md diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/box_iou_rotated_utils.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/active_rotated_filter_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/active_rotated_filter_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/active_rotated_filter_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/active_rotated_filter_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/assign_score_withk_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/assign_score_withk_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/assign_score_withk_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/assign_score_withk_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/ball_query_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/ball_query_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/ball_query_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/ball_query_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/bbox_overlaps_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/bbox_overlaps_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/bbox_overlaps_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/bbox_overlaps_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/bezier_align_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/bezier_align_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/bezier_align_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/bezier_align_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/border_align_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/border_align_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/border_align_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/border_align_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/box_iou_quadri_cuda.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/box_iou_quadri_cuda.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/box_iou_quadri_cuda.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/box_iou_quadri_cuda.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/box_iou_rotated_cuda.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/box_iou_rotated_cuda.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/box_iou_rotated_cuda.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/box_iou_rotated_cuda.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/carafe_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/carafe_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/carafe_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/carafe_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/carafe_naive_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/carafe_naive_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/carafe_naive_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/carafe_naive_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/chamfer_distance_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/chamfer_distance_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/chamfer_distance_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/chamfer_distance_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/common_cuda_helper.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/common_cuda_helper.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/common_cuda_helper.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/common_cuda_helper.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/convex_iou_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/convex_iou_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/convex_iou_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/convex_iou_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/correlation_cuda.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/correlation_cuda.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/correlation_cuda.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/correlation_cuda.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/deform_conv_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/deform_conv_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/deform_conv_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/deform_conv_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/deform_roi_pool_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/deform_roi_pool_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/deform_roi_pool_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/deform_roi_pool_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/diff_iou_rotated_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/diff_iou_rotated_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/diff_iou_rotated_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/diff_iou_rotated_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/furthest_point_sample_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/furthest_point_sample_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/furthest_point_sample_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/furthest_point_sample_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/gather_points_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/gather_points_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/gather_points_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/gather_points_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/group_points_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/group_points_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/group_points_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/group_points_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/iou3d_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/iou3d_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/iou3d_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/iou3d_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/knn_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/knn_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/knn_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/knn_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/masked_conv2d_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/masked_conv2d_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/masked_conv2d_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/masked_conv2d_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/min_area_polygons_cuda.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/min_area_polygons_cuda.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/min_area_polygons_cuda.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/min_area_polygons_cuda.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/modulated_deform_conv_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/modulated_deform_conv_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/modulated_deform_conv_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/modulated_deform_conv_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/ms_deform_attn_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/ms_deform_attn_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/ms_deform_attn_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/ms_deform_attn_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/nms_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/nms_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/nms_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/nms_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/nms_quadri_cuda.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/nms_quadri_cuda.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/nms_quadri_cuda.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/nms_quadri_cuda.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/nms_rotated_cuda.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/nms_rotated_cuda.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/nms_rotated_cuda.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/nms_rotated_cuda.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/parrots_cudawarpfunction.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/parrots_cudawarpfunction.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/parrots_cudawarpfunction.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/parrots_cudawarpfunction.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/points_in_boxes_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/points_in_boxes_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/points_in_boxes_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/points_in_boxes_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/points_in_polygons_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/points_in_polygons_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/points_in_polygons_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/points_in_polygons_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/prroi_pool_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/prroi_pool_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/prroi_pool_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/prroi_pool_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/psamask_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/psamask_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/psamask_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/psamask_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/riroi_align_rotated_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/riroi_align_rotated_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/riroi_align_rotated_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/riroi_align_rotated_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roi_align_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/roi_align_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roi_align_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/roi_align_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roi_align_rotated_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/roi_align_rotated_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roi_align_rotated_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/roi_align_rotated_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roi_pool_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/roi_pool_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roi_pool_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/roi_pool_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roiaware_pool3d_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/roiaware_pool3d_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roiaware_pool3d_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/roiaware_pool3d_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roipoint_pool3d_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/roipoint_pool3d_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/roipoint_pool3d_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/roipoint_pool3d_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/rotated_feature_align_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/rotated_feature_align_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/rotated_feature_align_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/rotated_feature_align_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/scatter_points_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/scatter_points_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/scatter_points_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/scatter_points_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/sigmoid_focal_loss_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/sigmoid_focal_loss_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/sigmoid_focal_loss_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/sigmoid_focal_loss_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/softmax_focal_loss_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/softmax_focal_loss_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/softmax_focal_loss_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/softmax_focal_loss_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/stack_ball_query_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/stack_ball_query_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/stack_ball_query_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/stack_ball_query_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/stack_group_points_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/stack_group_points_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/stack_group_points_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/stack_group_points_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/sync_bn_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/sync_bn_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/sync_bn_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/sync_bn_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/three_interpolate_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/three_interpolate_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/three_interpolate_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/three_interpolate_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/three_nn_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/three_nn_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/three_nn_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/three_nn_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/tin_shift_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/tin_shift_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/tin_shift_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/tin_shift_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/voxelization_cuda_kernel.cuh b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/voxelization_cuda_kernel.cuh similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/cuda/voxelization_cuda_kernel.cuh rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/cuda/voxelization_cuda_kernel.cuh diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/bbox_overlaps_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/bbox_overlaps_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/bbox_overlaps_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/bbox_overlaps_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/carafe_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/carafe_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/carafe_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/carafe_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/carafe_utils.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/carafe_utils.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/carafe_utils.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/carafe_utils.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/common_mlu_helper.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/common_mlu_helper.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/common_mlu_helper.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/common_mlu_helper.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/deform_roi_pool_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/deform_roi_pool_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/deform_roi_pool_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/deform_roi_pool_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/focal_loss_sigmoid_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/focal_loss_sigmoid_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/focal_loss_sigmoid_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/focal_loss_sigmoid_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/iou3d_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/iou3d_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/iou3d_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/iou3d_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/iou3d_utils.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/iou3d_utils.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/iou3d_utils.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/iou3d_utils.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/masked_conv2d_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/masked_conv2d_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/masked_conv2d_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/masked_conv2d_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/ms_deform_attn_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/ms_deform_attn_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/ms_deform_attn_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/ms_deform_attn_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/nms_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/nms_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/nms_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/nms_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/nms_utils.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/nms_utils.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/nms_utils.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/nms_utils.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/psamask_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/psamask_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/psamask_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/psamask_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/psamask_utils.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/psamask_utils.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/psamask_utils.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/psamask_utils.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_align_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roi_align_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_align_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roi_align_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_utils.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_utils.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_utils.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roi_align_rotated_utils.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_pool_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roi_pool_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roi_pool_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roi_pool_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roiaware_pool3d_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roiaware_pool3d_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roiaware_pool3d_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roiaware_pool3d_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_large_boxes_num_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_large_boxes_num_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_large_boxes_num_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_large_boxes_num_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/roipoint_pool3d_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/three_nn_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/three_nn_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/three_nn_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/three_nn_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/tin_shift_mlu_kernel.mlu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/tin_shift_mlu_kernel.mlu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mlu/tin_shift_mlu_kernel.mlu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mlu/tin_shift_mlu_kernel.mlu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSDevice.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mps/MPSDevice.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSDevice.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mps/MPSDevice.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.mm b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.mm similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.mm rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mps/MPSLibrary.mm diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSStream.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mps/MPSStream.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSStream.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mps/MPSStream.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSUtils.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mps/MPSUtils.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/mps/MPSUtils.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/mps/MPSUtils.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cpp_helper.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/parrots_cpp_helper.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cpp_helper.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/parrots_cpp_helper.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cuda_helper.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/parrots_cuda_helper.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/parrots_cuda_helper.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/parrots_cuda_helper.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_cpp_helper.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/pytorch_cpp_helper.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_cpp_helper.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/pytorch_cpp_helper.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_cuda_helper.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/pytorch_cuda_helper.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_cuda_helper.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/pytorch_cuda_helper.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_device_registry.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/pytorch_device_registry.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_device_registry.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/pytorch_device_registry.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_mlu_helper.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/pytorch_mlu_helper.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_mlu_helper.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/pytorch_mlu_helper.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_npu_helper.hpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/pytorch_npu_helper.hpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/common/pytorch_npu_helper.hpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/common/pytorch_npu_helper.hpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/active_rotated_filter_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/assign_score_withk.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/assign_score_withk.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/assign_score_withk_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query._parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/ball_query._parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query._parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/ball_query._parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/ball_query.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/ball_query.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/ball_query_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ball_query_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/ball_query_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/bbox_overlaps_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/border_align.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/border_align.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/border_align_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/border_align_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/border_align_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/border_align_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/border_align_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/box_iou_rotated_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe_naive.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe_naive.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe_naive_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe_naive_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe_naive_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_naive_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe_naive_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/carafe_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/carafe_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/chamfer_distance.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/chamfer_distance.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/chamfer_distance_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/contour_expand.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/contour_expand.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/contour_expand_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/contour_expand_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/contour_expand_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/contour_expand_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/contour_expand_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/convex_iou.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/convex_iou.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/convex_iou_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/convex_iou_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/convex_iou_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/convex_iou_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/convex_iou_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/correlation.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/correlation.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/correlation_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/correlation_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/correlation_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/correlation_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/correlation_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/cudabind.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/cudabind.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/cudabind.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/cudabind.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_conv.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_conv.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_conv_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_conv_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_conv_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_conv_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_conv_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/deform_roi_pool_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/diff_iou_rotated_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/focal_loss.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/focal_loss.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/focal_loss_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/focal_loss_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/focal_loss_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/focal_loss_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/focal_loss_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/furthest_point_sample_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_leakyrelu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/fused_bias_leakyrelu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_leakyrelu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/fused_bias_leakyrelu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/fused_bias_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/fused_bias_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/fused_bias_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/gather_points.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/gather_points.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/gather_points_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/gather_points_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/gather_points_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/gather_points_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/gather_points_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/group_points.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/group_points.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/group_points_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/group_points_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/group_points_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/group_points_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/group_points_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/info.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/info.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/info.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/info.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/iou3d.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/iou3d.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/iou3d_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/iou3d_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/iou3d_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/iou3d_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/iou3d_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/knn.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/knn.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/knn_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/knn_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/knn_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/knn_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/knn_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/masked_conv2d.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/masked_conv2d.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/masked_conv2d_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/min_area_polygons.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/min_area_polygons.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/min_area_polygons_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/modulated_deform_conv_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/ms_deform_attn_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/nms.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/nms.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/nms_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/nms_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/nms_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/nms_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/nms_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/nms_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/nms_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/pixel_group.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/pixel_group.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/pixel_group_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/pixel_group_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/pixel_group_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/pixel_group_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/pixel_group_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_boxes.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_boxes.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_boxes_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_polygons.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_polygons.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/points_in_polygons_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/prroi_pool.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/prroi_pool.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/prroi_pool_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/prroi_pool_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/prroi_pool_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/prroi_pool_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/prroi_pool_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/psamask.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/psamask.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/psamask_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/psamask_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/psamask_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/psamask_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/psamask_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/riroi_align_rotated_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_align_rotated_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_pool.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_pool.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_pool_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_pool_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_pool_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roi_pool_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roi_pool_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roiaware_pool3d_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/roipoint_pool3d_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/rotated_feature_align_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/sync_bn.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/sync_bn.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/sync_bn_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/sync_bn_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/sync_bn_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/sync_bn_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/sync_bn_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_interpolate.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_interpolate.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_interpolate_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_interpolate_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_interpolate_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_interpolate_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_interpolate_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_nn.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_nn.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_nn_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_nn_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_nn_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/three_nn_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/three_nn_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/tin_shift.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/tin_shift.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/tin_shift_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/tin_shift_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/tin_shift_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/tin_shift_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/tin_shift_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/upfirdn2d.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/upfirdn2d.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/upfirdn2d_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/upfirdn2d_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/upfirdn2d_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/voxelization.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/voxelization.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_parrots.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/voxelization_parrots.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_parrots.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/voxelization_parrots.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_pytorch.h b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/voxelization_pytorch.h similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/parrots/voxelization_pytorch.h rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/parrots/voxelization_pytorch.h diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/active_rotated_filter.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/active_rotated_filter.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/active_rotated_filter.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/active_rotated_filter.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/assign_score_withk.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/assign_score_withk.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/assign_score_withk.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/assign_score_withk.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/ball_query.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/ball_query.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/ball_query.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/ball_query.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/bbox_overlaps.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/bbox_overlaps.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/bbox_overlaps.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/bbox_overlaps.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/bezier_align.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/bezier_align.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/bezier_align.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/bezier_align.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/border_align.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/border_align.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/border_align.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/border_align.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/box_iou_quadri.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/box_iou_quadri.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/box_iou_quadri.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/box_iou_quadri.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/box_iou_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/box_iou_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/box_iou_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/box_iou_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/carafe.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/carafe.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/carafe.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/carafe.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/carafe_naive.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/carafe_naive.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/carafe_naive.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/carafe_naive.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/chamfer_distance.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/chamfer_distance.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/chamfer_distance.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/chamfer_distance.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/contour_expand.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/contour_expand.cpp old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/contour_expand.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/contour_expand.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/convex_iou.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/convex_iou.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/convex_iou.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/convex_iou.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/correlation.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/correlation.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/correlation.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/correlation.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/active_rotated_filter.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/active_rotated_filter.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/active_rotated_filter.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/active_rotated_filter.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/bezier_align.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/bezier_align.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/bezier_align.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/bezier_align.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_quadri.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_quadri.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_quadri.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_quadri.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/box_iou_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/deform_conv.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/deform_conv.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/deform_conv.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/deform_conv.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/modulated_deform_conv.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/modulated_deform_conv.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/modulated_deform_conv.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/modulated_deform_conv.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/nms.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/nms.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/nms.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/nms.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_quadri.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_quadri.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_quadri.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_quadri.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/nms_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/pixel_group.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/pixel_group.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/pixel_group.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/pixel_group.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/points_in_boxes.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/points_in_boxes.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/points_in_boxes.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/points_in_boxes.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/psamask.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/psamask.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/psamask.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/psamask.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/roi_align_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/rotated_feature_align.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/rotated_feature_align.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/rotated_feature_align.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/rotated_feature_align.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/voxelization.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/voxelization.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cpu/voxelization.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cpu/voxelization.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/active_rotated_filter_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/active_rotated_filter_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/active_rotated_filter_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/active_rotated_filter_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/assign_score_withk_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/assign_score_withk_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/assign_score_withk_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/assign_score_withk_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/ball_query_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/ball_query_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/ball_query_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/ball_query_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/bbox_overlaps_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/bbox_overlaps_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/bbox_overlaps_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/bbox_overlaps_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/bezier_align_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/bezier_align_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/bezier_align_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/bezier_align_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/border_align_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/border_align_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/border_align_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/border_align_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_quadri_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_quadri_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_quadri_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_quadri_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_rotated_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_rotated_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_rotated_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/box_iou_rotated_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_naive_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_naive_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_naive_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/carafe_naive_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/chamfer_distance_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/chamfer_distance_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/chamfer_distance_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/chamfer_distance_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/convex_iou.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/convex_iou.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/convex_iou.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/convex_iou.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/correlation_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/correlation_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/correlation_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/correlation_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/cudabind.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_conv_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_conv_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_conv_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_conv_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_roi_pool_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_roi_pool_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_roi_pool_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/deform_roi_pool_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/diff_iou_rotated_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/diff_iou_rotated_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/diff_iou_rotated_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/diff_iou_rotated_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/focal_loss_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/focal_loss_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/focal_loss_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/focal_loss_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/furthest_point_sample_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/fused_bias_leakyrelu_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/fused_bias_leakyrelu_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/fused_bias_leakyrelu_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/fused_bias_leakyrelu_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/gather_points_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/gather_points_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/gather_points_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/gather_points_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/group_points_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/group_points_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/group_points_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/group_points_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/iou3d_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/iou3d_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/iou3d_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/iou3d_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/knn_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/knn_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/knn_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/knn_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/masked_conv2d_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/masked_conv2d_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/masked_conv2d_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/masked_conv2d_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/min_area_polygons.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/min_area_polygons.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/min_area_polygons.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/min_area_polygons.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/modulated_deform_conv_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/modulated_deform_conv_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/modulated_deform_conv_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/modulated_deform_conv_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/ms_deform_attn_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/ms_deform_attn_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/ms_deform_attn_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/ms_deform_attn_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_quadri_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_quadri_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_quadri_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_quadri_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_rotated_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_rotated_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_rotated_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/nms_rotated_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_boxes_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_boxes_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_boxes_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_boxes_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_polygons_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_polygons_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_polygons_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/points_in_polygons_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/prroi_pool_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/prroi_pool_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/prroi_pool_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/prroi_pool_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/psamask_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/psamask_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/psamask_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/psamask_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/riroi_align_rotated_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/riroi_align_rotated_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/riroi_align_rotated_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/riroi_align_rotated_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_rotated_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_rotated_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_rotated_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_align_rotated_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_pool_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_pool_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_pool_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/roi_pool_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roiaware_pool3d_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/roiaware_pool3d_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roiaware_pool3d_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/roiaware_pool3d_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roipoint_pool3d_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/roipoint_pool3d_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/roipoint_pool3d_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/roipoint_pool3d_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/rotated_feature_align_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/rotated_feature_align_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/rotated_feature_align_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/rotated_feature_align_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/scatter_points_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/scatter_points_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/scatter_points_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/scatter_points_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_ball_query_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_ball_query_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_ball_query_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_ball_query_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_group_points_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_group_points_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_group_points_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/stack_group_points_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/sync_bn_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/sync_bn_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/sync_bn_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/sync_bn_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/three_interpolate_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/three_interpolate_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/three_interpolate_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/three_interpolate_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/three_nn_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/three_nn_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/three_nn_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/three_nn_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/tin_shift_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/tin_shift_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/tin_shift_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/tin_shift_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/upfirdn2d_kernel.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/upfirdn2d_kernel.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/upfirdn2d_kernel.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/upfirdn2d_kernel.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/voxelization_cuda.cu b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/voxelization_cuda.cu similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/cuda/voxelization_cuda.cu rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/cuda/voxelization_cuda.cu diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/deform_conv.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/deform_conv.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/deform_conv.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/deform_conv.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/deform_roi_pool.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/deform_roi_pool.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/deform_roi_pool.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/deform_roi_pool.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/diff_iou_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/diff_iou_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/diff_iou_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/diff_iou_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/focal_loss.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/focal_loss.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/focal_loss.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/focal_loss.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/furthest_point_sample.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/furthest_point_sample.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/furthest_point_sample.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/furthest_point_sample.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/fused_bias_leakyrelu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/fused_bias_leakyrelu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/fused_bias_leakyrelu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/fused_bias_leakyrelu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/fused_spconv_ops.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/fused_spconv_ops.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/fused_spconv_ops.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/fused_spconv_ops.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/gather_points.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/gather_points.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/gather_points.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/gather_points.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/group_points.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/group_points.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/group_points.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/group_points.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/info.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/info.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/info.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/info.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/iou3d.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/iou3d.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/iou3d.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/iou3d.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/knn.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/knn.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/knn.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/knn.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/masked_conv2d.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/masked_conv2d.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/masked_conv2d.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/masked_conv2d.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/min_area_polygons.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/min_area_polygons.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/min_area_polygons.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/min_area_polygons.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/bbox_overlaps_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/bbox_overlaps_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/bbox_overlaps_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/bbox_overlaps_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/carafe_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/carafe_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/carafe_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/carafe_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/deform_roi_pool_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/deform_roi_pool_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/deform_roi_pool_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/deform_roi_pool_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/focal_loss_sigmoid_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/focal_loss_sigmoid_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/focal_loss_sigmoid_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/focal_loss_sigmoid_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/iou3d_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/iou3d_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/iou3d_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/iou3d_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/masked_conv2d_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/masked_conv2d_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/masked_conv2d_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/masked_conv2d_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/ms_deform_attn_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/ms_deform_attn_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/ms_deform_attn_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/ms_deform_attn_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/nms_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/nms_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/nms_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/nms_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/psamask_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/psamask_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/psamask_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/psamask_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_rotated_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_rotated_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_rotated_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_align_rotated_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_pool_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_pool_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_pool_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/roi_pool_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roiaware_pool3d_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/roiaware_pool3d_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roiaware_pool3d_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/roiaware_pool3d_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roipoint_pool3d_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/roipoint_pool3d_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/roipoint_pool3d_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/roipoint_pool3d_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/three_nn_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/three_nn_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/three_nn_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/three_nn_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/tin_shift_mlu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/tin_shift_mlu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mlu/tin_shift_mlu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mlu/tin_shift_mlu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/modulated_deform_conv.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/modulated_deform_conv.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/modulated_deform_conv.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/modulated_deform_conv.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mps/bbox_overlaps_mps.mm b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mps/bbox_overlaps_mps.mm similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/mps/bbox_overlaps_mps.mm rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/mps/bbox_overlaps_mps.mm diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/ms_deform_attn.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/ms_deform_attn.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/ms_deform_attn.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/ms_deform_attn.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/nms.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/nms.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/nms.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/nms.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/nms_quadri.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/nms_quadri.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/nms_quadri.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/nms_quadri.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/nms_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/nms_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/nms_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/nms_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/deform_roi_pool.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/deform_roi_pool.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/deform_roi_pool.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/deform_roi_pool.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/focal_loss_npu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/focal_loss_npu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/focal_loss_npu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/focal_loss_npu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/fused_bias_leakyrelu_npu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/fused_bias_leakyrelu_npu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/fused_bias_leakyrelu_npu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/fused_bias_leakyrelu_npu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/nms_npu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/nms_npu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/nms_npu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/nms_npu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/psa_mask_npu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/psa_mask_npu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/psa_mask_npu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/psa_mask_npu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/roi_pool_npu.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/roi_pool_npu.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/npu/roi_pool_npu.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/npu/roi_pool_npu.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pixel_group.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/pixel_group.cpp old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pixel_group.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/pixel_group.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/points_in_boxes.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/points_in_boxes.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/points_in_boxes.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/points_in_boxes.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/points_in_polygons.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/points_in_polygons.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/points_in_polygons.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/points_in_polygons.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/prroi_pool.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/prroi_pool.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/prroi_pool.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/prroi_pool.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/psamask.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/psamask.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/psamask.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/psamask.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/pybind.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/riroi_align_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/riroi_align_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/riroi_align_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/riroi_align_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roi_align.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/roi_align.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roi_align.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/roi_align.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roi_align_rotated.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/roi_align_rotated.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roi_align_rotated.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/roi_align_rotated.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roi_pool.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/roi_pool.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roi_pool.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/roi_pool.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roiaware_pool3d.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/roiaware_pool3d.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roiaware_pool3d.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/roiaware_pool3d.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roipoint_pool3d.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/roipoint_pool3d.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/roipoint_pool3d.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/roipoint_pool3d.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/rotated_feature_align.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/rotated_feature_align.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/rotated_feature_align.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/rotated_feature_align.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/scatter_points.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/scatter_points.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/scatter_points.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/scatter_points.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/sync_bn.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/sync_bn.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/sync_bn.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/sync_bn.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/three_interpolate.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/three_interpolate.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/three_interpolate.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/three_interpolate.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/three_nn.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/three_nn.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/three_nn.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/three_nn.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/tin_shift.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/tin_shift.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/tin_shift.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/tin_shift.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/upfirdn2d.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/upfirdn2d.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/upfirdn2d.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/upfirdn2d.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/voxelization.cpp b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/voxelization.cpp similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/csrc/pytorch/voxelization.cpp rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/csrc/pytorch/voxelization.cpp diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/deform_conv.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/deform_conv.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/deform_conv.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/deform_conv.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/deform_roi_pool.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/deform_roi_pool.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/deform_roi_pool.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/deform_roi_pool.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/deprecated_wrappers.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/deprecated_wrappers.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/deprecated_wrappers.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/deprecated_wrappers.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/diff_iou_rotated.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/diff_iou_rotated.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/diff_iou_rotated.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/diff_iou_rotated.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/focal_loss.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/focal_loss.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/focal_loss.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/focal_loss.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/furthest_point_sample.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/furthest_point_sample.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/furthest_point_sample.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/furthest_point_sample.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/fused_bias_leakyrelu.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/fused_bias_leakyrelu.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/fused_bias_leakyrelu.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/fused_bias_leakyrelu.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/gather_points.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/gather_points.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/gather_points.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/gather_points.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/group_points.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/group_points.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/group_points.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/group_points.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/info.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/info.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/info.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/info.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/iou3d.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/iou3d.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/iou3d.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/iou3d.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/knn.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/knn.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/knn.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/knn.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/masked_conv.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/masked_conv.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/masked_conv.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/masked_conv.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/merge_cells.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/merge_cells.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/merge_cells.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/merge_cells.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/min_area_polygons.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/min_area_polygons.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/min_area_polygons.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/min_area_polygons.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/modulated_deform_conv.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/modulated_deform_conv.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/modulated_deform_conv.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/modulated_deform_conv.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/multi_scale_deform_attn.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/multi_scale_deform_attn.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/multi_scale_deform_attn.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/multi_scale_deform_attn.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/nms.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/nms.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/nms.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/nms.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/pixel_group.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/pixel_group.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/pixel_group.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/pixel_group.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/point_sample.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/point_sample.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/point_sample.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/point_sample.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/points_in_boxes.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/points_in_boxes.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/points_in_boxes.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/points_in_boxes.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/points_in_polygons.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/points_in_polygons.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/points_in_polygons.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/points_in_polygons.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/points_sampler.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/points_sampler.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/points_sampler.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/points_sampler.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/prroi_pool.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/prroi_pool.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/prroi_pool.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/prroi_pool.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/psa_mask.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/psa_mask.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/psa_mask.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/psa_mask.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/riroi_align_rotated.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/riroi_align_rotated.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/riroi_align_rotated.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/riroi_align_rotated.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/roi_align.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/roi_align.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/roi_align.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/roi_align.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/roi_align_rotated.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/roi_align_rotated.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/roi_align_rotated.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/roi_align_rotated.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/roi_pool.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/roi_pool.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/roi_pool.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/roi_pool.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/roiaware_pool3d.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/roiaware_pool3d.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/roiaware_pool3d.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/roiaware_pool3d.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/roipoint_pool3d.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/roipoint_pool3d.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/roipoint_pool3d.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/roipoint_pool3d.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/rotated_feature_align.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/rotated_feature_align.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/rotated_feature_align.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/rotated_feature_align.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/saconv.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/saconv.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/saconv.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/saconv.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/scatter_points.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/scatter_points.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/scatter_points.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/scatter_points.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/sync_bn.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/sync_bn.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/sync_bn.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/sync_bn.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/three_interpolate.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/three_interpolate.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/three_interpolate.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/three_interpolate.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/three_nn.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/three_nn.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/three_nn.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/three_nn.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/tin_shift.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/tin_shift.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/tin_shift.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/tin_shift.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/upfirdn2d.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/upfirdn2d.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/upfirdn2d.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/upfirdn2d.py diff --git a/cv/distiller/CWD/mmcv/mmcv/ops/voxelize.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/ops/voxelize.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/ops/voxelize.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/ops/voxelize.py diff --git a/cv/distiller/CWD/mmcv/mmcv/transforms/__init__.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/__init__.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/transforms/__init__.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/__init__.py diff --git a/cv/distiller/CWD/mmcv/mmcv/transforms/base.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/base.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/transforms/base.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/base.py diff --git a/cv/distiller/CWD/mmcv/mmcv/transforms/builder.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/builder.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/transforms/builder.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/builder.py diff --git a/cv/distiller/CWD/mmcv/mmcv/transforms/formatting.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/formatting.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/transforms/formatting.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/formatting.py diff --git a/cv/distiller/CWD/mmcv/mmcv/transforms/loading.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/loading.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/transforms/loading.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/loading.py diff --git a/cv/distiller/CWD/mmcv/mmcv/transforms/processing.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/processing.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/transforms/processing.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/processing.py diff --git a/cv/distiller/CWD/mmcv/mmcv/transforms/utils.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/utils.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/transforms/utils.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/utils.py diff --git a/cv/distiller/CWD/mmcv/mmcv/transforms/wrappers.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/wrappers.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/transforms/wrappers.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/transforms/wrappers.py diff --git a/cv/distiller/CWD/mmcv/mmcv/utils/__init__.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/utils/__init__.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/utils/__init__.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/utils/__init__.py diff --git a/cv/distiller/CWD/mmcv/mmcv/utils/device_type.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/utils/device_type.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/utils/device_type.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/utils/device_type.py diff --git a/cv/distiller/CWD/mmcv/mmcv/utils/env.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/utils/env.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/utils/env.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/utils/env.py diff --git a/cv/distiller/CWD/mmcv/mmcv/utils/ext_loader.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/utils/ext_loader.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/utils/ext_loader.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/utils/ext_loader.py diff --git a/cv/distiller/CWD/mmcv/mmcv/utils/parrots_jit.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/utils/parrots_jit.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/utils/parrots_jit.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/utils/parrots_jit.py diff --git a/cv/distiller/CWD/mmcv/mmcv/version.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/version.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/version.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/version.py diff --git a/cv/distiller/CWD/mmcv/mmcv/video/__init__.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/video/__init__.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/video/__init__.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/video/__init__.py diff --git a/cv/distiller/CWD/mmcv/mmcv/video/io.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/video/io.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/video/io.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/video/io.py diff --git a/cv/distiller/CWD/mmcv/mmcv/video/optflow.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/video/optflow.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/video/optflow.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/video/optflow.py diff --git a/cv/distiller/CWD/mmcv/mmcv/video/processing.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/video/processing.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/video/processing.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/video/processing.py diff --git a/cv/distiller/CWD/mmcv/mmcv/visualization/__init__.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/visualization/__init__.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/visualization/__init__.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/visualization/__init__.py diff --git a/cv/distiller/CWD/mmcv/mmcv/visualization/color.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/visualization/color.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/visualization/color.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/visualization/color.py diff --git a/cv/distiller/CWD/mmcv/mmcv/visualization/image.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/visualization/image.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/visualization/image.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/visualization/image.py diff --git a/cv/distiller/CWD/mmcv/mmcv/visualization/optflow.py b/cv/distiller/CWD/pytorch/mmcv/mmcv/visualization/optflow.py similarity index 100% rename from cv/distiller/CWD/mmcv/mmcv/visualization/optflow.py rename to cv/distiller/CWD/pytorch/mmcv/mmcv/visualization/optflow.py diff --git a/cv/distiller/CWD/mmcv/requirements.txt b/cv/distiller/CWD/pytorch/mmcv/requirements.txt similarity index 100% rename from cv/distiller/CWD/mmcv/requirements.txt rename to cv/distiller/CWD/pytorch/mmcv/requirements.txt diff --git a/cv/distiller/CWD/mmcv/requirements/build.txt b/cv/distiller/CWD/pytorch/mmcv/requirements/build.txt similarity index 100% rename from cv/distiller/CWD/mmcv/requirements/build.txt rename to cv/distiller/CWD/pytorch/mmcv/requirements/build.txt diff --git a/cv/distiller/CWD/mmcv/requirements/docs.txt b/cv/distiller/CWD/pytorch/mmcv/requirements/docs.txt similarity index 100% rename from cv/distiller/CWD/mmcv/requirements/docs.txt rename to cv/distiller/CWD/pytorch/mmcv/requirements/docs.txt diff --git a/cv/distiller/CWD/mmcv/requirements/optional.txt b/cv/distiller/CWD/pytorch/mmcv/requirements/optional.txt similarity index 100% rename from cv/distiller/CWD/mmcv/requirements/optional.txt rename to cv/distiller/CWD/pytorch/mmcv/requirements/optional.txt diff --git a/cv/distiller/CWD/mmcv/requirements/runtime.txt b/cv/distiller/CWD/pytorch/mmcv/requirements/runtime.txt similarity index 100% rename from cv/distiller/CWD/mmcv/requirements/runtime.txt rename to cv/distiller/CWD/pytorch/mmcv/requirements/runtime.txt diff --git a/cv/distiller/CWD/mmcv/requirements/test.txt b/cv/distiller/CWD/pytorch/mmcv/requirements/test.txt similarity index 100% rename from cv/distiller/CWD/mmcv/requirements/test.txt rename to cv/distiller/CWD/pytorch/mmcv/requirements/test.txt diff --git a/cv/distiller/CWD/mmcv/setup.cfg b/cv/distiller/CWD/pytorch/mmcv/setup.cfg similarity index 100% rename from cv/distiller/CWD/mmcv/setup.cfg rename to cv/distiller/CWD/pytorch/mmcv/setup.cfg diff --git a/cv/distiller/CWD/mmcv/setup.py b/cv/distiller/CWD/pytorch/mmcv/setup.py similarity index 100% rename from cv/distiller/CWD/mmcv/setup.py rename to cv/distiller/CWD/pytorch/mmcv/setup.py diff --git a/cv/distiller/CWD/mmcv/tests/data/batched_nms_data.pkl b/cv/distiller/CWD/pytorch/mmcv/tests/data/batched_nms_data.pkl similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/batched_nms_data.pkl rename to cv/distiller/CWD/pytorch/mmcv/tests/data/batched_nms_data.pkl diff --git a/cv/distiller/CWD/mmcv/tests/data/color.jpg b/cv/distiller/CWD/pytorch/mmcv/tests/data/color.jpg similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/color.jpg rename to cv/distiller/CWD/pytorch/mmcv/tests/data/color.jpg diff --git a/cv/distiller/CWD/mmcv/tests/data/color_exif.jpg b/cv/distiller/CWD/pytorch/mmcv/tests/data/color_exif.jpg similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/color_exif.jpg rename to cv/distiller/CWD/pytorch/mmcv/tests/data/color_exif.jpg diff --git a/cv/distiller/CWD/mmcv/tests/data/config/a.b.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/a.b.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/a.b.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/a.b.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/a.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/a.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/a.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/a.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/b.json b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/b.json similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/b.json rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/b.json diff --git a/cv/distiller/CWD/mmcv/tests/data/config/base.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/base.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/base.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/base.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/c.yaml b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/c.yaml similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/c.yaml rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/c.yaml diff --git a/cv/distiller/CWD/mmcv/tests/data/config/code.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/code.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/code.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/code.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/d.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/d.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/d.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/d.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/delete.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/delete.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/delete.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/delete.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/deprecated.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/deprecated.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/deprecated.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/deprecated.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/deprecated_as_base.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/deprecated_as_base.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/deprecated_as_base.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/deprecated_as_base.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/e.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/e.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/e.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/e.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/expected.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/expected.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/expected.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/expected.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/f.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/f.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/f.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/f.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/g.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/g.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/g.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/g.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/h.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/h.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/h.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/h.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/i_base.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/i_base.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/i_base.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/i_base.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/i_child.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/i_child.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/i_child.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/i_child.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/l.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/l.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/l.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/l.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/l1.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/l1.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/l1.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/l1.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/l2.yaml b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/l2.yaml similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/l2.yaml rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/l2.yaml diff --git a/cv/distiller/CWD/mmcv/tests/data/config/l3.json b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/l3.json similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/l3.json rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/l3.json diff --git a/cv/distiller/CWD/mmcv/tests/data/config/l4.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/l4.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/l4.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/l4.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/m.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/m.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/m.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/m.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/n.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/n.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/n.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/n.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/o.json b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/o.json similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/o.json rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/o.json diff --git a/cv/distiller/CWD/mmcv/tests/data/config/p.yaml b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/p.yaml similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/p.yaml rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/p.yaml diff --git a/cv/distiller/CWD/mmcv/tests/data/config/q.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/q.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/q.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/q.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/r.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/r.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/r.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/r.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/s.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/s.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/s.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/s.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/t.json b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/t.json similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/t.json rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/t.json diff --git a/cv/distiller/CWD/mmcv/tests/data/config/t.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/t.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/t.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/t.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/t.yaml b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/t.yaml similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/t.yaml rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/t.yaml diff --git a/cv/distiller/CWD/mmcv/tests/data/config/u.json b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/u.json similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/u.json rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/u.json diff --git a/cv/distiller/CWD/mmcv/tests/data/config/u.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/u.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/u.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/u.py diff --git a/cv/distiller/CWD/mmcv/tests/data/config/u.yaml b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/u.yaml similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/u.yaml rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/u.yaml diff --git a/cv/distiller/CWD/mmcv/tests/data/config/v.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/config/v.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/config/v.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/config/v.py diff --git a/cv/distiller/CWD/mmcv/tests/data/demo.lmdb/data.mdb b/cv/distiller/CWD/pytorch/mmcv/tests/data/demo.lmdb/data.mdb similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/demo.lmdb/data.mdb rename to cv/distiller/CWD/pytorch/mmcv/tests/data/demo.lmdb/data.mdb diff --git a/cv/distiller/CWD/mmcv/tests/data/demo.lmdb/lock.mdb b/cv/distiller/CWD/pytorch/mmcv/tests/data/demo.lmdb/lock.mdb similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/demo.lmdb/lock.mdb rename to cv/distiller/CWD/pytorch/mmcv/tests/data/demo.lmdb/lock.mdb diff --git a/cv/distiller/CWD/mmcv/tests/data/filelist.txt b/cv/distiller/CWD/pytorch/mmcv/tests/data/filelist.txt similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/filelist.txt rename to cv/distiller/CWD/pytorch/mmcv/tests/data/filelist.txt diff --git a/cv/distiller/CWD/mmcv/tests/data/for_3d_ops/features_for_fps_distance.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_3d_ops/features_for_fps_distance.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_3d_ops/features_for_fps_distance.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_3d_ops/features_for_fps_distance.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/for_3d_ops/fps_idx.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_3d_ops/fps_idx.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_3d_ops/fps_idx.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_3d_ops/fps_idx.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/for_3d_ops/test_voxel.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_3d_ops/test_voxel.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_3d_ops/test_voxel.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_3d_ops/test_voxel.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_feat.bin b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_carafe/carafe_feat.bin similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_feat.bin rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_carafe/carafe_feat.bin diff --git a/cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_feat_grad.bin b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_carafe/carafe_feat_grad.bin similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_feat_grad.bin rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_carafe/carafe_feat_grad.bin diff --git a/cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_mask.bin b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_carafe/carafe_mask.bin similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_mask.bin rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_carafe/carafe_mask.bin diff --git a/cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_mask_grad.bin b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_carafe/carafe_mask_grad.bin similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_mask_grad.bin rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_carafe/carafe_mask_grad.bin diff --git a/cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_output.bin b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_carafe/carafe_output.bin similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_carafe/carafe_output.bin rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_carafe/carafe_output.bin diff --git a/cv/distiller/CWD/mmcv/tests/data/for_ccattention/ccattention_input.bin b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_ccattention/ccattention_input.bin similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_ccattention/ccattention_input.bin rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_ccattention/ccattention_input.bin diff --git a/cv/distiller/CWD/mmcv/tests/data/for_ccattention/ccattention_output.bin b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_ccattention/ccattention_output.bin similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_ccattention/ccattention_output.bin rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_ccattention/ccattention_output.bin diff --git a/cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_bias.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_bias.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_bias.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_bias.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_input.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_input.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_input.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_input.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_mask.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_mask.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_mask.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_mask.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_output.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_output.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_output.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_output.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_weight.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_weight.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_weight.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_masked_conv2d/masked_conv2d_for_weight.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/for_psa_mask/psa_input.bin b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_psa_mask/psa_input.bin similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_psa_mask/psa_input.bin rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_psa_mask/psa_input.bin diff --git a/cv/distiller/CWD/mmcv/tests/data/for_psa_mask/psa_output_collect.bin b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_psa_mask/psa_output_collect.bin similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_psa_mask/psa_output_collect.bin rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_psa_mask/psa_output_collect.bin diff --git a/cv/distiller/CWD/mmcv/tests/data/for_psa_mask/psa_output_distribute.bin b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_psa_mask/psa_output_distribute.bin similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_psa_mask/psa_output_distribute.bin rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_psa_mask/psa_output_distribute.bin diff --git a/cv/distiller/CWD/mmcv/tests/data/for_scan/.file b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/.file similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_scan/.file rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/.file diff --git a/cv/distiller/CWD/mmcv/tests/data/for_scan/1.json b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/1.json similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_scan/1.json rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/1.json diff --git a/cv/distiller/CWD/mmcv/tests/data/for_scan/1.txt b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/1.txt similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_scan/1.txt rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/1.txt diff --git a/cv/distiller/CWD/mmcv/tests/data/for_scan/2.json b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/2.json similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_scan/2.json rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/2.json diff --git a/cv/distiller/CWD/mmcv/tests/data/for_scan/2.txt b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/2.txt similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_scan/2.txt rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/2.txt diff --git a/cv/distiller/CWD/mmcv/tests/data/for_scan/3.TXT b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/3.TXT similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_scan/3.TXT rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/3.TXT diff --git a/cv/distiller/CWD/mmcv/tests/data/for_scan/a.bin b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/a.bin similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_scan/a.bin rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/a.bin diff --git a/cv/distiller/CWD/mmcv/tests/data/for_scan/sub/1.json b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/sub/1.json similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_scan/sub/1.json rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/sub/1.json diff --git a/cv/distiller/CWD/mmcv/tests/data/for_scan/sub/1.txt b/cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/sub/1.txt similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/for_scan/sub/1.txt rename to cv/distiller/CWD/pytorch/mmcv/tests/data/for_scan/sub/1.txt diff --git a/cv/distiller/CWD/mmcv/tests/data/gray_alpha.png b/cv/distiller/CWD/pytorch/mmcv/tests/data/gray_alpha.png similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/gray_alpha.png rename to cv/distiller/CWD/pytorch/mmcv/tests/data/gray_alpha.png diff --git a/cv/distiller/CWD/mmcv/tests/data/grayscale.jpg b/cv/distiller/CWD/pytorch/mmcv/tests/data/grayscale.jpg similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/grayscale.jpg rename to cv/distiller/CWD/pytorch/mmcv/tests/data/grayscale.jpg diff --git a/cv/distiller/CWD/mmcv/tests/data/grayscale_dim3.jpg b/cv/distiller/CWD/pytorch/mmcv/tests/data/grayscale_dim3.jpg similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/grayscale_dim3.jpg rename to cv/distiller/CWD/pytorch/mmcv/tests/data/grayscale_dim3.jpg diff --git a/cv/distiller/CWD/mmcv/tests/data/mapping.txt b/cv/distiller/CWD/pytorch/mmcv/tests/data/mapping.txt similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/mapping.txt rename to cv/distiller/CWD/pytorch/mmcv/tests/data/mapping.txt diff --git a/cv/distiller/CWD/mmcv/tests/data/optflow.flo b/cv/distiller/CWD/pytorch/mmcv/tests/data/optflow.flo similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/optflow.flo rename to cv/distiller/CWD/pytorch/mmcv/tests/data/optflow.flo diff --git a/cv/distiller/CWD/mmcv/tests/data/optflow_concat0.jpg b/cv/distiller/CWD/pytorch/mmcv/tests/data/optflow_concat0.jpg similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/optflow_concat0.jpg rename to cv/distiller/CWD/pytorch/mmcv/tests/data/optflow_concat0.jpg diff --git a/cv/distiller/CWD/mmcv/tests/data/optflow_concat1.jpg b/cv/distiller/CWD/pytorch/mmcv/tests/data/optflow_concat1.jpg similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/optflow_concat1.jpg rename to cv/distiller/CWD/pytorch/mmcv/tests/data/optflow_concat1.jpg diff --git a/cv/distiller/CWD/mmcv/tests/data/palette.gif b/cv/distiller/CWD/pytorch/mmcv/tests/data/palette.gif similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/palette.gif rename to cv/distiller/CWD/pytorch/mmcv/tests/data/palette.gif diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/0.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/0.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/0.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/0.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/1.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/1.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/1.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/1.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/2.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/2.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/2.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/2.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/3.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/3.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/3.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/3.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/4.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/4.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/4.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/4.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/pad0_0.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad0_0.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/pad0_0.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad0_0.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/pad0_1.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad0_1.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/pad0_1.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad0_1.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/pad0_2.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad0_2.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/pad0_2.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad0_2.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/pad0_3.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad0_3.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/pad0_3.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad0_3.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/pad0_4.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad0_4.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/pad0_4.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad0_4.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/pad_0.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad_0.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/pad_0.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad_0.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/pad_1.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad_1.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/pad_1.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad_1.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/pad_2.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad_2.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/pad_2.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad_2.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/pad_3.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad_3.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/pad_3.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad_3.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/pad_4.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad_4.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/pad_4.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/pad_4.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/scale_0.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/scale_0.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/scale_0.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/scale_0.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/scale_1.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/scale_1.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/scale_1.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/scale_1.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/scale_2.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/scale_2.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/scale_2.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/scale_2.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/scale_3.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/scale_3.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/scale_3.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/scale_3.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/scale_4.npy b/cv/distiller/CWD/pytorch/mmcv/tests/data/patches/scale_4.npy similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/patches/scale_4.npy rename to cv/distiller/CWD/pytorch/mmcv/tests/data/patches/scale_4.npy diff --git a/cv/distiller/CWD/mmcv/tests/data/scripts/hello.py b/cv/distiller/CWD/pytorch/mmcv/tests/data/scripts/hello.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/scripts/hello.py rename to cv/distiller/CWD/pytorch/mmcv/tests/data/scripts/hello.py diff --git a/cv/distiller/CWD/mmcv/tests/data/sparse_flow.png b/cv/distiller/CWD/pytorch/mmcv/tests/data/sparse_flow.png old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/sparse_flow.png rename to cv/distiller/CWD/pytorch/mmcv/tests/data/sparse_flow.png diff --git a/cv/distiller/CWD/mmcv/tests/data/test.mp4 b/cv/distiller/CWD/pytorch/mmcv/tests/data/test.mp4 similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/test.mp4 rename to cv/distiller/CWD/pytorch/mmcv/tests/data/test.mp4 diff --git a/cv/distiller/CWD/mmcv/tests/data/uint16-5channel.tif b/cv/distiller/CWD/pytorch/mmcv/tests/data/uint16-5channel.tif similarity index 100% rename from cv/distiller/CWD/mmcv/tests/data/uint16-5channel.tif rename to cv/distiller/CWD/pytorch/mmcv/tests/data/uint16-5channel.tif diff --git a/cv/distiller/CWD/mmcv/tests/test_arraymisc.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_arraymisc.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_arraymisc.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_arraymisc.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_build_layers.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_build_layers.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_build_layers.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_build_layers.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_context_block.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_context_block.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_context_block.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_context_block.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_conv2d_adaptive_padding.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_conv2d_adaptive_padding.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_conv2d_adaptive_padding.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_conv2d_adaptive_padding.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_conv_module.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_conv_module.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_conv_module.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_conv_module.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_depthwise_seperable_conv_module.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_depthwise_seperable_conv_module.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_depthwise_seperable_conv_module.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_depthwise_seperable_conv_module.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_flops_counter.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_flops_counter.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_flops_counter.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_flops_counter.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_fuse_conv_bn.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_fuse_conv_bn.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_fuse_conv_bn.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_fuse_conv_bn.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_generalized_attention.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_generalized_attention.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_generalized_attention.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_generalized_attention.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_hsigmoid.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_hsigmoid.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_hsigmoid.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_hsigmoid.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_hswish.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_hswish.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_hswish.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_hswish.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_non_local.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_non_local.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_non_local.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_non_local.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_scale.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_scale.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_scale.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_scale.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_silu.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_silu.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_silu.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_silu.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_swish.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_swish.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_swish.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_swish.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_transformer.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_transformer.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_transformer.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_transformer.py diff --git a/cv/distiller/CWD/mmcv/tests/test_cnn/test_wrappers.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_wrappers.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_cnn/test_wrappers.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_cnn/test_wrappers.py diff --git a/cv/distiller/CWD/mmcv/tests/test_image/test_colorspace.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_image/test_colorspace.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_image/test_colorspace.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_image/test_colorspace.py diff --git a/cv/distiller/CWD/mmcv/tests/test_image/test_geometric.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_image/test_geometric.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_image/test_geometric.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_image/test_geometric.py diff --git a/cv/distiller/CWD/mmcv/tests/test_image/test_image_misc.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_image/test_image_misc.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_image/test_image_misc.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_image/test_image_misc.py diff --git a/cv/distiller/CWD/mmcv/tests/test_image/test_io.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_image/test_io.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_image/test_io.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_image/test_io.py diff --git a/cv/distiller/CWD/mmcv/tests/test_image/test_photometric.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_image/test_photometric.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_image/test_photometric.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_image/test_photometric.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/output.pkl b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/output.pkl similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/output.pkl rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/output.pkl diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_active_rotated_filter.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_active_rotated_filter.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_active_rotated_filter.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_active_rotated_filter.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_assign_score_withk.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_assign_score_withk.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_assign_score_withk.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_assign_score_withk.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_ball_query.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_ball_query.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_ball_query.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_ball_query.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_bbox.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_bbox.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_bbox.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_bbox.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_bezier_align.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_bezier_align.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_bezier_align.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_bezier_align.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_bilinear_grid_sample.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_bilinear_grid_sample.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_bilinear_grid_sample.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_bilinear_grid_sample.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_border_align.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_border_align.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_border_align.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_border_align.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_quadri.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_box_iou_quadri.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_quadri.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_box_iou_quadri.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_rotated.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_box_iou_rotated.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_box_iou_rotated.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_box_iou_rotated.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_carafe.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_carafe.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_carafe.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_carafe.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_cc_attention.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_cc_attention.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_cc_attention.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_cc_attention.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_chamfer_distance.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_chamfer_distance.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_chamfer_distance.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_chamfer_distance.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_contour_expand.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_contour_expand.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_contour_expand.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_contour_expand.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_convex_iou.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_convex_iou.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_convex_iou.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_convex_iou.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_corner_pool.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_corner_pool.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_corner_pool.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_corner_pool.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_correlation.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_correlation.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_correlation.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_correlation.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_conv.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_deform_conv.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_deform_conv.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_deform_conv.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_deform_roi_pool.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_deform_roi_pool.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_deform_roi_pool.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_deform_roi_pool.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_diff_iou_rotated.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_diff_iou_rotated.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_diff_iou_rotated.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_diff_iou_rotated.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_focal_loss.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_focal_loss.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_focal_loss.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_focal_loss.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_furthest_point_sample.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_furthest_point_sample.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_furthest_point_sample.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_furthest_point_sample.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_fused_bias_leakyrelu.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_fused_bias_leakyrelu.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_fused_bias_leakyrelu.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_fused_bias_leakyrelu.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_gather_points.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_gather_points.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_gather_points.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_gather_points.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_group_points.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_group_points.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_group_points.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_group_points.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_info.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_info.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_info.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_info.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_iou3d.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_iou3d.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_iou3d.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_iou3d.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_knn.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_knn.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_knn.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_knn.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_masked_conv2d.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_masked_conv2d.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_masked_conv2d.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_masked_conv2d.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_merge_cells.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_merge_cells.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_merge_cells.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_merge_cells.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_min_area_polygons.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_min_area_polygons.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_min_area_polygons.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_min_area_polygons.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_modulated_deform_conv.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_modulated_deform_conv.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_modulated_deform_conv.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_modulated_deform_conv.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_ms_deformable_attn.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_ms_deformable_attn.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_ms_deformable_attn.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_ms_deformable_attn.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_nms.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_nms.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_nms.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_nms.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_nms_quadri.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_nms_quadri.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_nms_quadri.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_nms_quadri.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_nms_rotated.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_nms_rotated.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_nms_rotated.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_nms_rotated.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_onnx.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_onnx.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_onnx.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_onnx.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_pixel_group.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_pixel_group.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_pixel_group.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_pixel_group.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_points_in_polygons.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_points_in_polygons.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_points_in_polygons.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_points_in_polygons.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_prroi_pool.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_prroi_pool.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_prroi_pool.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_prroi_pool.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_psa_mask.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_psa_mask.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_psa_mask.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_psa_mask.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_riroi_align_rotated.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_riroi_align_rotated.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_riroi_align_rotated.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_riroi_align_rotated.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_roi_align.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_roi_align.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align_rotated.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_roi_align_rotated.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_roi_align_rotated.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_roi_align_rotated.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roi_pool.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_roi_pool.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_roi_pool.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_roi_pool.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roiaware_pool3d.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_roiaware_pool3d.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_roiaware_pool3d.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_roiaware_pool3d.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_roipoint_pool3d.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_roipoint_pool3d.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_roipoint_pool3d.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_roipoint_pool3d.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_rotated_feature_align.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_rotated_feature_align.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_rotated_feature_align.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_rotated_feature_align.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_saconv.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_saconv.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_saconv.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_saconv.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_scatter_points.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_scatter_points.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_scatter_points.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_scatter_points.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_spconv.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_spconv.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_spconv.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_spconv.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_syncbn.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_syncbn.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_syncbn.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_syncbn.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_three_interpolate.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_three_interpolate.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_three_interpolate.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_three_interpolate.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_three_nn.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_three_nn.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_three_nn.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_three_nn.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_tin_shift.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_tin_shift.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_tin_shift.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_tin_shift.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_upfirdn2d.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_upfirdn2d.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_upfirdn2d.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_upfirdn2d.py diff --git a/cv/distiller/CWD/mmcv/tests/test_ops/test_voxelization.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_voxelization.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_ops/test_voxelization.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_ops/test_voxelization.py diff --git a/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_formatting.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_transforms/test_transforms_formatting.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_formatting.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_transforms/test_transforms_formatting.py diff --git a/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_loading.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_transforms/test_transforms_loading.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_loading.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_transforms/test_transforms_loading.py diff --git a/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_processing.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_transforms/test_transforms_processing.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_processing.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_transforms/test_transforms_processing.py diff --git a/cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_wrapper.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_transforms/test_transforms_wrapper.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_transforms/test_transforms_wrapper.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_transforms/test_transforms_wrapper.py diff --git a/cv/distiller/CWD/mmcv/tests/test_utils/test_env.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_utils/test_env.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_utils/test_env.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_utils/test_env.py diff --git a/cv/distiller/CWD/mmcv/tests/test_utils/test_parrots_jit.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_utils/test_parrots_jit.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_utils/test_parrots_jit.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_utils/test_parrots_jit.py diff --git a/cv/distiller/CWD/mmcv/tests/test_video/test_optflow.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_video/test_optflow.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_video/test_optflow.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_video/test_optflow.py diff --git a/cv/distiller/CWD/mmcv/tests/test_video/test_processing.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_video/test_processing.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_video/test_processing.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_video/test_processing.py diff --git a/cv/distiller/CWD/mmcv/tests/test_video/test_reader.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_video/test_reader.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_video/test_reader.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_video/test_reader.py diff --git a/cv/distiller/CWD/mmcv/tests/test_visualization.py b/cv/distiller/CWD/pytorch/mmcv/tests/test_visualization.py similarity index 100% rename from cv/distiller/CWD/mmcv/tests/test_visualization.py rename to cv/distiller/CWD/pytorch/mmcv/tests/test_visualization.py diff --git a/cv/distiller/CWD/mmrazor/.circleci/config.yml b/cv/distiller/CWD/pytorch/mmrazor/.circleci/config.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/.circleci/config.yml rename to cv/distiller/CWD/pytorch/mmrazor/.circleci/config.yml diff --git a/cv/distiller/CWD/mmrazor/.circleci/docker/Dockerfile b/cv/distiller/CWD/pytorch/mmrazor/.circleci/docker/Dockerfile old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/.circleci/docker/Dockerfile rename to cv/distiller/CWD/pytorch/mmrazor/.circleci/docker/Dockerfile diff --git a/cv/distiller/CWD/mmrazor/.circleci/test.yml b/cv/distiller/CWD/pytorch/mmrazor/.circleci/test.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/.circleci/test.yml rename to cv/distiller/CWD/pytorch/mmrazor/.circleci/test.yml diff --git a/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_summary_analyse.py b/cv/distiller/CWD/pytorch/mmrazor/.dev_scripts/benchmark_summary_analyse.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_summary_analyse.py rename to cv/distiller/CWD/pytorch/mmrazor/.dev_scripts/benchmark_summary_analyse.py diff --git a/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_test.py b/cv/distiller/CWD/pytorch/mmrazor/.dev_scripts/benchmark_test.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_test.py rename to cv/distiller/CWD/pytorch/mmrazor/.dev_scripts/benchmark_test.py diff --git a/cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_train.py b/cv/distiller/CWD/pytorch/mmrazor/.dev_scripts/benchmark_train.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/.dev_scripts/benchmark_train.py rename to cv/distiller/CWD/pytorch/mmrazor/.dev_scripts/benchmark_train.py diff --git a/cv/distiller/CWD/mmrazor/.dev_scripts/meta_files_test.py b/cv/distiller/CWD/pytorch/mmrazor/.dev_scripts/meta_files_test.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/.dev_scripts/meta_files_test.py rename to cv/distiller/CWD/pytorch/mmrazor/.dev_scripts/meta_files_test.py diff --git a/cv/distiller/CWD/mmrazor/.pre-commit-config.yaml b/cv/distiller/CWD/pytorch/mmrazor/.pre-commit-config.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/.pre-commit-config.yaml rename to cv/distiller/CWD/pytorch/mmrazor/.pre-commit-config.yaml diff --git a/cv/distiller/CWD/mmrazor/.readthedocs.yml b/cv/distiller/CWD/pytorch/mmrazor/.readthedocs.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/.readthedocs.yml rename to cv/distiller/CWD/pytorch/mmrazor/.readthedocs.yml diff --git a/cv/distiller/CWD/mmrazor/LICENSE b/cv/distiller/CWD/pytorch/mmrazor/LICENSE old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/LICENSE rename to cv/distiller/CWD/pytorch/mmrazor/LICENSE diff --git a/cv/distiller/CWD/mmrazor/MANIFEST.in b/cv/distiller/CWD/pytorch/mmrazor/MANIFEST.in old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/MANIFEST.in rename to cv/distiller/CWD/pytorch/mmrazor/MANIFEST.in diff --git a/cv/distiller/CWD/mmrazor/README.md b/cv/distiller/CWD/pytorch/mmrazor/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/README.md rename to cv/distiller/CWD/pytorch/mmrazor/README.md diff --git a/cv/distiller/CWD/mmrazor/README_zh-CN.md b/cv/distiller/CWD/pytorch/mmrazor/README_zh-CN.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/README_zh-CN.md rename to cv/distiller/CWD/pytorch/mmrazor/README_zh-CN.md diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/cifar100_bs16_auto_aug.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/datasets/mmcls/cifar100_bs16_auto_aug.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/cifar100_bs16_auto_aug.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/datasets/mmcls/cifar100_bs16_auto_aug.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/pipelines/auto_aug_cifar.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/datasets/mmcls/pipelines/auto_aug_cifar.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/datasets/mmcls/pipelines/auto_aug_cifar.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/datasets/mmcls/pipelines/auto_aug_cifar.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/attentive_mobilenetv3_supernet.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/attentive_mobilenetv3_supernet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/attentive_mobilenetv3_supernet.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/attentive_mobilenetv3_supernet.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/darts_supernet.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/darts_supernet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/darts_supernet.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/darts_supernet.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/dsnas_shufflenet_supernet.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/dsnas_shufflenet_supernet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/dsnas_shufflenet_supernet.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/dsnas_shufflenet_supernet.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/ofa_mobilenetv3_supernet.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/ofa_mobilenetv3_supernet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/ofa_mobilenetv3_supernet.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/ofa_mobilenetv3_supernet.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_mobilenet_supernet.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/spos_mobilenet_supernet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_mobilenet_supernet.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/spos_mobilenet_supernet.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_shufflenet_supernet.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/spos_shufflenet_supernet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/nas_backbones/spos_shufflenet_supernet.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/nas_backbones/spos_shufflenet_supernet.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_subnet.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/cifar10_darts_subnet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_subnet.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/cifar10_darts_subnet.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_supernet.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/cifar10_darts_supernet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/settings/cifar10_darts_supernet.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/cifar10_darts_supernet.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_dsnas.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs1024_dsnas.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_dsnas.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs1024_dsnas.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_spos.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs1024_spos.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs1024_spos.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs1024_spos.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_AdamW.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_AdamW.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_AdamW.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_AdamW.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim_pil.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim_pil.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim_pil.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_autoslim_pil.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_bignas.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_bignas.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_bignas.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_bignas.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_dmcp.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_dmcp.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_dmcp.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_dmcp.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_ofa.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_ofa.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/settings/imagenet_bs2048_ofa.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/settings/imagenet_bs2048_ofa.py diff --git a/cv/distiller/CWD/mmrazor/configs/_base_/vanilla_models/wrn16_2_cifar10.py b/cv/distiller/CWD/pytorch/mmrazor/configs/_base_/vanilla_models/wrn16_2_cifar10.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/_base_/vanilla_models/wrn16_2_cifar10.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/_base_/vanilla_models/wrn16_2_cifar10.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/abloss/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/abloss/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/abloss/abloss_logits_resnet50_resnet18_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/abloss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/abloss/abloss_pretrain_backbone_resnet50_resnet18_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/abloss/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/abloss/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/abloss/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/byot/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/byot/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/byot_resnet18_8xb16_cifar100.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/byot/byot_resnet18_8xb16_cifar100.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/byot_resnet18_8xb16_cifar100.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/byot/byot_resnet18_8xb16_cifar100.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/byot/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/byot/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/byot/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/crd/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/crd/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/crd_neck_r50_r18_8xb16_cifar10.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/crd/crd_neck_r50_r18_8xb16_cifar10.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/crd_neck_r50_r18_8xb16_cifar10.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/crd/crd_neck_r50_r18_8xb16_cifar10.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/datasets/crd_cifar10_bs16.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/crd/datasets/crd_cifar10_bs16.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/crd/datasets/crd_cifar10_bs16.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/crd/datasets/crd_cifar10_bs16.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dafl/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dafl/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/dafl_logits_resnet34_resnet18_8xb256_cifar10.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dafl/dafl_logits_resnet34_resnet18_8xb256_cifar10.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/dafl_logits_resnet34_resnet18_8xb256_cifar10.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dafl/dafl_logits_resnet34_resnet18_8xb256_cifar10.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dafl/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/dafl/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dafl/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/deit/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/deit/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/deit-base_regnety160_pt-16xb64_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/deit/deit-base_regnety160_pt-16xb64_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/deit-base_regnety160_pt-16xb64_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/deit/deit-base_regnety160_pt-16xb64_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/deit/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/deit/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/deit/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dfad/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dfad/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/dfad_logits_resnet34_resnet18_8xb32_cifar10.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dfad/dfad_logits_resnet34_resnet18_8xb32_cifar10.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/dfad_logits_resnet34_resnet18_8xb32_cifar10.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dfad/dfad_logits_resnet34_resnet18_8xb32_cifar10.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dfad/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/dfad/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dfad/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dkd/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dkd/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/dkd_resnet34_resnet18_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dkd/dkd_resnet34_resnet18_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/dkd_resnet34_resnet18_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dkd/dkd_resnet34_resnet18_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dkd/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/dkd/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/dkd/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/factor_transfer/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/factor_transfer/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_pretrain.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/factor_transfer/factor-transfer_backbone_resnet50_resnet18_8xb16_cifar10_train.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/factor_transfer/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/factor_transfer/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/factor_transfer/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/fitnets/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/fitnets/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/fitnets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/fitnets/fitnets_backbone_logits_resnet50_resnet18_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/fitnets/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/fitnets/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/fitnets/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/kd/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/kd/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet34_resnet18_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet34_resnet18_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet34_resnet18_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet34_resnet18_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_mobilenet-v2_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/kd/kd_logits_resnet50_shufflenet-v2-1x_16xb64_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/kd/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/kd/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/kd/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/ofd/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/ofd/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/ofd/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/ofd/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/ofd/ofd_backbone_resnet50_resnet18_8xb16_cifar10.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/rkd/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/rkd/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/rkd/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/rkd/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/rkd/rkd_neck_resnet34_resnet18_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/wsld/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/wsld/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/wsld/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/wsld/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/wsld_logits_resnet34_resnet18_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/wsld/wsld_logits_resnet34_resnet18_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/wsld/wsld_logits_resnet34_resnet18_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/wsld/wsld_logits_resnet34_resnet18_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/zskt/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/zskt/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/zskt/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/zskt/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/zskt/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmcls/zskt/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmcls/zskt/zskt_backbone_logits_resnet34_resnet18_8xb16_cifar10.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/cwd_cls_head_gfl_r101_fpn_gfl_r50_fpn_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_frcnn_r101_frcnn_r50_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco_visualization.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco_visualization.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco_visualization.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/cwd_fpn_retina_r101_retina_r50_1x_coco_visualization.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/cwd/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/cwd/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/fbkd/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/fbkd/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/fbkd_fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/fbkd/fbkd_fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/fbkd_fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/fbkd/fbkd_fpn_faster-rcnn_r101_faster-rcnn_r50_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/fbkd/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/fbkd/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/fbkd/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/mgd/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/mgd/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/mgd_fpn_retina_x101_retina_r50_2x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/mgd/mgd_fpn_retina_x101_retina_r50_2x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/mgd/mgd_fpn_retina_x101_retina_r50_2x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/mgd/mgd_fpn_retina_x101_retina_r50_2x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_faster-rcnn_r101_faster-rcnn_r50_2x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_fcos_x101_retina_r50_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_fcos_x101_retina_r50_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_fcos_x101_retina_r50_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_fcos_x101_retina_r50_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_mask-rcnn_swin_retina_r50_2x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_reppoints_x101-dcn_reppoints_r50_2x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_retina_x101_retina_r50_2x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_retina_x101_retina_r50_2x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_retina_x101_retina_r50_2x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet/pkd/pkd_fpn_retina_x101_retina_r50_2x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet3d/pkd/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet3d/pkd/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet3d/pkd/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet3d/pkd/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet3d/pkd/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmdet3d/pkd/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmdet3d/pkd/pkd_fpn_fcos3d_r101_fcos3d_r50_8xb2-1x_nus-mono3d.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmseg/cwd/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmseg/cwd/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmseg/cwd/cwd_logits_pspnet_r101-d8_pspnet_r18-d8_4xb2-80k_cityscapes-512x1024.py diff --git a/cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmseg/cwd/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/distill/mmseg/cwd/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/distill/mmseg/cwd/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoformer/AUTOFORMER_SUBNET_B.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoformer/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoformer/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_search_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoformer/autoformer_search_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_search_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoformer/autoformer_search_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_subnet_8xb256_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoformer/autoformer_subnet_8xb256_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_subnet_8xb256_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoformer/autoformer_subnet_8xb256_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_supernet_32xb256_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoformer/autoformer_supernet_32xb256_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoformer/autoformer_supernet_32xb256_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoformer/autoformer_supernet_32xb256_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_search_8xb256_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_search_8xb256_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_search_8xb256_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_search_8xb256_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_slimmable_subnet_8xb256_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-220M.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-320M.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_subnet_8xb256_in1k_flops-530M.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_supernet_8xb256_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_supernet_8xb256_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_supernet_8xb256_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/autoslim_mbv2_1.5x_supernet_8xb256_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/autoslim/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/autoslim/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A0.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A1.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A1.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A1.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A1.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A2.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A2.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A2.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A2.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A3.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A3.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A3.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A3.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A4.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A4.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A4.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A4.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A5.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A5.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A5.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A5.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A6.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A6.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A6.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/ATTENTIVE_SUBNET_A6.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_search_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_search_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_search_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_search_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_subnet_8xb256_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_supernet_32xb64_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_supernet_32xb64_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_supernet_32xb64_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/bignas/attentive_mobilenet_supernet_32xb64_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_MMRAZOR_97.32.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/DARTS_SUBNET_CIFAR_PAPER_ALIAS.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0_mmrazor.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0_mmrazor.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0_mmrazor.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/darts_subnet_1xb96_cifar10_2.0_mmrazor.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_supernet_unroll_1xb96_cifar10.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/darts_supernet_unroll_1xb96_cifar10.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/darts_supernet_unroll_1xb96_cifar10.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/darts_supernet_unroll_1xb96_cifar10.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/darts/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/darts/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/dsnas/DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/dsnas/DSNAS_SUBNET_IMAGENET_PAPER_ALIAS.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/dsnas/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/dsnas/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_subnet_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/dsnas/dsnas_subnet_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_subnet_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/dsnas/dsnas_subnet_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_supernet_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/dsnas/dsnas_supernet_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/dsnas/dsnas_supernet_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/dsnas/dsnas_supernet_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT22.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT22.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT22.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT22.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT31.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT31.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT31.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/OFA_SUBNET_NOTE8_LAT31.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_search_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_search_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_search_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_search_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_subnet_8xb256_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_subnet_8xb256_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_subnet_8xb256_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_subnet_8xb256_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_supernet_32xb64_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_supernet_32xb64_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_supernet_32xb64_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/onceforall/ofa_mobilenet_supernet_32xb64_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/SPOS_SUBNET.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/SPOS_SUBNET.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/SPOS_SUBNET.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/SPOS_SUBNET.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/faster-rcnn_nas_backbone_fpn_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/faster-rcnn_nas_backbone_fpn_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/faster-rcnn_nas_backbone_fpn_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/faster-rcnn_nas_backbone_fpn_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_search_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_search_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_search_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_search_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_subnet_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_subnet_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_subnet_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_subnet_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_supernet_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_supernet_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_supernet_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_mobilenet_supernet_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_predictor_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_predictor_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_predictor_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_search_predictor_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_subnet_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_subnet_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_subnet_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_subnet_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_supernet_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_supernet_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_supernet_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmcls/spos/spos_shufflenet_supernet_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/DETNAS_SUBNET.yaml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/DETNAS_SUBNET.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/DETNAS_SUBNET.yaml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/DETNAS_SUBNET.yaml diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_search_coco_1x.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_search_coco_1x.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_search_coco_1x.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_search_coco_1x.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_subnet_coco_1x.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_subnet_coco_1x.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_subnet_coco_1x.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_subnet_coco_1x.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_supernet_coco_1x.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_supernet_coco_1x.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_supernet_coco_1x.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_frcnn_shufflenet_supernet_coco_1x.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_retina_shufflenet_supernet_coco_1x.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_retina_shufflenet_supernet_coco_1x.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_retina_shufflenet_supernet_coco_1x.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_retina_shufflenet_supernet_coco_1x.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_subnet_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_subnet_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_subnet_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_subnet_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_supernet_8xb128_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_supernet_8xb128_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_supernet_8xb128_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/detnas_shufflenet_supernet_8xb128_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/nas/mmdet/detnas/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/nas/mmdet/detnas/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/base/group_fisher/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/base/group_fisher/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_deploy_template.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/base/group_fisher/group_fisher_deploy_template.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_deploy_template.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/base/group_fisher/group_fisher_deploy_template.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_finetune_template.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/base/group_fisher/group_fisher_finetune_template.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_finetune_template.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/base/group_fisher/group_fisher_finetune_template.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_prune_template.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/base/group_fisher/group_fisher_prune_template.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/base/group_fisher/group_fisher_prune_template.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/base/group_fisher/group_fisher_prune_template.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dcff/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dcff/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_compact_resnet_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dcff/dcff_compact_resnet_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_compact_resnet_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dcff/dcff_compact_resnet_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_resnet_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dcff/dcff_resnet_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/dcff_resnet_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dcff/dcff_resnet_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/fix_subnet.json b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dcff/fix_subnet.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dcff/fix_subnet.json rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dcff/fix_subnet.json diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_MBV2_100M.json b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/DMCP_MBV2_100M.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_MBV2_100M.json rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/DMCP_MBV2_100M.json diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_R50_2G.json b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/DMCP_R50_2G.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/DMCP_R50_2G.json rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/DMCP_R50_2G.json diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_subnet_32xb64.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_supernet_32xb64.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_supernet_32xb64.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_supernet_32xb64.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/dmcp_mbv2_supernet_32xb64.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_subnet_32xb64.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_supernet_32xb64.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_supernet_32xb64.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_supernet_32xb64.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/dmcp_resnet50_supernet_32xb64.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/dmcp/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/dmcp/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_deploy_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_deploy_mobilenet-v2_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_deploy_mobilenet-v2_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_deploy_mobilenet-v2_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_finetune_mobilenet-v2_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_act_prune_mobilenet-v2_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_deploy_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_deploy_mobilenet-v2_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_deploy_mobilenet-v2_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_deploy_mobilenet-v2_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_finetune_mobilenet-v2_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/group_fisher_flops_prune_mobilenet-v2_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/script.sh b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/script.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/script.sh rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/mobilenet/script.sh diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_deploy_resnet50_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_deploy_resnet50_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_deploy_resnet50_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_deploy_resnet50_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_finetune_resnet50_8xb32_in1k_dist.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_prune_resnet50_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_prune_resnet50_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_prune_resnet50_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_act_prune_resnet50_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_deploy_resnet50_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_deploy_resnet50_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_deploy_resnet50_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_deploy_resnet50_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_finetune_resnet50_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_prune_resnet50_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_prune_resnet50_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_prune_resnet50_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/group_fisher_flops_prune_resnet50_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/script.sh b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/script.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/script.sh rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/group_fisher/resnet50/script.sh diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a_deploy.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a_deploy.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a_deploy.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_a_deploy.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b_deploy.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b_deploy.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b_deploy.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_b_deploy.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c_deploy.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c_deploy.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c_deploy.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/l1-norm_resnet34_8xb32_in1k_c_deploy.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/script.sh b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/script.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmcls/l1-norm/script.sh rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmcls/l1-norm/script.sh diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/dcff/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/dcff/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_compact_faster_rcnn_resnet50_8xb4_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/dcff/dcff_compact_faster_rcnn_resnet50_8xb4_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_compact_faster_rcnn_resnet50_8xb4_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/dcff/dcff_compact_faster_rcnn_resnet50_8xb4_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_8xb4_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_fpn.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_fpn.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_fpn.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/dcff/dcff_faster_rcnn_resnet50_fpn.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/fix_subnet.json b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/dcff/fix_subnet.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/dcff/fix_subnet.json rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/dcff/fix_subnet.json diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_deploy_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_deploy_retinanet_r50_fpn_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_deploy_retinanet_r50_fpn_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_deploy_retinanet_r50_fpn_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_finetune_retinanet_r50_fpn_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_act_prune_retinanet_r50_fpn_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_deploy_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_deploy_retinanet_r50_fpn_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_deploy_retinanet_r50_fpn_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_deploy_retinanet_r50_fpn_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_finetune_retinanet_r50_fpn_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/group_fisher_flops_prune_retinanet_r50_fpn_1x_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/script.sh b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/script.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/script.sh rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmdet/group_fisher/retinanet/script.sh diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/dcff/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/dcff/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_compact_topdown_heatmap_resnet50_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/dcff/dcff_compact_topdown_heatmap_resnet50_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_compact_topdown_heatmap_resnet50_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/dcff/dcff_compact_topdown_heatmap_resnet50_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/dcff/dcff_topdown_heatmap_resnet50_coco.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/fix_subnet.json b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/dcff/fix_subnet.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmpose/dcff/fix_subnet.json rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/dcff/fix_subnet.json diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_aic-coco-256x192.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_aic-coco-256x192.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_aic-coco-256x192.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_aic-coco-256x192.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_coco-256x192.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_coco-256x192.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_coco-256x192.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_deploy_rtmpose-s_8xb256-420e_coco-256x192.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_finetune_rtmpose-s_8xb256-420e_coco-256x192.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_aic-coco-256x192.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/group_fisher_prune_rtmpose-s_8xb256-420e_coco-256x192.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/script.sh b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/script.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmpose/group_fisher/script.sh rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmpose/group_fisher/script.sh diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmseg/dcff/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmseg/dcff/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_compact_pointrend_resnet50_8xb2_cityscapes.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmseg/dcff/dcff_compact_pointrend_resnet50_8xb2_cityscapes.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_compact_pointrend_resnet50_8xb2_cityscapes.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmseg/dcff/dcff_compact_pointrend_resnet50_8xb2_cityscapes.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmseg/dcff/dcff_pointrend_resnet50_8xb2_cityscapes.py diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/fix_subnet.json b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmseg/dcff/fix_subnet.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/fix_subnet.json rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmseg/dcff/fix_subnet.json diff --git a/cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/pointrend_resnet50.py b/cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmseg/dcff/pointrend_resnet50.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/pruning/mmseg/dcff/pointrend_resnet50.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/pruning/mmseg/dcff/pointrend_resnet50.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_openvino_dynamic-224x224.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/deploy_cfgs/mmcls/classification_tensorrt-int8-explicit_dynamic-224x224.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_openvino_dynamic-800x1344.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_openvino_dynamic-800x1344.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_openvino_dynamic-800x1344.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_openvino_dynamic-800x1344.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_tensorrt-int8-explicit_dynamic-320x320-1344x1344.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_tensorrt-int8-explicit_dynamic-320x320-1344x1344.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_tensorrt-int8-explicit_dynamic-320x320-1344x1344.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/deploy_cfgs/mmdet/detection_tensorrt-int8-explicit_dynamic-320x320-1344x1344.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_openvino_mbv2_8xb32_in1k_calib32xb32.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet18_8xb32_in1k_calib32xb32.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_openvino_resnet50_8xb32_in1k_calib32xb32.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_retina_r50_1x_coco_calib32xb32.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_openvino_retina_r50_1x_coco_calib32xb32.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_retina_r50_1x_coco_calib32xb32.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_openvino_retina_r50_1x_coco_calib32xb32.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_openvino_yolox_s_8xb8-300e_coco_calib32xb32.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_mbv2_8xb32_in1k_calib32xb32.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet18_8xb32_in1k_calib32xb32.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_resnet50_8xb32_in1k_calib32xb32.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_retina_r50_1x_coco_calib32xb32.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/ptq/base/ptq_tensorrt_yolox_s_8xb8-300e_coco_calib32xb32.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/base/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/qat/base/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/base/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/base/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/qat/base/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/base/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/base/qat_openvino_resnet18_10e_8xb32_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/base/qat_openvino_resnet18_10e_8xb32_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/qat/base/qat_openvino_resnet18_10e_8xb32_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/base/qat_openvino_resnet18_10e_8xb32_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/lsq/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/lsq/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_100e_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_100e_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_100e_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_100e_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_10e_in1k.py b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_10e_in1k.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_10e_in1k.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/lsq/lsq_openvino_resnet18_8xb32_10e_in1k.py diff --git a/cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/metafile.yml b/cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/lsq/metafile.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/quantization/qat/lsq/metafile.yml rename to cv/distiller/CWD/pytorch/mmrazor/configs/quantization/qat/lsq/metafile.yml diff --git a/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/README.md b/cv/distiller/CWD/pytorch/mmrazor/configs/vanilla/mmcls/wide-resnet/README.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/README.md rename to cv/distiller/CWD/pytorch/mmrazor/configs/vanilla/mmcls/wide-resnet/README.md diff --git a/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py b/cv/distiller/CWD/pytorch/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn16-w2_b16x8_cifar10.py diff --git a/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn22-w4_b16x8_cifar10.py b/cv/distiller/CWD/pytorch/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn22-w4_b16x8_cifar10.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn22-w4_b16x8_cifar10.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn22-w4_b16x8_cifar10.py diff --git a/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py b/cv/distiller/CWD/pytorch/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn28-w4_b16x8_cifar10.py diff --git a/cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn40-w2_b16x8_cifar10.py b/cv/distiller/CWD/pytorch/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn40-w2_b16x8_cifar10.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn40-w2_b16x8_cifar10.py rename to cv/distiller/CWD/pytorch/mmrazor/configs/vanilla/mmcls/wide-resnet/wrn40-w2_b16x8_cifar10.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/datasets/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/crd_dataset_wrapper.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/crd_dataset_wrapper.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/datasets/crd_dataset_wrapper.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/crd_dataset_wrapper.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/transforms/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/transforms/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augment.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/transforms/auto_augment.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augment.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/transforms/auto_augment.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augmentv2.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/transforms/auto_augmentv2.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/auto_augmentv2.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/transforms/auto_augmentv2.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/formatting.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/transforms/formatting.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/datasets/transforms/formatting.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/datasets/transforms/formatting.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dmcp_subnet_hook.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/dmcp_subnet_hook.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dmcp_subnet_hook.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/dmcp_subnet_hook.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dump_subnet_hook.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/dump_subnet_hook.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/dump_subnet_hook.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/dump_subnet_hook.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/estimate_resources_hook.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/estimate_resources_hook.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/estimate_resources_hook.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/estimate_resources_hook.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/group_fisher_hooks.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/group_fisher_hooks.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/group_fisher_hooks.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/group_fisher_hooks.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/stop_distillation_hook.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/stop_distillation_hook.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/stop_distillation_hook.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/stop_distillation_hook.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/visualization_hook.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/visualization_hook.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/hooks/visualization_hook.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/hooks/visualization_hook.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/optimizers/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/optimizers/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/optimizer_constructor.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/optimizers/optimizer_constructor.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/optimizers/optimizer_constructor.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/optimizers/optimizer_constructor.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/autoslim_greedy_search_loop.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/autoslim_greedy_search_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/autoslim_greedy_search_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/autoslim_greedy_search_loop.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/darts_loop.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/darts_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/darts_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/darts_loop.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/distill_val_loop.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/distill_val_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/distill_val_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/distill_val_loop.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/evolution_search_loop.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/evolution_search_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/evolution_search_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/evolution_search_loop.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/iteprune_val_loop.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/iteprune_val_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/iteprune_val_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/iteprune_val_loop.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/quantization_loops.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/quantization_loops.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/quantization_loops.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/quantization_loops.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/slimmable_val_loop.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/slimmable_val_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/slimmable_val_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/slimmable_val_loop.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_sampler_loop.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/subnet_sampler_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_sampler_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/subnet_sampler_loop.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_val_loop.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/subnet_val_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/subnet_val_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/subnet_val_loop.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/utils/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/utils/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/calibrate_bn_mixin.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/utils/calibrate_bn_mixin.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/calibrate_bn_mixin.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/utils/calibrate_bn_mixin.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/check.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/utils/check.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/check.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/utils/check.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/genetic.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/utils/genetic.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/engine/runner/utils/genetic.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/engine/runner/utils/genetic.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/implementations/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/algorithm.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/algorithm.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/algorithm.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/algorithm.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/counters.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/counters.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/counters.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/counters.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/hook.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/hook.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/hook.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/hook.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/mutator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/mutator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/ops.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/ops.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/ops.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/ops.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_deploy_sub_model.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_deploy_sub_model.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_deploy_sub_model.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_deploy_sub_model.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_sub_model.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_sub_model.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_sub_model.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/prune_sub_model.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/unit.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/implementations/pruning/group_fisher/unit.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/implementations/pruning/group_fisher/unit.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/base.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/base.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/base.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/base.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/datafree_distillation.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/datafree_distillation.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/datafree_distillation.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/datafree_distillation.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/fpn_teacher_distill.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/fpn_teacher_distill.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/fpn_teacher_distill.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/fpn_teacher_distill.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/overhaul_feature_distillation.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/overhaul_feature_distillation.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/overhaul_feature_distillation.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/overhaul_feature_distillation.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/self_distill.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/self_distill.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/self_distill.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/self_distill.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/single_teacher_distill.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/single_teacher_distill.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/distill/configurable/single_teacher_distill.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/distill/configurable/single_teacher_distill.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoformer.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/autoformer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoformer.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/autoformer.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoslim.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/autoslim.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/autoslim.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/autoslim.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/bignas.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/bignas.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/bignas.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/bignas.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/darts.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/darts.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/darts.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/darts.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/dsnas.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/dsnas.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/dsnas.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/dsnas.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/spos.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/spos.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/nas/spos.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/nas/spos.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dcff.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/dcff.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dcff.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/dcff.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dmcp.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/dmcp.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/dmcp.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/dmcp.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/group_fisher_algoritho.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/group_fisher_algoritho.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/group_fisher_algoritho.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/group_fisher_algoritho.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/ite_prune_algorithm.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/ite_prune_algorithm.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/ite_prune_algorithm.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/ite_prune_algorithm.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/slimmable_network.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/slimmable_network.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/pruning/slimmable_network.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/pruning/slimmable_network.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/quantization/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/quantization/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/mm_architecture.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/quantization/mm_architecture.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/algorithms/quantization/mm_architecture.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/algorithms/quantization/mm_architecture.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/darts_backbone.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/darts_backbone.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/darts_backbone.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/darts_backbone.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_autoformer.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/searchable_autoformer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_autoformer.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/searchable_autoformer.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v2.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v2.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v2.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v2.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v3.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v3.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v3.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/searchable_mobilenet_v3.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_shufflenet_v2.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/searchable_shufflenet_v2.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/searchable_shufflenet_v2.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/searchable_shufflenet_v2.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/wideresnet.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/wideresnet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/backbones/wideresnet.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/backbones/wideresnet.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/classifiers/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/classifiers/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/image.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/classifiers/image.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/classifiers/image.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/classifiers/image.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/base_connector.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/base_connector.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/base_connector.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/base_connector.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/byot_connector.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/byot_connector.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/byot_connector.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/byot_connector.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/convmodule_connector.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/convmodule_connector.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/convmodule_connector.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/convmodule_connector.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/crd_connector.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/crd_connector.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/crd_connector.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/crd_connector.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/factor_transfer_connectors.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/factor_transfer_connectors.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/factor_transfer_connectors.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/factor_transfer_connectors.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/fbkd_connector.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/fbkd_connector.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/fbkd_connector.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/fbkd_connector.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/mgd_connector.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/mgd_connector.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/mgd_connector.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/mgd_connector.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/norm_connector.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/norm_connector.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/norm_connector.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/norm_connector.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/ofd_connector.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/ofd_connector.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/ofd_connector.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/ofd_connector.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/torch_connector.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/torch_connector.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/connectors/torch_connector.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/connectors/torch_connector.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_container.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_container.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_container.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_container.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_conv.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_conv.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_conv.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_conv.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_embed.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_embed.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_embed.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_embed.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_function.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_function.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_function.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_function.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_linear.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_linear.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_linear.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_linear.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_multi_head_attention.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_multi_head_attention.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_multi_head_attention.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_multi_head_attention.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_norm.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_norm.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_norm.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_norm.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_relative_position.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_relative_position.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_relative_position.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/dynamic_relative_position.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/group_fisher_ops.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/group_fisher_ops.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/group_fisher_ops.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/bricks/group_fisher_ops.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/head/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/head/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/dynamic_linear_head.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/head/dynamic_linear_head.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/head/dynamic_linear_head.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/head/dynamic_linear_head.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_conv_mixins.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_conv_mixins.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_conv_mixins.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_conv_mixins.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_layernorm_mixins.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_layernorm_mixins.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_layernorm_mixins.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_layernorm_mixins.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_mixins.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_mixins.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_mixins.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/dynamic_ops/mixins/dynamic_mixins.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/generators/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/generators/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/base_generator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/generators/base_generator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/base_generator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/generators/base_generator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/dafl_generator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/generators/dafl_generator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/dafl_generator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/generators/dafl_generator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/zskt_generator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/generators/zskt_generator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/generators/zskt_generator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/generators/zskt_generator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/heads/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/heads/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/darts_subnet_head.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/heads/darts_subnet_head.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/darts_subnet_head.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/heads/darts_subnet_head.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/deit_head.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/heads/deit_head.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/heads/deit_head.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/heads/deit_head.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/necks/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/necks/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/squeezemean_with_dropout.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/necks/squeezemean_with_dropout.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/necks/squeezemean_with_dropout.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/necks/squeezemean_with_dropout.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/base.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/base.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/base.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/base.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/common.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/common.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/common.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/common.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/darts_series.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/darts_series.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/darts_series.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/darts_series.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/efficientnet_series.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/efficientnet_series.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/efficientnet_series.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/efficientnet_series.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/function.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/function.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/function.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/function.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/gather_tensors.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/gather_tensors.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/gather_tensors.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/gather_tensors.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/mobilenet_series.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/mobilenet_series.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/mobilenet_series.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/mobilenet_series.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/shufflenet_series.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/shufflenet_series.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/shufflenet_series.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/shufflenet_series.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/transformer_series.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/transformer_series.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/ops/transformer_series.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/ops/transformer_series.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/utils/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/utils/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/mutable_register.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/utils/mutable_register.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/mutable_register.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/utils/mutable_register.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/set_dropout.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/utils/set_dropout.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/architectures/utils/set_dropout.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/architectures/utils/set_dropout.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/distillers/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/distillers/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/distillers/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/base_distiller.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/distillers/base_distiller.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/distillers/base_distiller.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/distillers/base_distiller.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/byot_distiller.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/distillers/byot_distiller.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/distillers/byot_distiller.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/distillers/byot_distiller.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/configurable_distiller.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/distillers/configurable_distiller.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/distillers/configurable_distiller.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/distillers/configurable_distiller.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/distillers/ofd_distiller.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/distillers/ofd_distiller.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/distillers/ofd_distiller.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/distillers/ofd_distiller.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/fake_quants/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/fake_quants/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/base.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/fake_quants/base.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/base.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/fake_quants/base.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/lsq.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/fake_quants/lsq.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/lsq.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/fake_quants/lsq.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/torch_fake_quants.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/fake_quants/torch_fake_quants.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/fake_quants/torch_fake_quants.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/fake_quants/torch_fake_quants.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/ab_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/ab_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/ab_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/ab_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/at_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/at_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/at_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/at_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/crd_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/crd_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/crd_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/crd_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/cross_entropy_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/cross_entropy_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/cross_entropy_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/cross_entropy_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/cwd.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/cwd.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/cwd.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/cwd.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/dafl_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/dafl_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/dafl_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/dafl_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/decoupled_kd.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/decoupled_kd.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/decoupled_kd.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/decoupled_kd.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/dist_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/dist_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/dist_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/dist_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/factor_transfer_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/factor_transfer_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/factor_transfer_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/factor_transfer_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/fbkd_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/fbkd_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/fbkd_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/fbkd_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/kd_soft_ce_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/kd_soft_ce_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/kd_soft_ce_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/kd_soft_ce_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/kl_divergence.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/kl_divergence.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/kl_divergence.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/kl_divergence.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/l1_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/l1_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/l1_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/l1_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/l2_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/l2_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/l2_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/l2_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/mgd_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/mgd_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/mgd_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/mgd_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/ofd_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/ofd_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/ofd_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/ofd_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/pkd_loss.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/pkd_loss.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/pkd_loss.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/pkd_loss.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/relational_kd.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/relational_kd.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/relational_kd.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/relational_kd.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/losses/weighted_soft_label_distillation.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/weighted_soft_label_distillation.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/losses/weighted_soft_label_distillation.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/losses/weighted_soft_label_distillation.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/base_mutable.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/base_mutable.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/base_mutable.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/base_mutable.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/derived_mutable.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/derived_mutable.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/derived_mutable.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/derived_mutable.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/MutableChannel.md b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/MutableChannel.md old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/MutableChannel.md rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/MutableChannel.md diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/base_mutable_channel.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/base_mutable_channel.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/base_mutable_channel.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/base_mutable_channel.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/mutable_channel_container.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/mutable_channel_container.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/mutable_channel_container.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/mutable_channel_container.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/oneshot_mutable_channel.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/oneshot_mutable_channel.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/oneshot_mutable_channel.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/oneshot_mutable_channel.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/sequential_mutable_channel.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/sequential_mutable_channel.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/sequential_mutable_channel.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/sequential_mutable_channel.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/simple_mutable_channel.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/simple_mutable_channel.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/simple_mutable_channel.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/simple_mutable_channel.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dcff_channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/dcff_channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dcff_channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/dcff_channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dmcp_channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/dmcp_channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/dmcp_channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/dmcp_channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/group_fisher_unit.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/group_fisher_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/group_fisher_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/group_fisher_unit.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/l1_mutable_channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/l1_mutable_channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/l1_mutable_channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/l1_mutable_channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.ipynb b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.ipynb old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.ipynb rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.ipynb diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/one_shot_mutable_channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/one_shot_mutable_channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/one_shot_mutable_channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/one_shot_mutable_channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/sequential_mutable_channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/sequential_mutable_channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/sequential_mutable_channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/sequential_mutable_channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/slimmable_channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/slimmable_channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/slimmable_channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/slimmable_channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/utils.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/utils.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_channel/units/utils.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_channel/units/utils.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_module/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_module/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/diff_mutable_module.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_module/diff_mutable_module.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/diff_mutable_module.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_module/diff_mutable_module.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/mutable_module.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_module/mutable_module.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/mutable_module.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_module/mutable_module.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/one_shot_mutable_module.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_module/one_shot_mutable_module.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_module/one_shot_mutable_module.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_module/one_shot_mutable_module.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_value/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_value/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/mutable_value.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_value/mutable_value.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutables/mutable_value/mutable_value.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutables/mutable_value/mutable_value.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/base_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/base_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/base_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/base_mutator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.ipynb b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.ipynb old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.ipynb rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.ipynb diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/channel_mutator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dcff_channel_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/dcff_channel_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dcff_channel_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/dcff_channel_mutator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dmcp_channel_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/dmcp_channel_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/dmcp_channel_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/dmcp_channel_mutator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/group_fisher_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/group_fisher_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/group_fisher_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/group_fisher_mutator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/one_shot_channel_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/one_shot_channel_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/one_shot_channel_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/one_shot_channel_mutator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/slimmable_channel_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/slimmable_channel_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/channel_mutator/slimmable_channel_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/channel_mutator/slimmable_channel_mutator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/group_mixin.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/group_mixin.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/group_mixin.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/group_mixin.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/mutators/nas_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/nas_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/mutators/nas_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/mutators/nas_mutator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/observers/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/observers/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/observers/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/observers/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/observers/base.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/observers/base.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/observers/base.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/observers/base.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/observers/lsq.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/observers/lsq.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/observers/lsq.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/observers/lsq.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/observers/torch_observers.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/observers/torch_observers.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/observers/torch_observers.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/observers/torch_observers.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/academic_quantizer.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/academic_quantizer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/academic_quantizer.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/academic_quantizer.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/base.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/base.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/base.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/base.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/exporters/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/exporters/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/base_quantize_exporter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/exporters/base_quantize_exporter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/base_quantize_exporter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/exporters/base_quantize_exporter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/openvino_quantize_exporter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/exporters/openvino_quantize_exporter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/openvino_quantize_exporter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/exporters/openvino_quantize_exporter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/optim_utils.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/exporters/optim_utils.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/optim_utils.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/exporters/optim_utils.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/tensorrt_quantize_exporter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/exporters/tensorrt_quantize_exporter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/exporters/tensorrt_quantize_exporter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/exporters/tensorrt_quantize_exporter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/native_quantizer.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/native_quantizer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/native_quantizer.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/native_quantizer.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/openvino_quantizer.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/openvino_quantizer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/openvino_quantizer.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/openvino_quantizer.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/tensorrt_quantizer.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/tensorrt_quantizer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/quantizers/tensorrt_quantizer.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/quantizers/tensorrt_quantizer.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/delivery/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/delivery/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/delivery_manager.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/delivery/delivery_manager.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/delivery_manager.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/delivery/delivery_manager.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/distill_delivery.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/delivery/distill_delivery.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/distill_delivery.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/delivery/distill_delivery.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/function_outputs_delivery.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/delivery/function_outputs_delivery.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/function_outputs_delivery.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/delivery/function_outputs_delivery.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/method_outputs_delivery.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/delivery/method_outputs_delivery.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/delivery/method_outputs_delivery.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/delivery/method_outputs_delivery.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/demo_inputs/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/demo_inputs/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/default_demo_inputs.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/demo_inputs/default_demo_inputs.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/default_demo_inputs.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/demo_inputs/default_demo_inputs.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/demo_inputs.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/demo_inputs/demo_inputs.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/demo_inputs.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/demo_inputs/demo_inputs.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmpose_demo_input.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/demo_inputs/mmpose_demo_input.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmpose_demo_input.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/demo_inputs/mmpose_demo_input.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmseg_demo_input.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/demo_inputs/mmseg_demo_input.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/demo_inputs/mmseg_demo_input.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/demo_inputs/mmseg_demo_input.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/base_estimator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/base_estimator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/base_estimator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/base_estimator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/flops_params_counter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/flops_params_counter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/flops_params_counter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/flops_params_counter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/latency_counter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/latency_counter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/latency_counter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/latency_counter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/activation_layer_counter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/activation_layer_counter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/activation_layer_counter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/activation_layer_counter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/base_counter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/base_counter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/base_counter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/base_counter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/conv_layer_counter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/conv_layer_counter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/conv_layer_counter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/conv_layer_counter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/deconv_layer_counter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/deconv_layer_counter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/deconv_layer_counter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/deconv_layer_counter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/group_fisher_counters.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/group_fisher_counters.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/group_fisher_counters.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/group_fisher_counters.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/linear_layer_counter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/linear_layer_counter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/linear_layer_counter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/linear_layer_counter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/norm_layer_counter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/norm_layer_counter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/norm_layer_counter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/norm_layer_counter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/pooling_layer_counter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/pooling_layer_counter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/pooling_layer_counter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/pooling_layer_counter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/upsample_layer_counter.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/upsample_layer_counter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/upsample_layer_counter.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/counters/op_counters/upsample_layer_counter.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/resource_estimator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/resource_estimator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/estimators/resource_estimator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/estimators/resource_estimator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/base_handler.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/base_handler.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/base_handler.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/base_handler.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/carts_handler.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/carts_handler.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/carts_handler.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/carts_handler.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/gp_handler.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/gp_handler.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/gp_handler.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/gp_handler.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/mlp_handler.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/mlp_handler.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/mlp_handler.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/mlp_handler.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/rbf_handler.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/rbf_handler.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/handler/rbf_handler.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/handler/rbf_handler.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/metric_predictor.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/metric_predictor.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/predictor/metric_predictor.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/predictor/metric_predictor.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/base_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/base_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/base_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/base_recorder.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_inputs_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/function_inputs_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_inputs_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/function_inputs_recorder.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_outputs_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/function_outputs_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/function_outputs_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/function_outputs_recorder.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_inputs_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/method_inputs_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_inputs_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/method_inputs_recorder.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_outputs_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/method_outputs_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/method_outputs_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/method_outputs_recorder.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_inputs_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/module_inputs_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_inputs_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/module_inputs_recorder.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_outputs_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/module_outputs_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/module_outputs_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/module_outputs_recorder.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/param_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/param_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/param_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/param_recorder.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/recorder_manager.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/recorder_manager.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/recorder/recorder_manager.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/recorder/recorder_manager.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/backward_tracer.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/backward_tracer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/backward_tracer.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/backward_tracer.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/channel_analyzer.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/channel_analyzer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/channel_analyzer.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/channel_analyzer.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/fx/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/fx/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/custom_tracer.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/fx/custom_tracer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/custom_tracer.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/fx/custom_tracer.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/graph_utils.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/fx/graph_utils.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx/graph_utils.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/fx/graph_utils.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx_tracer.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/fx_tracer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/fx_tracer.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/fx_tracer.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/cascade_encoder_decoder_loss_calculator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/cascade_encoder_decoder_loss_calculator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/cascade_encoder_decoder_loss_calculator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/cascade_encoder_decoder_loss_calculator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/image_classifier_loss_calculator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/image_classifier_loss_calculator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/image_classifier_loss_calculator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/image_classifier_loss_calculator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/single_stage_detector_loss_calculator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/single_stage_detector_loss_calculator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/single_stage_detector_loss_calculator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/single_stage_detector_loss_calculator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/sum_loss_calculator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/sum_loss_calculator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/sum_loss_calculator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/sum_loss_calculator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/top_down_pose_estimator_loss_calculator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/top_down_pose_estimator_loss_calculator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/top_down_pose_estimator_loss_calculator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/top_down_pose_estimator_loss_calculator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/two_stage_detector_loss_calculator.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/two_stage_detector_loss_calculator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/two_stage_detector_loss_calculator.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/loss_calculator/two_stage_detector_loss_calculator.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/parsers.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/parsers.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/parsers.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/parsers.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/path.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/path.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/task_modules/tracer/path.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/task_modules/tracer/path.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/utils/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/expandable_utils/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/expandable_utils/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/ops.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/expandable_utils/ops.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/ops.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/expandable_utils/ops.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/tools.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/expandable_utils/tools.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/tools.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/expandable_utils/tools.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/unit.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/expandable_utils/unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/utils/expandable_utils/unit.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/expandable_utils/unit.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/make_divisible.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/make_divisible.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/utils/make_divisible.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/make_divisible.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/misc.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/misc.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/utils/misc.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/misc.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/optim_wrapper.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/optim_wrapper.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/utils/optim_wrapper.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/optim_wrapper.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/parse_values.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/parse_values.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/utils/parse_values.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/parse_values.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/quantization_util.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/quantization_util.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/utils/quantization_util.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/quantization_util.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/models/utils/utils.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/utils.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/models/utils/utils.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/models/utils/utils.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/registry/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/registry/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/registry/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/registry/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/registry/registry.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/registry/registry.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/registry/registry.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/registry/registry.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/graph/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/base_graph.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/base_graph.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/graph/base_graph.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/base_graph.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_flow.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/channel_flow.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_flow.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/channel_flow.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_graph.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/channel_graph.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_graph.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/channel_graph.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_nodes.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/channel_nodes.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/graph/channel_nodes.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/channel_nodes.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/module_graph.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/module_graph.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/graph/module_graph.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/module_graph.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/graph/pseudo_fx_graph.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/pseudo_fx_graph.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/graph/pseudo_fx_graph.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/graph/pseudo_fx_graph.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/academic.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/academic.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/academic.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/academic.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/common_operator_config_utils.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/common_operator_config_utils.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/common_operator_config_utils.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/common_operator_config_utils.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/mapping.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/mapping.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/mapping.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/mapping.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/native.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/native.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/native.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/native.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/openvino.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/openvino.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/openvino.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/openvino.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/tensorrt.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/tensorrt.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/backend_config/tensorrt.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/backend_config/tensorrt.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/qconfig.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/qconfig.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/quantization/qconfig.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/quantization/qconfig.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/subnet/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/subnet/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/candidate.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/subnet/candidate.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/candidate.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/subnet/candidate.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/fix_subnet.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/subnet/fix_subnet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/structures/subnet/fix_subnet.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/structures/subnet/fix_subnet.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/testing/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/testing/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/testing/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/testing/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/testing/_fast_stop_training_hook.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/testing/_fast_stop_training_hook.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/testing/_fast_stop_training_hook.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/testing/_fast_stop_training_hook.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/testing/_fx_models.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/testing/_fx_models.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/testing/_fx_models.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/testing/_fx_models.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/utils/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/index_dict.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/index_dict.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/utils/index_dict.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/index_dict.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/log_tools.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/log_tools.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/utils/log_tools.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/log_tools.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/misc.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/misc.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/utils/misc.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/misc.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/placeholder.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/placeholder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/utils/placeholder.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/placeholder.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/runtime_info.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/runtime_info.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/utils/runtime_info.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/runtime_info.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/setup_env.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/setup_env.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/utils/setup_env.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/setup_env.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/utils/typing.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/typing.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/utils/typing.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/utils/typing.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/version.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/version.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/version.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/version.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/visualization/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/visualization/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/visualization/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/visualization/__init__.py diff --git a/cv/distiller/CWD/mmrazor/mmrazor/visualization/local_visualizer.py b/cv/distiller/CWD/pytorch/mmrazor/mmrazor/visualization/local_visualizer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/mmrazor/visualization/local_visualizer.py rename to cv/distiller/CWD/pytorch/mmrazor/mmrazor/visualization/local_visualizer.py diff --git a/cv/distiller/CWD/mmrazor/model-index.yml b/cv/distiller/CWD/pytorch/mmrazor/model-index.yml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/model-index.yml rename to cv/distiller/CWD/pytorch/mmrazor/model-index.yml diff --git a/cv/distiller/CWD/mmrazor/requirements.txt b/cv/distiller/CWD/pytorch/mmrazor/requirements.txt old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/requirements.txt rename to cv/distiller/CWD/pytorch/mmrazor/requirements.txt diff --git a/cv/distiller/CWD/mmrazor/requirements/docs.txt b/cv/distiller/CWD/pytorch/mmrazor/requirements/docs.txt old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/requirements/docs.txt rename to cv/distiller/CWD/pytorch/mmrazor/requirements/docs.txt diff --git a/cv/distiller/CWD/mmrazor/requirements/mminstall.txt b/cv/distiller/CWD/pytorch/mmrazor/requirements/mminstall.txt old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/requirements/mminstall.txt rename to cv/distiller/CWD/pytorch/mmrazor/requirements/mminstall.txt diff --git a/cv/distiller/CWD/mmrazor/requirements/optional.txt b/cv/distiller/CWD/pytorch/mmrazor/requirements/optional.txt old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/requirements/optional.txt rename to cv/distiller/CWD/pytorch/mmrazor/requirements/optional.txt diff --git a/cv/distiller/CWD/mmrazor/requirements/readthedocs.txt b/cv/distiller/CWD/pytorch/mmrazor/requirements/readthedocs.txt old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/requirements/readthedocs.txt rename to cv/distiller/CWD/pytorch/mmrazor/requirements/readthedocs.txt diff --git a/cv/distiller/CWD/mmrazor/requirements/runtime.txt b/cv/distiller/CWD/pytorch/mmrazor/requirements/runtime.txt old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/requirements/runtime.txt rename to cv/distiller/CWD/pytorch/mmrazor/requirements/runtime.txt diff --git a/cv/distiller/CWD/mmrazor/requirements/tests.txt b/cv/distiller/CWD/pytorch/mmrazor/requirements/tests.txt old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/requirements/tests.txt rename to cv/distiller/CWD/pytorch/mmrazor/requirements/tests.txt diff --git a/cv/distiller/CWD/mmrazor/resources/design_and_implement.png b/cv/distiller/CWD/pytorch/mmrazor/resources/design_and_implement.png old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/resources/design_and_implement.png rename to cv/distiller/CWD/pytorch/mmrazor/resources/design_and_implement.png diff --git a/cv/distiller/CWD/mmrazor/resources/mmrazor-logo.png b/cv/distiller/CWD/pytorch/mmrazor/resources/mmrazor-logo.png old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/resources/mmrazor-logo.png rename to cv/distiller/CWD/pytorch/mmrazor/resources/mmrazor-logo.png diff --git a/cv/distiller/CWD/mmrazor/resources/qq_group_qrcode.jpg b/cv/distiller/CWD/pytorch/mmrazor/resources/qq_group_qrcode.jpg old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/resources/qq_group_qrcode.jpg rename to cv/distiller/CWD/pytorch/mmrazor/resources/qq_group_qrcode.jpg diff --git a/cv/distiller/CWD/mmrazor/resources/xiaozhushou_weixin_qrcode.jpeg b/cv/distiller/CWD/pytorch/mmrazor/resources/xiaozhushou_weixin_qrcode.jpeg old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/resources/xiaozhushou_weixin_qrcode.jpeg rename to cv/distiller/CWD/pytorch/mmrazor/resources/xiaozhushou_weixin_qrcode.jpeg diff --git a/cv/distiller/CWD/mmrazor/resources/zhihu_qrcode.jpg b/cv/distiller/CWD/pytorch/mmrazor/resources/zhihu_qrcode.jpg old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/resources/zhihu_qrcode.jpg rename to cv/distiller/CWD/pytorch/mmrazor/resources/zhihu_qrcode.jpg diff --git a/cv/distiller/CWD/mmrazor/setup.cfg b/cv/distiller/CWD/pytorch/mmrazor/setup.cfg old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/setup.cfg rename to cv/distiller/CWD/pytorch/mmrazor/setup.cfg diff --git a/cv/distiller/CWD/mmrazor/setup.py b/cv/distiller/CWD/pytorch/mmrazor/setup.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/setup.py rename to cv/distiller/CWD/pytorch/mmrazor/setup.py diff --git a/cv/distiller/CWD/mmrazor/tests/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/data/MBV2_220M.yaml b/cv/distiller/CWD/pytorch/mmrazor/tests/data/MBV2_220M.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/MBV2_220M.yaml rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/MBV2_220M.yaml diff --git a/cv/distiller/CWD/mmrazor/tests/data/MBV2_320M.yaml b/cv/distiller/CWD/pytorch/mmrazor/tests/data/MBV2_320M.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/MBV2_320M.yaml rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/MBV2_320M.yaml diff --git a/cv/distiller/CWD/mmrazor/tests/data/MBV2_530M.yaml b/cv/distiller/CWD/pytorch/mmrazor/tests/data/MBV2_530M.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/MBV2_530M.yaml rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/MBV2_530M.yaml diff --git a/cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_channel_config.json b/cv/distiller/CWD/pytorch/mmrazor/tests/data/MBV2_slimmable_channel_config.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_channel_config.json rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/MBV2_slimmable_channel_config.json diff --git a/cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_config.json b/cv/distiller/CWD/pytorch/mmrazor/tests/data/MBV2_slimmable_config.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_config.json rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/MBV2_slimmable_config.json diff --git a/cv/distiller/CWD/mmrazor/tests/data/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/data/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/data/color.jpeg b/cv/distiller/CWD/pytorch/mmrazor/tests/data/color.jpeg old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/color.jpeg rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/color.jpeg diff --git a/cv/distiller/CWD/mmrazor/tests/data/concat_subnet1.yaml b/cv/distiller/CWD/pytorch/mmrazor/tests/data/concat_subnet1.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/concat_subnet1.yaml rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/concat_subnet1.yaml diff --git a/cv/distiller/CWD/mmrazor/tests/data/concat_subnet2.yaml b/cv/distiller/CWD/pytorch/mmrazor/tests/data/concat_subnet2.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/concat_subnet2.yaml rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/concat_subnet2.yaml diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/a/1.JPG b/cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/a/1.JPG old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/dataset/a/1.JPG rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/a/1.JPG diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/ann.json b/cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/ann.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/dataset/ann.json rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/ann.json diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/ann.txt b/cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/ann.txt old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/dataset/ann.txt rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/ann.txt diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/b/2.jpeg b/cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/b/2.jpeg old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/dataset/b/2.jpeg rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/b/2.jpeg diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/b/subb/3.jpg b/cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/b/subb/3.jpg old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/dataset/b/subb/3.jpg rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/b/subb/3.jpg diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/classes.txt b/cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/classes.txt old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/dataset/classes.txt rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/classes.txt diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/multi_label_ann.json b/cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/multi_label_ann.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/dataset/multi_label_ann.json rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/dataset/multi_label_ann.json diff --git a/cv/distiller/CWD/mmrazor/tests/data/model_library.py b/cv/distiller/CWD/pytorch/mmrazor/tests/data/model_library.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/model_library.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/model_library.py diff --git a/cv/distiller/CWD/mmrazor/tests/data/models.py b/cv/distiller/CWD/pytorch/mmrazor/tests/data/models.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/models.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/models.py diff --git a/cv/distiller/CWD/mmrazor/tests/data/subnet1.yaml b/cv/distiller/CWD/pytorch/mmrazor/tests/data/subnet1.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/subnet1.yaml rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/subnet1.yaml diff --git a/cv/distiller/CWD/mmrazor/tests/data/subnet2.yaml b/cv/distiller/CWD/pytorch/mmrazor/tests/data/subnet2.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/subnet2.yaml rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/subnet2.yaml diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_models/test_algorithm/MBV2_220M.yaml b/cv/distiller/CWD/pytorch/mmrazor/tests/data/test_models/test_algorithm/MBV2_220M.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/test_models/test_algorithm/MBV2_220M.yaml rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/test_models/test_algorithm/MBV2_220M.yaml diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_models/test_mutator/subnet1.json b/cv/distiller/CWD/pytorch/mmrazor/tests/data/test_models/test_mutator/subnet1.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/test_models/test_mutator/subnet1.json rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/test_models/test_mutator/subnet1.json diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_models/test_subnet/mockmodel_subnet.yaml b/cv/distiller/CWD/pytorch/mmrazor/tests/data/test_models/test_subnet/mockmodel_subnet.yaml old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/test_models/test_subnet/mockmodel_subnet.yaml rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/test_models/test_subnet/mockmodel_subnet.yaml diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_models/test_task_modules/mmcls_cfg.py b/cv/distiller/CWD/pytorch/mmrazor/tests/data/test_models/test_task_modules/mmcls_cfg.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/test_models/test_task_modules/mmcls_cfg.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/test_models/test_task_modules/mmcls_cfg.py diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_architecture_config.py b/cv/distiller/CWD/pytorch/mmrazor/tests/data/test_registry/registry_architecture_config.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_architecture_config.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/test_registry/registry_architecture_config.py diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_subnet_config.py b/cv/distiller/CWD/pytorch/mmrazor/tests/data/test_registry/registry_subnet_config.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_subnet_config.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/test_registry/registry_subnet_config.py diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_registry/subnet.json b/cv/distiller/CWD/pytorch/mmrazor/tests/data/test_registry/subnet.json old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/test_registry/subnet.json rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/test_registry/subnet.json diff --git a/cv/distiller/CWD/mmrazor/tests/data/tracer_passed_models.py b/cv/distiller/CWD/pytorch/mmrazor/tests/data/tracer_passed_models.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/data/tracer_passed_models.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/data/tracer_passed_models.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_deliver_manager.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_delivers/test_deliver_manager.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_deliver_manager.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_delivers/test_deliver_manager.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_function_outputs_deliver.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_delivers/test_function_outputs_deliver.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_function_outputs_deliver.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_delivers/test_function_outputs_deliver.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_method_outputs_deliver.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_delivers/test_method_outputs_deliver.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_method_outputs_deliver.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_delivers/test_method_outputs_deliver.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/toy_module.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_delivers/toy_module.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/toy_module.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_delivers/toy_module.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_graph/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_graph/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_graph/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_flow.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_graph/test_channel_flow.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_flow.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_graph/test_channel_flow.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_graph.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_graph/test_channel_graph.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_graph.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_graph/test_channel_graph.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_graph.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_graph/test_graph.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_graph.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_graph/test_graph.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_prune_tracer_model.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_graph/test_prune_tracer_model.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_prune_tracer_model.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_graph/test_prune_tracer_model.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_base_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_base_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_base_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_base_recorder.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_inputs_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_func_inputs_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_inputs_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_func_inputs_recorder.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_outputs_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_func_outputs_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_outputs_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_func_outputs_recorder.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_inputs_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_method_inputs_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_inputs_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_method_inputs_recorder.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_outputs_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_method_outputs_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_outputs_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_method_outputs_recorder.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_module_recorders.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_module_recorders.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_module_recorders.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_module_recorders.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_param_recorder.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_param_recorder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_param_recorder.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_param_recorder.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_recorder_manager.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_recorder_manager.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_recorder_manager.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/test_recorder_manager.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/toy_mod.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/toy_mod.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/toy_mod.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_recorders/toy_mod.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_tracer/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_tracer/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_backward_tracer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_tracer/test_backward_tracer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_backward_tracer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_tracer/test_backward_tracer.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_fx_tracer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_tracer/test_fx_tracer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_fx_tracer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_tracer/test_fx_tracer.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_loss_calculator.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_tracer/test_loss_calculator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_loss_calculator.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_tracer/test_loss_calculator.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_prune_tracer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_tracer/test_prune_tracer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_prune_tracer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_core/test_tracer/test_prune_tracer.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_data.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_data.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_data.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_data.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_datasets/test_datasets.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_datasets/test_datasets.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_datasets/test_datasets.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_datasets/test_datasets.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_datasets/test_transforms/test_formatting.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_datasets/test_transforms/test_formatting.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_datasets/test_transforms/test_formatting.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_datasets/test_transforms/test_formatting.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_doc.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_doc.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_doc.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_doc.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_stop_distillation_hook.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_engine/test_hooks/test_stop_distillation_hook.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_stop_distillation_hook.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_engine/test_hooks/test_stop_distillation_hook.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_visualization_hook.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_engine/test_hooks/test_visualization_hook.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_visualization_hook.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_engine/test_hooks/test_visualization_hook.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_impl/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/test_group_fisher/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/test_group_fisher/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_algorithm.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_algorithm.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_algorithm.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_algorithm.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_deploy_sub_model.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_deploy_sub_model.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_deploy_sub_model.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_deploy_sub_model.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_sub_model.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_sub_model.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_sub_model.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_sub_model.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_unit.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_unit.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoformer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_autoformer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoformer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_autoformer.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoslim.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_autoslim.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoslim.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_autoslim.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_base_algorithm.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_base_algorithm.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_base_algorithm.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_base_algorithm.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_bignas.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_bignas.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_bignas.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_bignas.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_darts.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_darts.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_darts.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_darts.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_datafree_distill.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_datafree_distill.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_datafree_distill.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_datafree_distill.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dcff_network.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_dcff_network.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dcff_network.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_dcff_network.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dmcp.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_dmcp.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dmcp.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_dmcp.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dsnas.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_dsnas.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dsnas.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_dsnas.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_general_quant.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_general_quant.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_general_quant.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_general_quant.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_mm_architecture.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_mm_architecture.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_mm_architecture.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_mm_architecture.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_ofd_algo.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_ofd_algo.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_ofd_algo.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_ofd_algo.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_prune_algorithm.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_prune_algorithm.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_prune_algorithm.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_prune_algorithm.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_self_distill.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_self_distill.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_self_distill.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_self_distill.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_single_teacher_distill.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_single_teacher_distill.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_single_teacher_distill.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_single_teacher_distill.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_slimmable_network.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_slimmable_network.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_slimmable_network.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_slimmable_network.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_spos.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_spos.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_spos.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/test_spos.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/toy_models.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/toy_models.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/toy_models.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_algorithms/toy_models.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_autoformerbackbone.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/test_autoformerbackbone.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_autoformerbackbone.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/test_autoformerbackbone.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_dartsbackbone.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/test_dartsbackbone.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_dartsbackbone.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/test_dartsbackbone.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v2.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v2.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v2.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v2.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v3.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v3.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v3.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v3.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_shufflenet_v2.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_shufflenet_v2.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_shufflenet_v2.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_shufflenet_v2.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/utils.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/utils.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/utils.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_backbones/utils.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_connectors/test_connectors.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_connectors/test_connectors.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_connectors/test_connectors.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_connectors/test_connectors.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_attention.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_attention.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_attention.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_attention.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_container.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_container.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_container.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_container.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_conv.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_conv.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_conv.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_conv.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_embed.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_embed.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_embed.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_embed.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_layernorm.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_layernorm.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_layernorm.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_layernorm.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_linear.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_linear.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_linear.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_linear.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_norm.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_norm.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_norm.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_norm.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_relative_position.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_relative_position.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_relative_position.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_relative_position.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_resizer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_resizer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_resizer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_resizer.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/utils.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/utils.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/utils.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_dynamic_op/utils.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_generators/test_generators.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_generators/test_generators.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_generators/test_generators.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_architectures/test_generators/test_generators.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_classifier/test_imageclassifier.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_classifier/test_imageclassifier.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_classifier/test_imageclassifier.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_classifier/test_imageclassifier.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_byot_distill.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_distillers/test_byot_distill.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_byot_distill.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_distillers/test_byot_distill.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_configurable_distill.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_distillers/test_configurable_distill.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_configurable_distill.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_distillers/test_configurable_distill.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_lsq_fake_quants.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_fake_quants/test_lsq_fake_quants.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_lsq_fake_quants.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_fake_quants/test_lsq_fake_quants.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_torch_fake_quants.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_fake_quants/test_torch_fake_quants.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_torch_fake_quants.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_fake_quants/test_torch_fake_quants.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_distillation_losses.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_losses/test_distillation_losses.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_distillation_losses.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_losses/test_distillation_losses.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_general_losses.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_losses/test_general_losses.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_general_losses.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_losses/test_general_losses.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_derived_mutable.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_derived_mutable.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_derived_mutable.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_derived_mutable.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffchoiceroute.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_diffchoiceroute.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffchoiceroute.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_diffchoiceroute.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffop.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_diffop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffop.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_diffop.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_gumbelchoiceroute.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_gumbelchoiceroute.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_gumbelchoiceroute.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_gumbelchoiceroute.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_mutable_channels.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_mutable_channels.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_mutable_channels.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_mutable_channels.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_sequential_mutable_channel.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_sequential_mutable_channel.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_sequential_mutable_channel.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_sequential_mutable_channel.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_dcff_channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_dcff_channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_dcff_channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_dcff_channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_l1_mutable_channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_l1_mutable_channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_l1_mutable_channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_l1_mutable_channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_mutable_channel_units.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_mutable_channel_units.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_mutable_channel_units.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_mutable_channel_units.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_one_shot_mutable_channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_one_shot_mutable_channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_one_shot_mutable_channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_one_shot_mutable_channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_sequential_mutable_channel_unit.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_sequential_mutable_channel_unit.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_sequential_mutable_channel_unit.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_sequential_mutable_channel_unit.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_value.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_value.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_value.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_mutable_value.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_onehotop.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_onehotop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_onehotop.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_onehotop.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_oneshotop.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_oneshotop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_oneshotop.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_oneshotop.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_sequential_mutable_channel.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_sequential_mutable_channel.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_sequential_mutable_channel.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutables/test_sequential_mutable_channel.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutators/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutators/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_channel_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutators/test_channel_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_channel_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutators/test_channel_mutator.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dcff_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutators/test_dcff_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dcff_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutators/test_dcff_mutator.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dmcp_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutators/test_dmcp_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dmcp_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutators/test_dmcp_mutator.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_nas_mutator.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutators/test_nas_mutator.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_nas_mutator.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_mutators/test_nas_mutator.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_lsq_observer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_observers/test_lsq_observer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_lsq_observer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_observers/test_lsq_observer.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_torch_observers.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_observers/test_torch_observers.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_torch_observers.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_observers/test_torch_observers.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_academic_quantizer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_quantizers/test_academic_quantizer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_academic_quantizer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_quantizers/test_academic_quantizer.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_exporter.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_quantizers/test_exporter.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_exporter.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_quantizers/test_exporter.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_native_quantizer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_quantizers/test_native_quantizer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_native_quantizer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_quantizers/test_native_quantizer.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_openvino_quantizer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_quantizers/test_openvino_quantizer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_openvino_quantizer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_quantizers/test_openvino_quantizer.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_tensorrt_quantizer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_quantizers/test_tensorrt_quantizer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_tensorrt_quantizer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_quantizers/test_tensorrt_quantizer.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_candidate.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_subnet/test_candidate.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_candidate.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_subnet/test_candidate.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_fix_subnet.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_subnet/test_fix_subnet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_fix_subnet.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_subnet/test_fix_subnet.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_custom_tracer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_custom_tracer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_custom_tracer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_custom_tracer.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/test_demo_inputs.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/test_demo_inputs.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/test_demo_inputs.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/test_demo_inputs.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_estimators/test_flops_params.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_estimators/test_flops_params.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_estimators/test_flops_params.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_estimators/test_flops_params.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_graph_utils.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_graph_utils.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_graph_utils.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_graph_utils.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_predictors/test_metric_predictor.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_predictors/test_metric_predictor.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_predictors/test_metric_predictor.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_task_modules/test_predictors/test_metric_predictor.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_utils/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_utils/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_utils/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_utils/test_expandable_utils/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_utils/test_expandable_utils/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/test_expand.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_utils/test_expandable_utils/test_expand.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/test_expand.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_models/test_utils/test_expandable_utils/test_expand.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_registry/test_registry.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_registry/test_registry.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_registry/test_registry.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_registry/test_registry.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_autoslim_greedy_search_loop.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_autoslim_greedy_search_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_runners/test_autoslim_greedy_search_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_autoslim_greedy_search_loop.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_darts_loop.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_darts_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_runners/test_darts_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_darts_loop.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_distill_val_loop.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_distill_val_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_runners/test_distill_val_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_distill_val_loop.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_evolution_search_loop.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_evolution_search_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_runners/test_evolution_search_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_evolution_search_loop.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_quantization_loop.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_quantization_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_runners/test_quantization_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_quantization_loop.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_subnet_sampler_loop.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_subnet_sampler_loop.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_runners/test_subnet_sampler_loop.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_subnet_sampler_loop.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_calibrate_bn_mixin.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_utils/test_calibrate_bn_mixin.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_calibrate_bn_mixin.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_utils/test_calibrate_bn_mixin.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_check.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_utils/test_check.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_check.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_utils/test_check.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_genetic.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_utils/test_genetic.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_genetic.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_runners/test_utils/test_genetic.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_structures/test_backendconfig.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_structures/test_backendconfig.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_structures/test_backendconfig.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_structures/test_backendconfig.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_structures/test_qconfig.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_structures/test_qconfig.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_structures/test_qconfig.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_structures/test_qconfig.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_tools/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_tools/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_tools/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_tools/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_tools/test_tools.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_tools/test_tools.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_tools/test_tools.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_tools/test_tools.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_utils/test_index_dict.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_utils/test_index_dict.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_utils/test_index_dict.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_utils/test_index_dict.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_utils/test_placeholder.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_utils/test_placeholder.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_utils/test_placeholder.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_utils/test_placeholder.py diff --git a/cv/distiller/CWD/mmrazor/tests/test_visualizer/test_visualizer.py b/cv/distiller/CWD/pytorch/mmrazor/tests/test_visualizer/test_visualizer.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/test_visualizer/test_visualizer.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/test_visualizer/test_visualizer.py diff --git a/cv/distiller/CWD/mmrazor/tests/utils/__init__.py b/cv/distiller/CWD/pytorch/mmrazor/tests/utils/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/utils/__init__.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/utils/__init__.py diff --git a/cv/distiller/CWD/mmrazor/tests/utils/set_dist_env.py b/cv/distiller/CWD/pytorch/mmrazor/tests/utils/set_dist_env.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/utils/set_dist_env.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/utils/set_dist_env.py diff --git a/cv/distiller/CWD/mmrazor/tests/utils/set_torch_thread.py b/cv/distiller/CWD/pytorch/mmrazor/tests/utils/set_torch_thread.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tests/utils/set_torch_thread.py rename to cv/distiller/CWD/pytorch/mmrazor/tests/utils/set_torch_thread.py diff --git a/cv/distiller/CWD/mmrazor/tools/dataset_converters/cityscapes.py b/cv/distiller/CWD/pytorch/mmrazor/tools/dataset_converters/cityscapes.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/dataset_converters/cityscapes.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/dataset_converters/cityscapes.py diff --git a/cv/distiller/CWD/mmrazor/tools/dist_test.sh b/cv/distiller/CWD/pytorch/mmrazor/tools/dist_test.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/dist_test.sh rename to cv/distiller/CWD/pytorch/mmrazor/tools/dist_test.sh diff --git a/cv/distiller/CWD/mmrazor/tools/dist_train.sh b/cv/distiller/CWD/pytorch/mmrazor/tools/dist_train.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/dist_train.sh rename to cv/distiller/CWD/pytorch/mmrazor/tools/dist_train.sh diff --git a/cv/distiller/CWD/mmrazor/tools/misc/print_config.py b/cv/distiller/CWD/pytorch/mmrazor/tools/misc/print_config.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/misc/print_config.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/misc/print_config.py diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_attentivenas_nas_ckpt.py b/cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_attentivenas_nas_ckpt.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/model_converters/convert_attentivenas_nas_ckpt.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_attentivenas_nas_ckpt.py diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_bignas_gml_ckpt.py b/cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_bignas_gml_ckpt.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/model_converters/convert_bignas_gml_ckpt.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_bignas_gml_ckpt.py diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt.py b/cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_kd_ckpt.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_kd_ckpt.py diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt_to_student.py b/cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_kd_ckpt_to_student.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt_to_student.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_kd_ckpt_to_student.py diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_ofa_ckpt.py b/cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_ofa_ckpt.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/model_converters/convert_ofa_ckpt.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_ofa_ckpt.py diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_quant_ckpt.py b/cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_quant_ckpt.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/model_converters/convert_quant_ckpt.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_quant_ckpt.py diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_supernet2subnet.py b/cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_supernet2subnet.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/model_converters/convert_supernet2subnet.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/convert_supernet2subnet.py diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/publish_model.py b/cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/publish_model.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/model_converters/publish_model.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/model_converters/publish_model.py diff --git a/cv/distiller/CWD/mmrazor/tools/pruning/get_channel_units.py b/cv/distiller/CWD/pytorch/mmrazor/tools/pruning/get_channel_units.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/pruning/get_channel_units.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/pruning/get_channel_units.py diff --git a/cv/distiller/CWD/mmrazor/tools/pruning/get_flops.py b/cv/distiller/CWD/pytorch/mmrazor/tools/pruning/get_flops.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/pruning/get_flops.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/pruning/get_flops.py diff --git a/cv/distiller/CWD/mmrazor/tools/pruning/get_l1_prune_config.py b/cv/distiller/CWD/pytorch/mmrazor/tools/pruning/get_l1_prune_config.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/pruning/get_l1_prune_config.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/pruning/get_l1_prune_config.py diff --git a/cv/distiller/CWD/mmrazor/tools/pruning/get_static_model_from_algorithm.py b/cv/distiller/CWD/pytorch/mmrazor/tools/pruning/get_static_model_from_algorithm.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/pruning/get_static_model_from_algorithm.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/pruning/get_static_model_from_algorithm.py diff --git a/cv/distiller/CWD/mmrazor/tools/ptq.py b/cv/distiller/CWD/pytorch/mmrazor/tools/ptq.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/ptq.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/ptq.py diff --git a/cv/distiller/CWD/mmrazor/tools/slurm_test.sh b/cv/distiller/CWD/pytorch/mmrazor/tools/slurm_test.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/slurm_test.sh rename to cv/distiller/CWD/pytorch/mmrazor/tools/slurm_test.sh diff --git a/cv/distiller/CWD/mmrazor/tools/slurm_train.sh b/cv/distiller/CWD/pytorch/mmrazor/tools/slurm_train.sh old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/slurm_train.sh rename to cv/distiller/CWD/pytorch/mmrazor/tools/slurm_train.sh diff --git a/cv/distiller/CWD/mmrazor/tools/test.py b/cv/distiller/CWD/pytorch/mmrazor/tools/test.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/test.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/test.py diff --git a/cv/distiller/CWD/mmrazor/tools/train.py b/cv/distiller/CWD/pytorch/mmrazor/tools/train.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/train.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/train.py diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/demo.jpg b/cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/demo.jpg old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/visualizations/demo.jpg rename to cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/demo.jpg diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/feature_diff_visualization.py b/cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/feature_diff_visualization.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/visualizations/feature_diff_visualization.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/feature_diff_visualization.py diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/feature_visualization.py b/cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/feature_visualization.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/visualizations/feature_visualization.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/feature_visualization.py diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_diff_visualization.py b/cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/vis_configs/backbone_feature_diff_visualization.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_diff_visualization.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/vis_configs/backbone_feature_diff_visualization.py diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_visualization.py b/cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/vis_configs/backbone_feature_visualization.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/backbone_feature_visualization.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/vis_configs/backbone_feature_visualization.py diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_diff_visualization.py b/cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/vis_configs/fpn_feature_diff_visualization.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_diff_visualization.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/vis_configs/fpn_feature_diff_visualization.py diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_visualization.py b/cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/vis_configs/fpn_feature_visualization.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/visualizations/vis_configs/fpn_feature_visualization.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/vis_configs/fpn_feature_visualization.py diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/vis_scheduler.py b/cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/vis_scheduler.py old mode 100755 new mode 100644 similarity index 100% rename from cv/distiller/CWD/mmrazor/tools/visualizations/vis_scheduler.py rename to cv/distiller/CWD/pytorch/mmrazor/tools/visualizations/vis_scheduler.py -- Gitee

    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 Q5e+X_`$G&2^w+8X1u%?H6#xJL literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmrazor/setup.cfg b/cv/distiller/CWD/mmrazor/setup.cfg new file mode 100755 index 000000000..f3eceac29 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/setup.cfg @@ -0,0 +1,24 @@ +[bdist_wheel] +universal=1 + +[aliases] +test=pytest + +[yapf] +based_on_style = pep8 +blank_line_before_nested_class_or_def = true +split_before_expression_after_opening_paren = true + +[isort] +line_length = 79 +multi_line_output = 0 +extra_standard_library = pkg_resources,setuptools +known_first_party = mmrazor +known_third_party=cv2,mmcls,mmcv,mmdet,mmseg,numpy,ordered_set,packaging,pytest,pytorch_sphinx_theme,torch,yaml +no_lines_before = STDLIB,LOCALFOLDER +default_section = THIRDPARTY + +[codespell] +skip = *.ipynb +quiet-level = 3 +ignore-words-list = patten,confectionary,nd,ty,formating diff --git a/cv/distiller/CWD/mmrazor/setup.py b/cv/distiller/CWD/mmrazor/setup.py new file mode 100755 index 000000000..4d69ff2d4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/setup.py @@ -0,0 +1,192 @@ +import os +import os.path as osp +import shutil +import sys +import warnings +from setuptools import find_packages, setup + + +def readme(): + with open('README.md', encoding='utf-8') as f: + content = f.read() + return content + + +def get_version(): + version_file = 'mmrazor/version.py' + with open(version_file, 'r', encoding='utf-8') as f: + exec(compile(f.read(), version_file, 'exec')) + return locals()['__version__'] + + +def parse_requirements(fname='requirements.txt', with_version=True): + """Parse the package dependencies listed in a requirements file but strips + specific versioning information. + + Args: + fname (str): path to requirements file + with_version (bool, default=False): if True include version specs + + Returns: + List[str]: list of requirements items + + CommandLine: + python -c "import setup; print(setup.parse_requirements())" + """ + import re + import sys + from os.path import exists + require_fpath = fname + + def parse_line(line): + """Parse information from a line in a requirements text file.""" + if line.startswith('-r '): + # Allow specifying requirements in other files + target = line.split(' ')[1] + for info in parse_require_file(target): + yield info + else: + info = {'line': line} + if line.startswith('-e '): + info['package'] = line.split('#egg=')[1] + else: + # Remove versioning from the package + pat = '(' + '|'.join(['>=', '==', '>']) + ')' + parts = re.split(pat, line, maxsplit=1) + parts = [p.strip() for p in parts] + + info['package'] = parts[0] + if len(parts) > 1: + op, rest = parts[1:] + if ';' in rest: + # Handle platform specific dependencies + # http://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies + version, platform_deps = map(str.strip, + rest.split(';')) + info['platform_deps'] = platform_deps + else: + version = rest # NOQA + info['version'] = (op, version) + yield info + + def parse_require_file(fpath): + with open(fpath, 'r') as f: + for line in f.readlines(): + line = line.strip() + if line and not line.startswith('#'): + for info in parse_line(line): + yield info + + def gen_packages_items(): + if exists(require_fpath): + for info in parse_require_file(require_fpath): + parts = [info['package']] + if with_version and 'version' in info: + parts.extend(info['version']) + if not sys.version.startswith('3.4'): + # apparently package_deps are broken in 3.4 + platform_deps = info.get('platform_deps') + if platform_deps is not None: + parts.append(';' + platform_deps) + item = ''.join(parts) + yield item + + packages = list(gen_packages_items()) + return packages + + +def add_mim_extension(): + """Add extra files that are required to support MIM into the package. + + These files will be added by creating a symlink to the originals if the + package is installed in `editable` mode (e.g. pip install -e .), or by + copying from the originals otherwise. + """ + + # parse installment mode + if 'develop' in sys.argv: + # installed by `pip install -e .` + mode = 'symlink' + elif 'sdist' in sys.argv or 'bdist_wheel' in sys.argv: + # installed by `pip install .` + # or create source distribution by `python setup.py sdist` + mode = 'copy' + else: + return + + filenames = ['tools', 'configs', 'model-index.yml'] + repo_path = osp.dirname(__file__) + mim_path = osp.join(repo_path, 'mmrazor', '.mim') + os.makedirs(mim_path, exist_ok=True) + + for filename in filenames: + if osp.exists(filename): + src_path = osp.join(repo_path, filename) + tar_path = osp.join(mim_path, filename) + + if osp.isfile(tar_path) or osp.islink(tar_path): + os.remove(tar_path) + elif osp.isdir(tar_path): + shutil.rmtree(tar_path) + + if mode == 'symlink': + src_relpath = osp.relpath(src_path, osp.dirname(tar_path)) + try: + os.symlink(src_relpath, tar_path) + except OSError: + # Creating a symbolic link on windows may raise an + # `OSError: [WinError 1314]` due to privilege. If + # the error happens, the src file will be copied + mode = 'copy' + warnings.warn( + f'Failed to create a symbolic link for {src_relpath}, ' + f'and it will be copied to {tar_path}') + else: + continue + + elif mode == 'copy': + if osp.isfile(src_path): + shutil.copyfile(src_path, tar_path) + elif osp.isdir(src_path): + shutil.copytree(src_path, tar_path) + else: + warnings.warn(f'Cannot copy file {src_path}.') + else: + raise ValueError(f'Invalid mode {mode}') + + +if __name__ == '__main__': + add_mim_extension() + setup( + name='mmrazor', + version=get_version(), + description='OpenMMLab Model Compression Toolbox and Benchmark', + long_description=readme(), + long_description_content_type='text/markdown', + keywords='computer vision, model compression', + packages=find_packages(exclude=('configs', 'tools', 'demo')), + include_package_data=True, + classifiers=[ + 'Development Status :: 4 - Beta', + 'License :: OSI Approved :: Apache Software License', + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Topic :: Scientific/Engineering :: Artificial Intelligence', + ], + url='https://github.com/open-mmlab/mmrazor', + author='MMRazor Contributors', + author_email='openmmlab@gmail.com', + license='Apache License 2.0', + install_requires=parse_requirements('requirements/runtime.txt'), + extras_require={ + 'all': parse_requirements('requirements.txt'), + 'tests': parse_requirements('requirements/tests.txt'), + 'optional': parse_requirements('requirements/optional.txt'), + 'mim': parse_requirements('requirements/mminstall.txt'), + }, + zip_safe=False) diff --git a/cv/distiller/CWD/mmrazor/tests/__init__.py b/cv/distiller/CWD/mmrazor/tests/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/data/MBV2_220M.yaml b/cv/distiller/CWD/mmrazor/tests/data/MBV2_220M.yaml new file mode 100755 index 000000000..2aa967c8d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/MBV2_220M.yaml @@ -0,0 +1,474 @@ +backbone.conv1.bn.mutable_num_features: + current_choice: 8 + origin_channels: 48 +backbone.conv1.conv.mutable_in_channels: + current_choice: 3 + origin_channels: 3 +backbone.conv1.conv.mutable_out_channels: + current_choice: 8 + origin_channels: 48 +backbone.conv2.bn.mutable_num_features: + current_choice: 1920 + origin_channels: 1920 +backbone.conv2.conv.mutable_in_channels: + current_choice: 280 + origin_channels: 480 +backbone.conv2.conv.mutable_out_channels: + current_choice: 1920 + origin_channels: 1920 +backbone.layer1.0.conv.0.bn.mutable_num_features: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.0.conv.mutable_in_channels: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.0.conv.mutable_out_channels: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.1.bn.mutable_num_features: + current_choice: 8 + origin_channels: 24 +backbone.layer1.0.conv.1.conv.mutable_in_channels: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.1.conv.mutable_out_channels: + current_choice: 8 + origin_channels: 24 +backbone.layer2.0.conv.0.bn.mutable_num_features: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.0.conv.mutable_in_channels: + current_choice: 8 + origin_channels: 24 +backbone.layer2.0.conv.0.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.1.bn.mutable_num_features: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.1.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.1.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.2.bn.mutable_num_features: + current_choice: 16 + origin_channels: 40 +backbone.layer2.0.conv.2.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.2.conv.mutable_out_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer2.1.conv.0.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.0.conv.mutable_in_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer2.1.conv.0.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.1.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.1.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.1.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.2.bn.mutable_num_features: + current_choice: 16 + origin_channels: 40 +backbone.layer2.1.conv.2.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.2.conv.mutable_out_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer3.0.conv.0.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.0.conv.mutable_in_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer3.0.conv.0.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.1.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.1.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.1.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.2.bn.mutable_num_features: + current_choice: 24 + origin_channels: 48 +backbone.layer3.0.conv.2.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.2.conv.mutable_out_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.1.conv.0.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.0.conv.mutable_in_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.1.conv.0.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.1.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.1.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.1.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.2.bn.mutable_num_features: + current_choice: 24 + origin_channels: 48 +backbone.layer3.1.conv.2.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.2.conv.mutable_out_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.2.conv.0.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.0.conv.mutable_in_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.2.conv.0.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.2.bn.mutable_num_features: + current_choice: 24 + origin_channels: 48 +backbone.layer3.2.conv.2.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.2.conv.mutable_out_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer4.0.conv.0.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.0.conv.mutable_in_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer4.0.conv.0.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.1.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.1.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.1.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.2.bn.mutable_num_features: + current_choice: 48 + origin_channels: 96 +backbone.layer4.0.conv.2.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.2.conv.mutable_out_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.1.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.0.conv.mutable_in_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.1.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.2.bn.mutable_num_features: + current_choice: 48 + origin_channels: 96 +backbone.layer4.1.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.2.conv.mutable_out_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.2.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.0.conv.mutable_in_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.2.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.2.bn.mutable_num_features: + current_choice: 48 + origin_channels: 96 +backbone.layer4.2.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.2.conv.mutable_out_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.3.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.0.conv.mutable_in_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.3.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.2.bn.mutable_num_features: + current_choice: 48 + origin_channels: 96 +backbone.layer4.3.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.2.conv.mutable_out_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer5.0.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.0.conv.mutable_in_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer5.0.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.2.bn.mutable_num_features: + current_choice: 64 + origin_channels: 144 +backbone.layer5.0.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.2.conv.mutable_out_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer5.1.conv.0.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.0.conv.mutable_in_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer5.1.conv.0.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.1.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.1.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.1.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.2.bn.mutable_num_features: + current_choice: 64 + origin_channels: 144 +backbone.layer5.1.conv.2.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.2.conv.mutable_out_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer5.2.conv.0.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.0.conv.mutable_in_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer5.2.conv.0.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.1.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.1.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.1.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.2.bn.mutable_num_features: + current_choice: 64 + origin_channels: 144 +backbone.layer5.2.conv.2.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.2.conv.mutable_out_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer6.0.conv.0.bn.mutable_num_features: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.0.conv.mutable_in_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer6.0.conv.0.conv.mutable_out_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.1.bn.mutable_num_features: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.1.conv.mutable_in_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.1.conv.mutable_out_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.2.bn.mutable_num_features: + current_choice: 176 + origin_channels: 240 +backbone.layer6.0.conv.2.conv.mutable_in_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.2.conv.mutable_out_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer6.1.conv.0.bn.mutable_num_features: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.0.conv.mutable_in_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer6.1.conv.0.conv.mutable_out_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.1.bn.mutable_num_features: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.1.conv.mutable_in_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.1.conv.mutable_out_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.2.bn.mutable_num_features: + current_choice: 176 + origin_channels: 240 +backbone.layer6.1.conv.2.conv.mutable_in_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.2.conv.mutable_out_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer6.2.conv.0.bn.mutable_num_features: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.0.conv.mutable_in_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer6.2.conv.0.conv.mutable_out_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.1.bn.mutable_num_features: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.1.conv.mutable_in_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.1.conv.mutable_out_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.2.bn.mutable_num_features: + current_choice: 176 + origin_channels: 240 +backbone.layer6.2.conv.2.conv.mutable_in_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.2.conv.mutable_out_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer7.0.conv.0.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.0.conv.mutable_in_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer7.0.conv.0.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.2.bn.mutable_num_features: + current_choice: 280 + origin_channels: 480 +backbone.layer7.0.conv.2.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.2.conv.mutable_out_channels: + current_choice: 280 + origin_channels: 480 +head.fc.mutable_in_features: + current_choice: 1920 + origin_channels: 1920 +head.fc.mutable_out_features: + current_choice: 1000 + origin_channels: 1000 diff --git a/cv/distiller/CWD/mmrazor/tests/data/MBV2_320M.yaml b/cv/distiller/CWD/mmrazor/tests/data/MBV2_320M.yaml new file mode 100755 index 000000000..2c63bcf76 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/MBV2_320M.yaml @@ -0,0 +1,474 @@ +backbone.conv1.bn.mutable_num_features: + current_choice: 8 + origin_channels: 48 +backbone.conv1.conv.mutable_in_channels: + current_choice: 3 + origin_channels: 3 +backbone.conv1.conv.mutable_out_channels: + current_choice: 8 + origin_channels: 48 +backbone.conv2.bn.mutable_num_features: + current_choice: 1920 + origin_channels: 1920 +backbone.conv2.conv.mutable_in_channels: + current_choice: 480 + origin_channels: 480 +backbone.conv2.conv.mutable_out_channels: + current_choice: 1920 + origin_channels: 1920 +backbone.layer1.0.conv.0.bn.mutable_num_features: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.0.conv.mutable_in_channels: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.0.conv.mutable_out_channels: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.1.bn.mutable_num_features: + current_choice: 8 + origin_channels: 24 +backbone.layer1.0.conv.1.conv.mutable_in_channels: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.1.conv.mutable_out_channels: + current_choice: 8 + origin_channels: 24 +backbone.layer2.0.conv.0.bn.mutable_num_features: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.0.conv.mutable_in_channels: + current_choice: 8 + origin_channels: 24 +backbone.layer2.0.conv.0.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.1.bn.mutable_num_features: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.1.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.1.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.2.bn.mutable_num_features: + current_choice: 16 + origin_channels: 40 +backbone.layer2.0.conv.2.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.2.conv.mutable_out_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer2.1.conv.0.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.0.conv.mutable_in_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer2.1.conv.0.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.1.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.1.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.1.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.2.bn.mutable_num_features: + current_choice: 16 + origin_channels: 40 +backbone.layer2.1.conv.2.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.2.conv.mutable_out_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer3.0.conv.0.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.0.conv.mutable_in_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer3.0.conv.0.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.1.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.1.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.1.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.2.bn.mutable_num_features: + current_choice: 24 + origin_channels: 48 +backbone.layer3.0.conv.2.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.2.conv.mutable_out_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.1.conv.0.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.0.conv.mutable_in_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.1.conv.0.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.1.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.1.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.1.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.2.bn.mutable_num_features: + current_choice: 24 + origin_channels: 48 +backbone.layer3.1.conv.2.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.2.conv.mutable_out_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.2.conv.0.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.0.conv.mutable_in_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.2.conv.0.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.2.bn.mutable_num_features: + current_choice: 24 + origin_channels: 48 +backbone.layer3.2.conv.2.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.2.conv.mutable_out_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer4.0.conv.0.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.0.conv.mutable_in_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer4.0.conv.0.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.1.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.1.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.1.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.2.bn.mutable_num_features: + current_choice: 56 + origin_channels: 96 +backbone.layer4.0.conv.2.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.2.conv.mutable_out_channels: + current_choice: 56 + origin_channels: 96 +backbone.layer4.1.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.0.conv.mutable_in_channels: + current_choice: 56 + origin_channels: 96 +backbone.layer4.1.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.2.bn.mutable_num_features: + current_choice: 56 + origin_channels: 96 +backbone.layer4.1.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.2.conv.mutable_out_channels: + current_choice: 56 + origin_channels: 96 +backbone.layer4.2.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.0.conv.mutable_in_channels: + current_choice: 56 + origin_channels: 96 +backbone.layer4.2.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.2.bn.mutable_num_features: + current_choice: 56 + origin_channels: 96 +backbone.layer4.2.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.2.conv.mutable_out_channels: + current_choice: 56 + origin_channels: 96 +backbone.layer4.3.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.0.conv.mutable_in_channels: + current_choice: 56 + origin_channels: 96 +backbone.layer4.3.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.2.bn.mutable_num_features: + current_choice: 56 + origin_channels: 96 +backbone.layer4.3.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.2.conv.mutable_out_channels: + current_choice: 56 + origin_channels: 96 +backbone.layer5.0.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.0.conv.mutable_in_channels: + current_choice: 56 + origin_channels: 96 +backbone.layer5.0.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.2.bn.mutable_num_features: + current_choice: 96 + origin_channels: 144 +backbone.layer5.0.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.2.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer5.1.conv.0.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.0.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer5.1.conv.0.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.1.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.1.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.1.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.2.bn.mutable_num_features: + current_choice: 96 + origin_channels: 144 +backbone.layer5.1.conv.2.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.2.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer5.2.conv.0.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.0.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer5.2.conv.0.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.1.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.1.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.1.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.2.bn.mutable_num_features: + current_choice: 96 + origin_channels: 144 +backbone.layer5.2.conv.2.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.2.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer6.0.conv.0.bn.mutable_num_features: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.0.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer6.0.conv.0.conv.mutable_out_channels: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.1.bn.mutable_num_features: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.1.conv.mutable_in_channels: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.1.conv.mutable_out_channels: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.2.bn.mutable_num_features: + current_choice: 240 + origin_channels: 240 +backbone.layer6.0.conv.2.conv.mutable_in_channels: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.2.conv.mutable_out_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer6.1.conv.0.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.0.conv.mutable_in_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer6.1.conv.0.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.1.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.1.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.1.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.2.bn.mutable_num_features: + current_choice: 240 + origin_channels: 240 +backbone.layer6.1.conv.2.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.2.conv.mutable_out_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer6.2.conv.0.bn.mutable_num_features: + current_choice: 960 + origin_channels: 1440 +backbone.layer6.2.conv.0.conv.mutable_in_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer6.2.conv.0.conv.mutable_out_channels: + current_choice: 960 + origin_channels: 1440 +backbone.layer6.2.conv.1.bn.mutable_num_features: + current_choice: 960 + origin_channels: 1440 +backbone.layer6.2.conv.1.conv.mutable_in_channels: + current_choice: 960 + origin_channels: 1440 +backbone.layer6.2.conv.1.conv.mutable_out_channels: + current_choice: 960 + origin_channels: 1440 +backbone.layer6.2.conv.2.bn.mutable_num_features: + current_choice: 240 + origin_channels: 240 +backbone.layer6.2.conv.2.conv.mutable_in_channels: + current_choice: 960 + origin_channels: 1440 +backbone.layer6.2.conv.2.conv.mutable_out_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer7.0.conv.0.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.0.conv.mutable_in_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer7.0.conv.0.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.2.bn.mutable_num_features: + current_choice: 480 + origin_channels: 480 +backbone.layer7.0.conv.2.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.2.conv.mutable_out_channels: + current_choice: 480 + origin_channels: 480 +head.fc.mutable_in_features: + current_choice: 1920 + origin_channels: 1920 +head.fc.mutable_out_features: + current_choice: 1000 + origin_channels: 1000 diff --git a/cv/distiller/CWD/mmrazor/tests/data/MBV2_530M.yaml b/cv/distiller/CWD/mmrazor/tests/data/MBV2_530M.yaml new file mode 100755 index 000000000..19bf6fccf --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/MBV2_530M.yaml @@ -0,0 +1,474 @@ +backbone.conv1.bn.mutable_num_features: + current_choice: 32 + origin_channels: 48 +backbone.conv1.conv.mutable_in_channels: + current_choice: 3 + origin_channels: 3 +backbone.conv1.conv.mutable_out_channels: + current_choice: 32 + origin_channels: 48 +backbone.conv2.bn.mutable_num_features: + current_choice: 1920 + origin_channels: 1920 +backbone.conv2.conv.mutable_in_channels: + current_choice: 480 + origin_channels: 480 +backbone.conv2.conv.mutable_out_channels: + current_choice: 1920 + origin_channels: 1920 +backbone.layer1.0.conv.0.bn.mutable_num_features: + current_choice: 32 + origin_channels: 48 +backbone.layer1.0.conv.0.conv.mutable_in_channels: + current_choice: 32 + origin_channels: 48 +backbone.layer1.0.conv.0.conv.mutable_out_channels: + current_choice: 32 + origin_channels: 48 +backbone.layer1.0.conv.1.bn.mutable_num_features: + current_choice: 16 + origin_channels: 24 +backbone.layer1.0.conv.1.conv.mutable_in_channels: + current_choice: 32 + origin_channels: 48 +backbone.layer1.0.conv.1.conv.mutable_out_channels: + current_choice: 16 + origin_channels: 24 +backbone.layer2.0.conv.0.bn.mutable_num_features: + current_choice: 144 + origin_channels: 144 +backbone.layer2.0.conv.0.conv.mutable_in_channels: + current_choice: 16 + origin_channels: 24 +backbone.layer2.0.conv.0.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 144 +backbone.layer2.0.conv.1.bn.mutable_num_features: + current_choice: 144 + origin_channels: 144 +backbone.layer2.0.conv.1.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 144 +backbone.layer2.0.conv.1.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 144 +backbone.layer2.0.conv.2.bn.mutable_num_features: + current_choice: 24 + origin_channels: 40 +backbone.layer2.0.conv.2.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 144 +backbone.layer2.0.conv.2.conv.mutable_out_channels: + current_choice: 24 + origin_channels: 40 +backbone.layer2.1.conv.0.bn.mutable_num_features: + current_choice: 176 + origin_channels: 240 +backbone.layer2.1.conv.0.conv.mutable_in_channels: + current_choice: 24 + origin_channels: 40 +backbone.layer2.1.conv.0.conv.mutable_out_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer2.1.conv.1.bn.mutable_num_features: + current_choice: 176 + origin_channels: 240 +backbone.layer2.1.conv.1.conv.mutable_in_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer2.1.conv.1.conv.mutable_out_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer2.1.conv.2.bn.mutable_num_features: + current_choice: 24 + origin_channels: 40 +backbone.layer2.1.conv.2.conv.mutable_in_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer2.1.conv.2.conv.mutable_out_channels: + current_choice: 24 + origin_channels: 40 +backbone.layer3.0.conv.0.bn.mutable_num_features: + current_choice: 192 + origin_channels: 240 +backbone.layer3.0.conv.0.conv.mutable_in_channels: + current_choice: 24 + origin_channels: 40 +backbone.layer3.0.conv.0.conv.mutable_out_channels: + current_choice: 192 + origin_channels: 240 +backbone.layer3.0.conv.1.bn.mutable_num_features: + current_choice: 192 + origin_channels: 240 +backbone.layer3.0.conv.1.conv.mutable_in_channels: + current_choice: 192 + origin_channels: 240 +backbone.layer3.0.conv.1.conv.mutable_out_channels: + current_choice: 192 + origin_channels: 240 +backbone.layer3.0.conv.2.bn.mutable_num_features: + current_choice: 48 + origin_channels: 48 +backbone.layer3.0.conv.2.conv.mutable_in_channels: + current_choice: 192 + origin_channels: 240 +backbone.layer3.0.conv.2.conv.mutable_out_channels: + current_choice: 48 + origin_channels: 48 +backbone.layer3.1.conv.0.bn.mutable_num_features: + current_choice: 240 + origin_channels: 288 +backbone.layer3.1.conv.0.conv.mutable_in_channels: + current_choice: 48 + origin_channels: 48 +backbone.layer3.1.conv.0.conv.mutable_out_channels: + current_choice: 240 + origin_channels: 288 +backbone.layer3.1.conv.1.bn.mutable_num_features: + current_choice: 240 + origin_channels: 288 +backbone.layer3.1.conv.1.conv.mutable_in_channels: + current_choice: 240 + origin_channels: 288 +backbone.layer3.1.conv.1.conv.mutable_out_channels: + current_choice: 240 + origin_channels: 288 +backbone.layer3.1.conv.2.bn.mutable_num_features: + current_choice: 48 + origin_channels: 48 +backbone.layer3.1.conv.2.conv.mutable_in_channels: + current_choice: 240 + origin_channels: 288 +backbone.layer3.1.conv.2.conv.mutable_out_channels: + current_choice: 48 + origin_channels: 48 +backbone.layer3.2.conv.0.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.0.conv.mutable_in_channels: + current_choice: 48 + origin_channels: 48 +backbone.layer3.2.conv.0.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.2.bn.mutable_num_features: + current_choice: 48 + origin_channels: 48 +backbone.layer3.2.conv.2.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.2.conv.mutable_out_channels: + current_choice: 48 + origin_channels: 48 +backbone.layer4.0.conv.0.bn.mutable_num_features: + current_choice: 264 + origin_channels: 288 +backbone.layer4.0.conv.0.conv.mutable_in_channels: + current_choice: 48 + origin_channels: 48 +backbone.layer4.0.conv.0.conv.mutable_out_channels: + current_choice: 264 + origin_channels: 288 +backbone.layer4.0.conv.1.bn.mutable_num_features: + current_choice: 264 + origin_channels: 288 +backbone.layer4.0.conv.1.conv.mutable_in_channels: + current_choice: 264 + origin_channels: 288 +backbone.layer4.0.conv.1.conv.mutable_out_channels: + current_choice: 264 + origin_channels: 288 +backbone.layer4.0.conv.2.bn.mutable_num_features: + current_choice: 88 + origin_channels: 96 +backbone.layer4.0.conv.2.conv.mutable_in_channels: + current_choice: 264 + origin_channels: 288 +backbone.layer4.0.conv.2.conv.mutable_out_channels: + current_choice: 88 + origin_channels: 96 +backbone.layer4.1.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.0.conv.mutable_in_channels: + current_choice: 88 + origin_channels: 96 +backbone.layer4.1.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.2.bn.mutable_num_features: + current_choice: 88 + origin_channels: 96 +backbone.layer4.1.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.2.conv.mutable_out_channels: + current_choice: 88 + origin_channels: 96 +backbone.layer4.2.conv.0.bn.mutable_num_features: + current_choice: 336 + origin_channels: 576 +backbone.layer4.2.conv.0.conv.mutable_in_channels: + current_choice: 88 + origin_channels: 96 +backbone.layer4.2.conv.0.conv.mutable_out_channels: + current_choice: 336 + origin_channels: 576 +backbone.layer4.2.conv.1.bn.mutable_num_features: + current_choice: 336 + origin_channels: 576 +backbone.layer4.2.conv.1.conv.mutable_in_channels: + current_choice: 336 + origin_channels: 576 +backbone.layer4.2.conv.1.conv.mutable_out_channels: + current_choice: 336 + origin_channels: 576 +backbone.layer4.2.conv.2.bn.mutable_num_features: + current_choice: 88 + origin_channels: 96 +backbone.layer4.2.conv.2.conv.mutable_in_channels: + current_choice: 336 + origin_channels: 576 +backbone.layer4.2.conv.2.conv.mutable_out_channels: + current_choice: 88 + origin_channels: 96 +backbone.layer4.3.conv.0.bn.mutable_num_features: + current_choice: 432 + origin_channels: 576 +backbone.layer4.3.conv.0.conv.mutable_in_channels: + current_choice: 88 + origin_channels: 96 +backbone.layer4.3.conv.0.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 576 +backbone.layer4.3.conv.1.bn.mutable_num_features: + current_choice: 432 + origin_channels: 576 +backbone.layer4.3.conv.1.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 576 +backbone.layer4.3.conv.1.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 576 +backbone.layer4.3.conv.2.bn.mutable_num_features: + current_choice: 88 + origin_channels: 96 +backbone.layer4.3.conv.2.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 576 +backbone.layer4.3.conv.2.conv.mutable_out_channels: + current_choice: 88 + origin_channels: 96 +backbone.layer5.0.conv.0.bn.mutable_num_features: + current_choice: 576 + origin_channels: 576 +backbone.layer5.0.conv.0.conv.mutable_in_channels: + current_choice: 88 + origin_channels: 96 +backbone.layer5.0.conv.0.conv.mutable_out_channels: + current_choice: 576 + origin_channels: 576 +backbone.layer5.0.conv.1.bn.mutable_num_features: + current_choice: 576 + origin_channels: 576 +backbone.layer5.0.conv.1.conv.mutable_in_channels: + current_choice: 576 + origin_channels: 576 +backbone.layer5.0.conv.1.conv.mutable_out_channels: + current_choice: 576 + origin_channels: 576 +backbone.layer5.0.conv.2.bn.mutable_num_features: + current_choice: 144 + origin_channels: 144 +backbone.layer5.0.conv.2.conv.mutable_in_channels: + current_choice: 576 + origin_channels: 576 +backbone.layer5.0.conv.2.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 144 +backbone.layer5.1.conv.0.bn.mutable_num_features: + current_choice: 576 + origin_channels: 864 +backbone.layer5.1.conv.0.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 144 +backbone.layer5.1.conv.0.conv.mutable_out_channels: + current_choice: 576 + origin_channels: 864 +backbone.layer5.1.conv.1.bn.mutable_num_features: + current_choice: 576 + origin_channels: 864 +backbone.layer5.1.conv.1.conv.mutable_in_channels: + current_choice: 576 + origin_channels: 864 +backbone.layer5.1.conv.1.conv.mutable_out_channels: + current_choice: 576 + origin_channels: 864 +backbone.layer5.1.conv.2.bn.mutable_num_features: + current_choice: 144 + origin_channels: 144 +backbone.layer5.1.conv.2.conv.mutable_in_channels: + current_choice: 576 + origin_channels: 864 +backbone.layer5.1.conv.2.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 144 +backbone.layer5.2.conv.0.bn.mutable_num_features: + current_choice: 648 + origin_channels: 864 +backbone.layer5.2.conv.0.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 144 +backbone.layer5.2.conv.0.conv.mutable_out_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer5.2.conv.1.bn.mutable_num_features: + current_choice: 648 + origin_channels: 864 +backbone.layer5.2.conv.1.conv.mutable_in_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer5.2.conv.1.conv.mutable_out_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer5.2.conv.2.bn.mutable_num_features: + current_choice: 144 + origin_channels: 144 +backbone.layer5.2.conv.2.conv.mutable_in_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer5.2.conv.2.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 144 +backbone.layer6.0.conv.0.bn.mutable_num_features: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.0.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 144 +backbone.layer6.0.conv.0.conv.mutable_out_channels: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.1.bn.mutable_num_features: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.1.conv.mutable_in_channels: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.1.conv.mutable_out_channels: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.2.bn.mutable_num_features: + current_choice: 240 + origin_channels: 240 +backbone.layer6.0.conv.2.conv.mutable_in_channels: + current_choice: 864 + origin_channels: 864 +backbone.layer6.0.conv.2.conv.mutable_out_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer6.1.conv.0.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.0.conv.mutable_in_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer6.1.conv.0.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.1.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.1.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.1.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.2.bn.mutable_num_features: + current_choice: 240 + origin_channels: 240 +backbone.layer6.1.conv.2.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.1.conv.2.conv.mutable_out_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer6.2.conv.0.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.2.conv.0.conv.mutable_in_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer6.2.conv.0.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.2.conv.1.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.2.conv.1.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.2.conv.1.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.2.conv.2.bn.mutable_num_features: + current_choice: 240 + origin_channels: 240 +backbone.layer6.2.conv.2.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer6.2.conv.2.conv.mutable_out_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer7.0.conv.0.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.0.conv.mutable_in_channels: + current_choice: 240 + origin_channels: 240 +backbone.layer7.0.conv.0.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.2.bn.mutable_num_features: + current_choice: 480 + origin_channels: 480 +backbone.layer7.0.conv.2.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.2.conv.mutable_out_channels: + current_choice: 480 + origin_channels: 480 +head.fc.mutable_in_features: + current_choice: 1920 + origin_channels: 1920 +head.fc.mutable_out_features: + current_choice: 1000 + origin_channels: 1000 diff --git a/cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_channel_config.json b/cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_channel_config.json new file mode 100755 index 000000000..4b9e421f3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_channel_config.json @@ -0,0 +1,362 @@ +{ + "backbone.conv1.conv_(0, 48)_48": { + "init_args": { + "num_channels": 48, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 8, + 8, + 32 + ], + "choice_mode": "number" + }, + "choice": 32 + }, + "backbone.layer1.0.conv.1.conv_(0, 24)_24": { + "init_args": { + "num_channels": 24, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 8, + 8, + 16 + ], + "choice_mode": "number" + }, + "choice": 16 + }, + "backbone.layer2.0.conv.0.conv_(0, 144)_144": { + "init_args": { + "num_channels": 144, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 96, + 96, + 144 + ], + "choice_mode": "number" + }, + "choice": 144 + }, + "backbone.layer2.0.conv.2.conv_(0, 40)_40": { + "init_args": { + "num_channels": 40, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 16, + 16, + 24 + ], + "choice_mode": "number" + }, + "choice": 24 + }, + "backbone.layer2.1.conv.0.conv_(0, 240)_240": { + "init_args": { + "num_channels": 240, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 96, + 96, + 176 + ], + "choice_mode": "number" + }, + "choice": 176 + }, + "backbone.layer3.0.conv.0.conv_(0, 240)_240": { + "init_args": { + "num_channels": 240, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 96, + 96, + 192 + ], + "choice_mode": "number" + }, + "choice": 192 + }, + "backbone.layer3.0.conv.2.conv_(0, 48)_48": { + "init_args": { + "num_channels": 48, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 24, + 24, + 48 + ], + "choice_mode": "number" + }, + "choice": 48 + }, + "backbone.layer3.1.conv.0.conv_(0, 288)_288": { + "init_args": { + "num_channels": 288, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 144, + 144, + 240 + ], + "choice_mode": "number" + }, + "choice": 240 + }, + "backbone.layer3.2.conv.0.conv_(0, 288)_288": { + "init_args": { + "num_channels": 288, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 144, + 144, + 144 + ], + "choice_mode": "number" + }, + "choice": 144 + }, + "backbone.layer4.0.conv.0.conv_(0, 288)_288": { + "init_args": { + "num_channels": 288, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 144, + 144, + 264 + ], + "choice_mode": "number" + }, + "choice": 264 + }, + "backbone.layer4.0.conv.2.conv_(0, 96)_96": { + "init_args": { + "num_channels": 96, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 48, + 56, + 88 + ], + "choice_mode": "number" + }, + "choice": 88 + }, + "backbone.layer4.1.conv.0.conv_(0, 576)_576": { + "init_args": { + "num_channels": 576, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 288, + 288, + 288 + ], + "choice_mode": "number" + }, + "choice": 288 + }, + "backbone.layer4.2.conv.0.conv_(0, 576)_576": { + "init_args": { + "num_channels": 576, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 288, + 288, + 336 + ], + "choice_mode": "number" + }, + "choice": 336 + }, + "backbone.layer4.3.conv.0.conv_(0, 576)_576": { + "init_args": { + "num_channels": 576, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 288, + 288, + 432 + ], + "choice_mode": "number" + }, + "choice": 432 + }, + "backbone.layer5.0.conv.0.conv_(0, 576)_576": { + "init_args": { + "num_channels": 576, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 288, + 288, + 576 + ], + "choice_mode": "number" + }, + "choice": 576 + }, + "backbone.layer5.0.conv.2.conv_(0, 144)_144": { + "init_args": { + "num_channels": 144, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 64, + 96, + 144 + ], + "choice_mode": "number" + }, + "choice": 144 + }, + "backbone.layer5.1.conv.0.conv_(0, 864)_864": { + "init_args": { + "num_channels": 864, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 432, + 432, + 576 + ], + "choice_mode": "number" + }, + "choice": 576 + }, + "backbone.layer5.2.conv.0.conv_(0, 864)_864": { + "init_args": { + "num_channels": 864, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 432, + 432, + 648 + ], + "choice_mode": "number" + }, + "choice": 648 + }, + "backbone.layer6.0.conv.0.conv_(0, 864)_864": { + "init_args": { + "num_channels": 864, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 648, + 864, + 864 + ], + "choice_mode": "number" + }, + "choice": 864 + }, + "backbone.layer6.0.conv.2.conv_(0, 240)_240": { + "init_args": { + "num_channels": 240, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 176, + 240, + 240 + ], + "choice_mode": "number" + }, + "choice": 240 + }, + "backbone.layer6.1.conv.0.conv_(0, 1440)_1440": { + "init_args": { + "num_channels": 1440, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 720, + 1440, + 1440 + ], + "choice_mode": "number" + }, + "choice": 1440 + }, + "backbone.layer6.2.conv.0.conv_(0, 1440)_1440": { + "init_args": { + "num_channels": 1440, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 720, + 960, + 1440 + ], + "choice_mode": "number" + }, + "choice": 1440 + }, + "backbone.layer7.0.conv.0.conv_(0, 1440)_1440": { + "init_args": { + "num_channels": 1440, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 1440, + 1440, + 1440 + ], + "choice_mode": "number" + }, + "choice": 1440 + }, + "backbone.layer7.0.conv.2.conv_(0, 480)_480": { + "init_args": { + "num_channels": 480, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 280, + 480, + 480 + ], + "choice_mode": "number" + }, + "choice": 480 + } +} \ No newline at end of file diff --git a/cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_config.json b/cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_config.json new file mode 100755 index 000000000..9010b83e2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/MBV2_slimmable_config.json @@ -0,0 +1,377 @@ +{ + "backbone.conv1.conv_(0, 48)_48": { + "init_args": { + "num_channels": 48, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 8, + 8, + 32 + ], + "choice_mode": "number" + }, + "choice": 32 + }, + "backbone.layer1.0.conv.1.conv_(0, 24)_24": { + "init_args": { + "num_channels": 24, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 8, + 8, + 16 + ], + "choice_mode": "number" + }, + "choice": 16 + }, + "backbone.layer2.0.conv.0.conv_(0, 144)_144": { + "init_args": { + "num_channels": 144, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 96, + 96, + 144 + ], + "choice_mode": "number" + }, + "choice": 144 + }, + "backbone.layer2.0.conv.2.conv_(0, 40)_40": { + "init_args": { + "num_channels": 40, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 16, + 16, + 24 + ], + "choice_mode": "number" + }, + "choice": 24 + }, + "backbone.layer2.1.conv.0.conv_(0, 240)_240": { + "init_args": { + "num_channels": 240, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 96, + 96, + 176 + ], + "choice_mode": "number" + }, + "choice": 176 + }, + "backbone.layer3.0.conv.0.conv_(0, 240)_240": { + "init_args": { + "num_channels": 240, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 96, + 96, + 192 + ], + "choice_mode": "number" + }, + "choice": 192 + }, + "backbone.layer3.0.conv.2.conv_(0, 48)_48": { + "init_args": { + "num_channels": 48, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 24, + 24, + 48 + ], + "choice_mode": "number" + }, + "choice": 48 + }, + "backbone.layer3.1.conv.0.conv_(0, 288)_288": { + "init_args": { + "num_channels": 288, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 144, + 144, + 240 + ], + "choice_mode": "number" + }, + "choice": 240 + }, + "backbone.layer3.2.conv.0.conv_(0, 288)_288": { + "init_args": { + "num_channels": 288, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 144, + 144, + 144 + ], + "choice_mode": "number" + }, + "choice": 144 + }, + "backbone.layer4.0.conv.0.conv_(0, 288)_288": { + "init_args": { + "num_channels": 288, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 144, + 144, + 264 + ], + "choice_mode": "number" + }, + "choice": 264 + }, + "backbone.layer4.0.conv.2.conv_(0, 96)_96": { + "init_args": { + "num_channels": 96, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 48, + 56, + 88 + ], + "choice_mode": "number" + }, + "choice": 88 + }, + "backbone.layer4.1.conv.0.conv_(0, 576)_576": { + "init_args": { + "num_channels": 576, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 288, + 288, + 288 + ], + "choice_mode": "number" + }, + "choice": 288 + }, + "backbone.layer4.2.conv.0.conv_(0, 576)_576": { + "init_args": { + "num_channels": 576, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 288, + 288, + 336 + ], + "choice_mode": "number" + }, + "choice": 336 + }, + "backbone.layer4.3.conv.0.conv_(0, 576)_576": { + "init_args": { + "num_channels": 576, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 288, + 288, + 432 + ], + "choice_mode": "number" + }, + "choice": 432 + }, + "backbone.layer5.0.conv.0.conv_(0, 576)_576": { + "init_args": { + "num_channels": 576, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 288, + 288, + 576 + ], + "choice_mode": "number" + }, + "choice": 576 + }, + "backbone.layer5.0.conv.2.conv_(0, 144)_144": { + "init_args": { + "num_channels": 144, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 64, + 96, + 144 + ], + "choice_mode": "number" + }, + "choice": 144 + }, + "backbone.layer5.1.conv.0.conv_(0, 864)_864": { + "init_args": { + "num_channels": 864, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 432, + 432, + 576 + ], + "choice_mode": "number" + }, + "choice": 576 + }, + "backbone.layer5.2.conv.0.conv_(0, 864)_864": { + "init_args": { + "num_channels": 864, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 432, + 432, + 648 + ], + "choice_mode": "number" + }, + "choice": 648 + }, + "backbone.layer6.0.conv.0.conv_(0, 864)_864": { + "init_args": { + "num_channels": 864, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 648, + 864, + 864 + ], + "choice_mode": "number" + }, + "choice": 864 + }, + "backbone.layer6.0.conv.2.conv_(0, 240)_240": { + "init_args": { + "num_channels": 240, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 176, + 240, + 240 + ], + "choice_mode": "number" + }, + "choice": 240 + }, + "backbone.layer6.1.conv.0.conv_(0, 1440)_1440": { + "init_args": { + "num_channels": 1440, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 720, + 1440, + 1440 + ], + "choice_mode": "number" + }, + "choice": 1440 + }, + "backbone.layer6.2.conv.0.conv_(0, 1440)_1440": { + "init_args": { + "num_channels": 1440, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 720, + 960, + 1440 + ], + "choice_mode": "number" + }, + "choice": 1440 + }, + "backbone.layer7.0.conv.0.conv_(0, 1440)_1440": { + "init_args": { + "num_channels": 1440, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 1440, + 1440, + 1440 + ], + "choice_mode": "number" + }, + "choice": 1440 + }, + "backbone.layer7.0.conv.2.conv_(0, 480)_480": { + "init_args": { + "num_channels": 480, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 280, + 480, + 480 + ], + "choice_mode": "number" + }, + "choice": 480 + }, + "backbone.conv2.conv_(0, 1920)_1920": { + "init_args": { + "num_channels": 1920, + "divisor": 1, + "min_value": 1, + "min_ratio": 0.9, + "candidate_choices": [ + 1920, + 1920, + 1920 + ], + "choice_mode": "number" + }, + "choice": 1920 + } +} \ No newline at end of file diff --git a/cv/distiller/CWD/mmrazor/tests/data/__init__.py b/cv/distiller/CWD/mmrazor/tests/data/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/data/color.jpeg b/cv/distiller/CWD/mmrazor/tests/data/color.jpeg new file mode 100755 index 0000000000000000000000000000000000000000..2f19ebc6c6e867372f61dceadba4d66de46e31ab GIT binary patch literal 39779 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%0AA>LtYn8_PSiCL!FyNsStAlJ=5 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 LDJue#wx|Eu-QcpD literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmrazor/tests/data/concat_subnet1.yaml b/cv/distiller/CWD/mmrazor/tests/data/concat_subnet1.yaml new file mode 100755 index 000000000..c15cab25f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/concat_subnet1.yaml @@ -0,0 +1,24 @@ +op1.mutable_in_channels: + current_choice: 3 + origin_channels: 3 +op1.mutable_out_channels: + current_choice: 4 + origin_channels: 8 +bn1.mutable_num_features: + current_choice: 4 + origin_channels: 8 +op2.mutable_in_channels: + current_choice: 3 + origin_channels: 3 +op2.mutable_out_channels: + current_choice: 4 + origin_channels: 8 +bn2.mutable_num_features: + current_choice: 4 + origin_channels: 8 +op3.mutable_in_channels: + current_choice: 8 + origin_channels: 16 +op3.mutable_out_channels: + current_choice: 8 + origin_channels: 8 \ No newline at end of file diff --git a/cv/distiller/CWD/mmrazor/tests/data/concat_subnet2.yaml b/cv/distiller/CWD/mmrazor/tests/data/concat_subnet2.yaml new file mode 100755 index 000000000..f2c6e7ab2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/concat_subnet2.yaml @@ -0,0 +1,24 @@ +op1.mutable_in_channels: + current_choice: 3 + origin_channels: 3 +op1.mutable_out_channels: + current_choice: 8 + origin_channels: 8 +bn1.mutable_num_features: + current_choice: 8 + origin_channels: 8 +op2.mutable_in_channels: + current_choice: 3 + origin_channels: 3 +op2.mutable_out_channels: + current_choice: 8 + origin_channels: 8 +bn2.mutable_num_features: + current_choice: 8 + origin_channels: 8 +op3.mutable_in_channels: + current_choice: 16 + origin_channels: 16 +op3.mutable_out_channels: + current_choice: 8 + origin_channels: 8 \ No newline at end of file diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/a/1.JPG b/cv/distiller/CWD/mmrazor/tests/data/dataset/a/1.JPG new file mode 100755 index 000000000..e69de29bb diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/ann.json b/cv/distiller/CWD/mmrazor/tests/data/dataset/ann.json new file mode 100755 index 000000000..a55539329 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/dataset/ann.json @@ -0,0 +1,28 @@ +{ + "metainfo": { + "categories": [ + { + "category_name": "first", + "id": 0 + }, + { + "category_name": "second", + "id": 1 + } + ] + }, + "data_list": [ + { + "img_path": "a/1.JPG", + "gt_label": 0 + }, + { + "img_path": "b/2.jpeg", + "gt_label": 1 + }, + { + "img_path": "b/subb/2.jpeg", + "gt_label": 1 + } + ] +} diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/ann.txt b/cv/distiller/CWD/mmrazor/tests/data/dataset/ann.txt new file mode 100755 index 000000000..f929e873b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/dataset/ann.txt @@ -0,0 +1,3 @@ +a/1.JPG 0 +b/2.jpeg 1 +b/subb/3.jpg 1 diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/b/2.jpeg b/cv/distiller/CWD/mmrazor/tests/data/dataset/b/2.jpeg new file mode 100755 index 000000000..e69de29bb diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/b/subb/3.jpg b/cv/distiller/CWD/mmrazor/tests/data/dataset/b/subb/3.jpg new file mode 100755 index 000000000..e69de29bb diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/classes.txt b/cv/distiller/CWD/mmrazor/tests/data/dataset/classes.txt new file mode 100755 index 000000000..c012a51e6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/dataset/classes.txt @@ -0,0 +1,2 @@ +bus +car diff --git a/cv/distiller/CWD/mmrazor/tests/data/dataset/multi_label_ann.json b/cv/distiller/CWD/mmrazor/tests/data/dataset/multi_label_ann.json new file mode 100755 index 000000000..5cd8a84d0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/dataset/multi_label_ann.json @@ -0,0 +1,28 @@ +{ + "metainfo": { + "categories": [ + { + "category_name": "first", + "id": 0 + }, + { + "category_name": "second", + "id": 1 + } + ] + }, + "data_list": [ + { + "img_path": "a/1.JPG", + "gt_label": [0] + }, + { + "img_path": "b/2.jpeg", + "gt_label": [1] + }, + { + "img_path": "b/subb/2.jpeg", + "gt_label": [0, 1] + } + ] +} diff --git a/cv/distiller/CWD/mmrazor/tests/data/model_library.py b/cv/distiller/CWD/mmrazor/tests/data/model_library.py new file mode 100755 index 000000000..d917dcc30 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/model_library.py @@ -0,0 +1,693 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import List +from typing import Dict, Callable +from mmrazor.registry import MODELS +from mmengine.config import Config +import os +from mmengine.utils import get_installed_path +from mmrazor.registry import MODELS +import torch +import torch.nn as nn +from .models import (AddCatModel, ConcatModel, ConvAttnModel, DwConvModel, + ExpandLineModel, GroupWiseConvModel, SingleLineModel, + MultiBindModel, MultiConcatModel, MultiConcatModel2, + ResBlock, Xmodel, MultipleUseModel, Icep, SelfAttention) +import json +# model generator +from mmdet.testing._utils import demo_mm_inputs +import string +import copy +# helper functions + + +def get_shape(tensor, only_length=False): + if isinstance(tensor, torch.Tensor): + if only_length: + return len(tensor.shape) + else: + return tensor.shape + elif isinstance(tensor, list) or isinstance(tensor, tuple): + shapes = [] + for x in tensor: + shapes.append(get_shape(x, only_length)) + return shapes + elif isinstance(tensor, dict): + shapes = {} + for key in tensor: + shapes[key] = get_shape(tensor[key], only_length) + return shapes + else: + raise NotImplementedError( + f'unsuppored type{type(tensor)} to get shape of tensors.') + + +# generators + + +class ModelGenerator(nn.Module): + + def __init__(self, name: str, model_src) -> None: + super().__init__() + self.name = name + self.model_src = model_src + self._model = None + + def __call__(self, *args, **kwargs): + return self.init_model() + + def init_model(self): + return self.model_src() + + def forward(self, x): + assert self._model is not None + return self._model(x, *self.input()) + + def input(self): + return [] + + def assert_model_is_changed(self, tensors_org, tensors_new): + shape1 = get_shape(tensors_org) + shape2 = get_shape(tensors_new) + assert shape1 == shape2, f'{shape1}!={shape2}' + + def __repr__(self) -> str: + return self.name + + @classmethod + def get_base_name(cls, name: str): + names = name.split('.') + return '.'.join(names[1:]) + + @classmethod + def get_short_name(cls, name: str): + scope = name.split('.')[0] + base_name = cls.get_base_name(name) + names = base_name.replace('-', '.').replace('_', '.').split('.') + name = names[0] + name = name.rstrip(string.digits) + + return f'{scope}.{name}' + + @property + def base_name(self): + return self.__class__.get_base_name(self.name) + + @property + def short_name(self): + return self.__class__.get_short_name(self.name) + + @property + def scope(self): + return self.name.split('.')[0] + + +class MMModelGenerator(ModelGenerator): + + def __init__(self, name, cfg) -> None: + self.cfg = cfg + super().__init__(name, self.get_model_src) + + def get_model_src(self): + model = MODELS.build(self.cfg) + model = revert_sync_batchnorm(model) + return model + + def __repr__(self) -> str: + return self.name + + +class MMDetModelGenerator(MMModelGenerator): + + def forward(self, x): + assert self._model is not None + self._model.eval() + return self._model(x, **self.input(), mode='tensor') + + def input(self): + data = demo_mm_inputs(1, [[3, 224, 224]]) + data = self._model.data_preprocessor(data, False) + data.pop('inputs') + return data + + def assert_model_is_changed(self, tensors_org, tensors_new): + assert get_shape(tensors_org, True) == get_shape(tensors_new, True) + + +# model library + + +class ModelLibrary: + default_includes: List = [] + _models = None + + def __init__(self, include=default_includes, exclude=[]) -> None: + self.include_key = include + self.exclude_key = exclude + self._include_models, self._uninclude_models, self.exclude_models =\ + self._classify_models(self.models) + + @property + def models(self): + if self.__class__._models is None: + self.__class__._models: Dict[ + str, Callable] = self.__class__.get_models() + return self.__class__._models + + @classmethod + def get_models(cls): + raise NotImplementedError() + + def include_models(self): + return self._include_models + + def uninclude_models(self): + return self._uninclude_models + + def is_include(self, name: str, includes: List[str], start_with=True): + for key in includes: + if start_with: + if name.startswith(key): + return True + else: + if key in name: + return True + return False + + def is_default_includes_cover_all_models(self): + models = copy.copy(self._models) + is_covered = True + for name in models: + if self.is_include(name, self.__class__.default_includes): + pass + else: + is_covered = False + print(name, '\tnot include') + return is_covered + + def short_names(self): + short_names = set() + for name in self.models: + short_names.add(self.models[name].short_name) + return short_names + + def _classify_models(self, models: Dict): + include = [] + uninclude = [] + exclude = [] + for name in models: + if self.is_include(name, self.exclude_key, start_with=False): + exclude.append(models[name]) + elif self.is_include(name, self.include_key, start_with=True): + include.append(models[name]) + else: + uninclude.append(models[name]) + return include, uninclude, exclude + + def get_short_name_of_model(self, name: str): + names = name.replace('-', '.').replace('_', '.').split('.') + return names[0] + + +class DefaultModelLibrary(ModelLibrary): + _mm_models = None + + default_includes: List = [ + 'SingleLineModel', + 'ResBlock', + 'AddCatModel', + 'ConcatModel', + 'MultiConcatModel', + 'MultiConcatModel2', + 'GroupWiseConvModel', + 'Xmodel', + 'MultipleUseModel', + 'Icep', + 'ExpandLineModel', + 'MultiBindModel', + 'DwConvModel', + 'ConvAttnModel', + 'SelfAttention', + # mm models + 'resnet', + 'pspnet', + 'yolo' + ] + + def __init__(self, + include=default_includes, + exclude=[], + with_mm_models=False) -> None: + self.with_mm_models = with_mm_models + super().__init__(include, exclude) + + @property + def models(self): + models = copy.copy(super().models) + if self.with_mm_models: + models.update(self.mm_models) + return models + + @property + def mm_models(self): + if self.__class__._mm_models is None: + self.__class__._mm_models = self.get_mm_models() + return self.__class__._mm_models + + @classmethod + def get_models(cls): + models = [ + SingleLineModel, + ResBlock, + AddCatModel, + ConcatModel, + MultiConcatModel, + MultiConcatModel2, + GroupWiseConvModel, + Xmodel, + MultipleUseModel, + Icep, + ExpandLineModel, + MultiBindModel, + DwConvModel, # + ConvAttnModel, + SelfAttention, + ] + model_dict = {} + for model in models: + model_dict[model.__name__] = ModelGenerator( + 'default.' + model.__name__, model) + return model_dict + + @classmethod + def get_mm_models(cls): + paths = [ + 'mmcls::resnet/resnet34_8xb32_in1k.py', + 'mmseg::pspnet/pspnet_r18-d8_4xb4-80k_potsdam-512x512.py', + 'mmdet::yolo/yolov3_d53_8xb8-320-273e_coco.py' + ] + models = {} + for path in paths: + Model = MMModelLibrary.get_model_from_path(path) + models[Model.base_name] = Model + return models + + +class TorchModelLibrary(ModelLibrary): + + default_includes = [ + 'alexnet', 'densenet', 'efficientnet', 'googlenet', 'inception', + 'mnasnet', 'mobilenet', 'regnet', 'resnet', 'resnext', 'shufflenet', + 'squeezenet', 'vgg', 'wide_resnet', "vit", "swin", "convnext" + ] + + def __init__(self, include=default_includes, exclude=[]) -> None: + super().__init__(include, exclude) + + @classmethod + def get_models(cls): + from inspect import isfunction + + import torchvision + + attrs = dir(torchvision.models) + models = {} + for name in attrs: + module = getattr(torchvision.models, name) + if isfunction(module) and name is not 'get_weight': + models[name] = ModelGenerator('torch.' + name, module) + return models + + +class MMModelLibrary(ModelLibrary): + default_includes = [] + base_config_path = '/' + repo = 'mmxx' + + def __init__(self, include=default_includes, exclude=[]) -> None: + super().__init__(include, exclude) + + @classmethod + def scope_path(cls): + path = cls._scope_path(cls.repo) + cls.base_config_path + return path + + @classmethod + def get_models(cls): + models = {} + added_models = set() + for dirpath, dirnames, filenames in os.walk(cls.scope_path()): + for filename in filenames: + if filename.endswith('.py'): + + cfg_path = dirpath + '/' + filename + try: + config = Config.fromfile(cfg_path) + except: + continue + if 'model' in config: + + # get model_name + model_name = cls.get_model_name_from_path( + cfg_path, cls.scope_path()) + + model_cfg = config['model'] + model_cfg = cls._config_process(model_cfg) + if json.dumps(model_cfg) not in added_models: + models[model_name] = cls.generator_type()( + cls.repo + '.' + model_name, model_cfg) + added_models.add(json.dumps(model_cfg)) + return models + + @classmethod + def generator_type(cls): + return MMModelGenerator + + @classmethod + def get_model_name_from_path(cls, config_path, scope_path): + import os + dirpath = os.path.dirname(config_path) + '/' + filename = os.path.basename(config_path) + + model_type_name = '_'.join(dirpath.replace(scope_path, '').split('/')) + model_type_name = model_type_name if model_type_name == '' else model_type_name + '_' + model_name = model_type_name + \ + os.path.basename(filename).split('.')[0] + return model_name + + @classmethod + def get_model_from_path(cls, config_path): + path, scope = Config._get_cfg_path(config_path, '') + if scope is None: + scope = 'mmrazor' + config = Config.fromfile(path)['model'] + config = cls._config_process(config=config) + config['_scope_'] = scope + name = cls.get_model_name_from_path(path, cls._scope_path(scope)) + return cls.generator_type()(scope + '.' + name, config) + + @staticmethod + def _scope_path(scope): + if scope == 'mmseg': + scope = 'mmsegmentation' + repo_path = get_installed_path(scope) + path = repo_path + '/.mim/configs/' + return path + + @classmethod + def _config_process(cls, config: Dict): + config['_scope_'] = cls.repo + config = cls._remove_certain_key(config, 'init_cfg') + config = cls._remove_certain_key(config, 'pretrained') + config = cls._remove_certain_key(config, 'Pretrained') + return config + + @classmethod + def _remove_certain_key(cls, config: Dict, key: str = 'init_cfg'): + if isinstance(config, dict): + if key in config: + config.pop(key) + for keyx in config: + config[keyx] = cls._remove_certain_key(config[keyx], key) + return config + + +class MMClsModelLibrary(MMModelLibrary): + + default_includes = [ + 'vgg', + 'efficientnet', + 'resnet', + 'mobilenet', + 'resnext', + 'wide-resnet', + 'shufflenet', + 'hrnet', + 'resnest', + 'inception', + 'res2net', + 'densenet', + 'convnext', + 'regnet', + 'van', + 'swin_transformer', + 'convmixer', + 't2t', + 'twins', + 'repmlp', + 'tnt', + 't2t', + 'mlp_mixer', + 'conformer', + 'poolformer', + 'vit', + 'efficientformer', + 'mobileone', + 'edgenext', + 'mvit', + 'seresnet', + 'repvgg', + 'seresnext', + 'deit', + 'replknet', + 'hornet', + 'mobilevit', + 'davit', + ] + base_config_path = '_base_/models/' + repo = 'mmcls' + + def __init__( + self, + include=default_includes, + exclude=['cutmix', 'cifar', 'gem', 'efficientformer']) -> None: + super().__init__(include=include, exclude=exclude) + + +class MMDetModelLibrary(MMModelLibrary): + + default_includes = [ + '_base', + 'gfl', + 'sparse', + 'simple', + 'pisa', + 'lvis', + 'carafe', + 'selfsup', + 'solo', + 'ssd', + 'res2net', + 'yolof', + 'reppoints', + 'htc', + 'groie', + 'dyhead', + 'grid', + 'soft', + 'swin', + 'regnet', + 'gcnet', + 'ddod', + 'instaboost', + 'point', + 'vfnet', + 'pafpn', + 'ghm', + 'mask', + 'resnest', + 'tood', + 'detectors', + 'cornernet', + 'convnext', + 'cascade', + 'paa', + 'detr', + 'rpn', + 'ld', + 'lad', + 'ms', + 'faster', + 'centripetalnet', + 'gn', + 'dcnv2', + 'legacy', + 'panoptic', + 'strong', + 'fpg', + 'deformable', + 'free', + 'scratch', + 'openimages', + 'fsaf', + 'rtmdet', + 'solov2', + 'yolact', + 'empirical', + 'centernet', + 'hrnet', + 'guided', + 'deepfashion', + 'fast', + 'mask2former', + 'retinanet', + 'autoassign', + 'gn+ws', + 'dcn', + 'yolo', + 'foveabox', + 'libra', + 'double', + 'queryinst', + 'resnet', + 'nas', + 'sabl', + 'fcos', + 'scnet', + 'maskformer', + 'pascal', + 'cityscapes', + 'timm', + 'seesaw', + 'pvt', + 'atss', + 'efficientnet', + 'wider', + 'tridentnet', + 'dynamic', + 'yolox', + 'albu', + 'misc', + 'crowddet', + 'condins', + ] + base_config_path = '/' + repo = 'mmdet' + + def __init__( + self, + include=default_includes, + exclude=[ + 'lad', + 'ld', + 'faster_rcnn_faster-rcnn_r50-caffe-c4_ms-1x_coco', + ] + ) -> None: + super().__init__(include=include, exclude=exclude) + + @classmethod + def _config_process(cls, config: Dict): + config = super()._config_process(config) + if 'preprocess_cfg' in config: + config.pop('preprocess_cfg') + return config + + @classmethod + def generator_type(cls): + return MMModelGenerator + + +class MMSegModelLibrary(MMModelLibrary): + default_includes: List = [ + '_base_', + 'knet', + 'sem', + 'dnlnet', + 'dmnet', + 'icnet', + 'apcnet', + 'swin', + 'isanet', + 'fastfcn', + 'poolformer', + 'mae', + 'segformer', + 'ccnet', + 'twins', + 'emanet', + 'upernet', + 'beit', + 'hrnet', + 'bisenetv2', + 'vit', + 'setr', + 'cgnet', + 'ocrnet', + 'ann', + 'erfnet', + 'point', + 'bisenetv1', + 'nonlocal', + 'unet', + 'danet', + 'stdc', + 'fcn', + 'encnet', + 'resnest', + 'mobilenet', + 'convnext', + 'deeplabv3', + 'pspnet', + 'gcnet', + 'fastscnn', + 'segmenter', + 'dpt', + 'deeplabv3plus', + 'psanet', + ] + base_config_path = '/' + repo = 'mmsegmentation' + + def __init__(self, include=default_includes, exclude=['_base_']) -> None: + super().__init__(include, exclude) + + @classmethod + def _config_process(cls, config: Dict): + config['_scope_'] = 'mmseg' + return config + + +class MMPoseModelLibrary(MMModelLibrary): + default_includes: List = [ + 'hand', + 'face', + 'wholebody', + 'body', + 'animal', + ] + base_config_path = '/' + repo = 'mmpose' + + def __init__(self, include=default_includes, exclude=[]) -> None: + super().__init__(include, exclude=exclude) + + @classmethod + def _config_process(cls, config: Dict): + config['_scope_'] = 'mmpose' + return config + + +# tools + +def revert_sync_batchnorm(module): + # this is very similar to the function that it is trying to revert: + # https://github.com/pytorch/pytorch/blob/c8b3686a3e4ba63dc59e5dcfe5db3430df256833/torch/nn/modules/batchnorm.py#L679 + module_output = module + if isinstance(module, torch.nn.modules.batchnorm.SyncBatchNorm): + new_cls = nn.BatchNorm2d + module_output = nn.BatchNorm2d(module.num_features, module.eps, + module.momentum, module.affine, + module.track_running_stats) + if module.affine: + with torch.no_grad(): + module_output.weight = module.weight + module_output.bias = module.bias + module_output.running_mean = module.running_mean + module_output.running_var = module.running_var + module_output.num_batches_tracked = module.num_batches_tracked + if hasattr(module, "qconfig"): + module_output.qconfig = module.qconfig + for name, child in module.named_children(): + module_output.add_module(name, revert_sync_batchnorm(child)) + del module + return module_output diff --git a/cv/distiller/CWD/mmrazor/tests/data/models.py b/cv/distiller/CWD/mmrazor/tests/data/models.py new file mode 100755 index 000000000..0347b9147 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/models.py @@ -0,0 +1,1073 @@ +# Copyright (c) OpenMMLab. All rights reserved. +# this file includes models for tesing. +from collections import OrderedDict +from typing import Dict +import math + +from torch.nn import Module +from torch import Tensor +import torch.nn as nn +import torch.nn.functional as F +import torch +from mmengine.model import BaseModel +from mmrazor.models.architectures.dynamic_ops import DynamicBatchNorm2d, DynamicConv2d, DynamicLinear, DynamicChannelMixin, DynamicPatchEmbed, DynamicSequential +from mmrazor.models.mutables.mutable_channel import MutableChannelContainer +from mmrazor.models.mutables import MutableChannelUnit +from mmrazor.models.mutables import DerivedMutable +from mmrazor.models.mutables import BaseMutable +from mmrazor.models.mutables import OneShotMutableChannelUnit, OneShotMutableChannel + +from mmrazor.models.mutables import OneShotMutableValue +from mmrazor.models.architectures.backbones.searchable_autoformer import TransformerEncoderLayer +from mmrazor.registry import MODELS +from mmrazor.models.mutables import OneShotMutableValue +from mmrazor.models.architectures.backbones.searchable_autoformer import TransformerEncoderLayer +from mmrazor.models.utils.parse_values import parse_values + +from mmrazor.models.architectures.ops.mobilenet_series import MBBlock +from mmcv.cnn import ConvModule +from mmengine.model import Sequential +from mmrazor.models.architectures.utils.mutable_register import ( + mutate_conv_module, mutate_mobilenet_layer) + +# models to test fx tracer + + +def untracable_function(x: torch.Tensor): + if x.sum() > 0: + x = x - 1 + else: + x = x + 1 + return x + + +class UntracableModule(nn.Module): + + def __init__(self, in_channel, out_channel) -> None: + super().__init__() + self.conv = nn.Conv2d(in_channel, out_channel, 3, 1, 1) + self.conv2 = nn.Conv2d(out_channel, out_channel, 3, 1, 1) + + def forward(self, x: torch.Tensor): + x = self.conv(x) + if x.sum() > 0: + x = x * 2 + else: + x = x * -2 + x = self.conv2(x) + return x + + +class ModuleWithUntracableMethod(nn.Module): + + def __init__(self, in_channel, out_channel) -> None: + super().__init__() + self.conv = nn.Conv2d(in_channel, out_channel, 3, 1, 1) + self.conv2 = nn.Conv2d(out_channel, out_channel, 3, 1, 1) + + def forward(self, x: torch.Tensor): + x = self.conv(x) + x = self.untracable_method(x) + x = self.conv2(x) + return x + + def untracable_method(self, x): + if x.sum() > 0: + x = x * 2 + else: + x = x * -2 + return x + +@MODELS.register_module() +class UntracableBackBone(nn.Module): + + def __init__(self) -> None: + super().__init__() + self.conv = nn.Conv2d(3, 16, 3, 2) + self.untracable_module = UntracableModule(16, 8) + self.module_with_untracable_method = ModuleWithUntracableMethod(8, 16) + + def forward(self, x): + x = self.conv(x) + x = untracable_function(x) + x = self.untracable_module(x) + x = self.module_with_untracable_method(x) + return x + + +class UntracableModel(nn.Module): + + def __init__(self) -> None: + super().__init__() + self.backbone = UntracableBackBone() + self.head = LinearHeadForTest(16, 1000) + + def forward(self, x): + return self.head(self.backbone(x)) + + +class ConvAttnModel(Module): + + def __init__(self) -> None: + super().__init__() + self.conv = nn.Conv2d(3, 8, 3, 1, 1) + self.pool = nn.AdaptiveAvgPool2d(1) + self.conv2 = nn.Conv2d(8, 16, 3, 1, 1) + self.head = LinearHeadForTest(16, 1000) + + def forward(self, x): + x1 = self.conv(x) + attn = F.sigmoid(self.pool(x1)) + x_attn = x1 * attn + x_last = self.conv2(x_attn) + return self.head(x_last) + +@MODELS.register_module() +class LinearHeadForTest(Module): + + def __init__(self, in_channel, num_class=1000) -> None: + super().__init__() + self.pool = nn.AdaptiveAvgPool2d(1) + self.linear = nn.Linear(in_channel, num_class) + + def forward(self, x): + pool = self.pool(x).flatten(1) + return self.linear(pool) + + +class MultiConcatModel(Module): + """ + x---------------- + |op1 |op2 |op4 + x1 x2 x4 + | | | + |cat----- | + cat1 | + |op3 | + x3 | + |cat------------- + cat2 + |avg_pool + x_pool + |fc + output + """ + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.op2 = nn.Conv2d(3, 8, 1) + self.op3 = nn.Conv2d(16, 8, 1) + self.op4 = nn.Conv2d(3, 8, 1) + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.fc = nn.Linear(16, 1000) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.op1(x) + x2 = self.op2(x) + cat1 = torch.cat([x1, x2], dim=1) + x3 = self.op3(cat1) + x4 = self.op4(x) + cat2 = torch.cat([x3, x4], dim=1) + x_pool = self.avg_pool(cat2).flatten(1) + output = self.fc(x_pool) + + return output + + +class MultiConcatModel2(Module): + """ + x--------------- + |op1 |op2 |op3 + x1 x2 x3 + | | | + |cat----- | + cat1 | + |cat------------- + cat2 + |op4 + x4 + |avg_pool + x_pool + |fc + output + """ + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.op2 = nn.Conv2d(3, 8, 1) + self.op3 = nn.Conv2d(3, 8, 1) + self.op4 = nn.Conv2d(24, 8, 1) + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.fc = nn.Linear(8, 1000) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.op1(x) + x2 = self.op2(x) + x3 = self.op3(x) + cat1 = torch.cat([x1, x2], dim=1) + cat2 = torch.cat([cat1, x3], dim=1) + x4 = self.op4(cat2) + + x_pool = self.avg_pool(x4).reshape([x4.shape[0], -1]) + output = self.fc(x_pool) + + return output + + +class ConcatModel(Module): + """ + x------------ + |op1,bn1 |op2,bn2 + x1 x2 + |cat--------| + cat1 + |op3 + x3 + |avg_pool + x_pool + |fc + output + """ + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.bn1 = nn.BatchNorm2d(8) + self.op2 = nn.Conv2d(3, 8, 1) + self.bn2 = nn.BatchNorm2d(8) + self.op3 = nn.Conv2d(16, 8, 1) + + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.fc = nn.Linear(8, 1000) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.bn1(self.op1(x)) + x2 = self.bn2(self.op2(x)) + cat1 = torch.cat([x1, x2], dim=1) + x3 = self.op3(cat1) + + x_pool = self.avg_pool(x3).flatten(1) + output = self.fc(x_pool) + + return output + + +class ResBlock(Module): + """ + x + |op1,bn1 + x1----------- + |op2,bn2 | + x2 | + +------------ + |op3 + x3 + |avg_pool + x_pool + |fc + output + """ + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.bn1 = nn.BatchNorm2d(8) + self.op2 = nn.Conv2d(8, 8, 1) + self.bn2 = nn.BatchNorm2d(8) + self.op3 = nn.Conv2d(8, 8, 1) + + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.fc = nn.Linear(8, 1000) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.bn1(self.op1(x)) + x2 = self.bn2(self.op2(x1)) + x3 = self.op3(x2 + x1) + x_pool = self.avg_pool(x3).flatten(1) + output = self.fc(x_pool) + return output + + +class SingleLineModel(nn.Module): + """ + x + |net0,net1 + |net2 + |net3 + x1 + |fc + output + """ + + def __init__(self) -> None: + super().__init__() + self.net = nn.Sequential( + nn.Conv2d(3, 8, 3, 1, 1), nn.BatchNorm2d(8), nn.ReLU(), + nn.Conv2d(8, 16, 3, 1, 1), nn.BatchNorm2d(16), + nn.AdaptiveAvgPool2d(1)) + self.linear = nn.Linear(16, 1000) + + def forward(self, x): + x1 = self.net(x) + x1 = x1.reshape([x1.shape[0], -1]) + return self.linear(x1) + + +class AddCatModel(Module): + """ + x------------------------ + |op1 |op2 |op3 |op4 + x1 x2 x3 x4 + | | | | + |cat----- |cat----- + cat1 cat2 + | | + +---------------- + x5 + |avg_pool + x_pool + |fc + y + """ + + def __init__(self) -> None: + super().__init__() + self.op1 = nn.Conv2d(3, 2, 3) + self.op2 = nn.Conv2d(3, 6, 3) + self.op3 = nn.Conv2d(3, 4, 3) + self.op4 = nn.Conv2d(3, 4, 3) + self.op5 = nn.Conv2d(8, 16, 3) + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.fc = nn.Linear(16, 1000) + + def forward(self, x): + x1 = self.op1(x) + x2 = self.op2(x) + x3 = self.op3(x) + x4 = self.op4(x) + + cat1 = torch.cat((x1, x2), dim=1) + cat2 = torch.cat((x3, x4), dim=1) + x5 = self.op5(cat1 + cat2) + x_pool = self.avg_pool(x5).flatten(1) + y = self.fc(x_pool) + return y + + +class GroupWiseConvModel(nn.Module): + """ + x + |op1,bn1 + x1 + |op2,bn2 + x2 + |op3 + x3 + |avg_pool + x_pool + |fc + y + """ + + def __init__(self) -> None: + super().__init__() + self.op1 = nn.Conv2d(3, 8, 3, 1, 1) + self.bn1 = nn.BatchNorm2d(8) + self.op2 = nn.Conv2d(8, 16, 3, 1, 1, groups=2) + self.bn2 = nn.BatchNorm2d(16) + self.op3 = nn.Conv2d(16, 32, 3, 1, 1) + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.fc = nn.Linear(32, 1000) + + def forward(self, x): + x1 = self.op1(x) + x1 = self.bn1(x1) + x2 = self.op2(x1) + x2 = self.bn2(x2) + x3 = self.op3(x2) + x_pool = self.avg_pool(x3).flatten(1) + return self.fc(x_pool) + + +class Xmodel(nn.Module): + """ + x-------- + |op1 |op2 + x1 x2 + | | + +-------- + x12------ + |op3 |op4 + x3 x4 + | | + +-------- + x34 + |avg_pool + x_pool + |fc + y + """ + + def __init__(self) -> None: + super().__init__() + self.op1 = nn.Conv2d(3, 8, 3, 1, 1) + self.op2 = nn.Conv2d(3, 8, 3, 1, 1) + self.op3 = nn.Conv2d(8, 16, 3, 1, 1) + self.op4 = nn.Conv2d(8, 16, 3, 1, 1) + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.fc = nn.Linear(16, 1000) + + def forward(self, x): + x1 = self.op1(x) + x2 = self.op2(x) + x12 = x1 * x2 + x3 = self.op3(x12) + x4 = self.op4(x12) + x34 = x3 + x4 + x_pool = self.avg_pool(x34).flatten(1) + return self.fc(x_pool) + + +class MultipleUseModel(nn.Module): + """ + x------------------------ + |conv0 |conv1 |conv2 |conv3 + xs.0 xs.1 xs.2 xs.3 + |convm |convm |convm |convm + xs_.0 xs_.1 xs_.2 xs_.3 + | | | | + +------------------------ + | + x_sum + |conv_last + feature + |avg_pool + pool + |linear + output + """ + + def __init__(self) -> None: + super().__init__() + self.conv0 = nn.Conv2d(3, 8, 3, 1, 1) + self.conv1 = nn.Conv2d(3, 8, 3, 1, 1) + self.conv2 = nn.Conv2d(3, 8, 3, 1, 1) + self.conv3 = nn.Conv2d(3, 8, 3, 1, 1) + self.conv_multiple_use = nn.Conv2d(8, 16, 3, 1, 1) + self.conv_last = nn.Conv2d(16 * 4, 32, 3, 1, 1) + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.linear = nn.Linear(32, 1000) + + def forward(self, x): + xs = [ + conv(x) + for conv in [self.conv0, self.conv1, self.conv2, self.conv3] + ] + xs_ = [self.conv_multiple_use(x_) for x_ in xs] + x_cat = torch.cat(xs_, dim=1) + feature = self.conv_last(x_cat) + pool = self.avg_pool(feature).flatten(1) + return self.linear(pool) + + +class IcepBlock(nn.Module): + """ + x------------------------ + |op1 |op2 |op3 |op4 + x1 x2 x3 x4 + | | | | + cat---------------------- + | + y_ + """ + + def __init__(self, in_c=3, out_c=32) -> None: + super().__init__() + self.op1 = nn.Conv2d(in_c, out_c, 3, 1, 1) + self.op2 = nn.Conv2d(in_c, out_c, 3, 1, 1) + self.op3 = nn.Conv2d(in_c, out_c, 3, 1, 1) + self.op4 = nn.Conv2d(in_c, out_c, 3, 1, 1) + # self.op5 = nn.Conv2d(out_c*4, out_c, 3) + + def forward(self, x): + x1 = self.op1(x) + x2 = self.op2(x) + x3 = self.op3(x) + x4 = self.op4(x) + y_ = [x1, x2, x3, x4] + y_ = torch.cat(y_, 1) + return y_ + + +class Icep(nn.Module): + + def __init__(self, num_icep_blocks=2) -> None: + super().__init__() + self.icps = nn.Sequential(*[ + IcepBlock(32 * 4 if i != 0 else 3, 32) + for i in range(num_icep_blocks) + ]) + self.op = nn.Conv2d(32 * 4, 32, 1) + self.avg_pool = nn.AdaptiveAvgPool2d(1) + self.fc = nn.Linear(32, 1000) + + def forward(self, x): + y_ = self.icps(x) + y = self.op(y_) + pool = self.avg_pool(y).flatten(1) + return self.fc(pool) + + +class ExpandLineModel(Module): + """ + x + |net0,net1,net2 + |net3,net4 + x1 + |fc + output + """ + + def __init__(self) -> None: + super().__init__() + self.net = nn.Sequential( + nn.Conv2d(3, 8, 3, 1, 1), nn.BatchNorm2d(8), nn.ReLU(), + nn.Conv2d(8, 16, 3, 1, 1), nn.BatchNorm2d(16), + nn.AdaptiveAvgPool2d(2)) + self.linear = nn.Linear(64, 1000) + + def forward(self, x): + x1 = self.net(x) + x1 = x1.reshape([x1.shape[0], -1]) + return self.linear(x1) + + +class MultiBindModel(Module): + + def __init__(self) -> None: + super().__init__() + self.conv1 = nn.Conv2d(3, 8, 3, 1, 1) + self.conv2 = nn.Conv2d(3, 8, 3, 1, 1) + self.conv3 = nn.Conv2d(8, 8, 3, 1, 1) + self.head = LinearHeadForTest(8, 1000) + + def forward(self, x): + x1 = self.conv1(x) + x2 = self.conv2(x) + x12 = x1 + x2 + x3 = self.conv3(x12) + x123 = x12 + x3 + return self.head(x123) + + +class DwConvModel(nn.Module): + + def __init__(self) -> None: + super().__init__() + self.net = nn.Sequential( + nn.Conv2d(3, 48, 3, 1, 1), nn.BatchNorm2d(48), nn.ReLU(), + nn.Conv2d(48, 48, 3, 1, 1, groups=48), nn.BatchNorm2d(48), + nn.ReLU()) + self.head = LinearHeadForTest(48, 1000) + + def forward(self, x): + return self.head(self.net(x)) + + +class SelfAttention(nn.Module): + + def __init__(self) -> None: + super().__init__() + self.stem = nn.Conv2d(3, 32, 4, 4, 4) + + self.num_head = 4 + self.qkv = nn.Linear(32, 32 * 3) + self.proj = nn.Linear(32, 32) + + self.head = LinearHeadForTest(32, 1000) + + def forward(self, x: torch.Tensor): + x = self.stem(x) + h, w = x.shape[-2:] + x = self._to_token(x) + x = x + self._forward_attention(x) + x = self._to_img(x, h, w) + return self.head(x) + + def _to_img(self, x, h, w): + x = x.reshape([x.shape[0], h, w, x.shape[2]]) + x = x.permute(0, 3, 1, 2) + return x + + def _to_token(self, x): + x = x.flatten(2).transpose(-1, -2) + return x + + def _forward_attention(self, x: torch.Tensor): + qkv = self.qkv(x) + qkv = qkv.reshape([ + x.shape[0], x.shape[1], 3, self.num_head, + x.shape[2] // self.num_head + ]).permute(2, 0, 3, 1, 4).contiguous() + q, k, v = qkv + attn = q @ k.transpose(-1, -2) / math.sqrt(32 // self.num_head) + y = attn @ v # B H N h + y = y.permute(0, 2, 1, 3).flatten(-2) + return self.proj(y) + + +def MMClsResNet18() -> BaseModel: + model_cfg = dict( + _scope_='mmcls', + type='ImageClassifier', + backbone=dict( + type='ResNet', + depth=18, + num_stages=4, + out_indices=(3, ), + style='pytorch'), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=1000, + in_channels=512, + loss=dict(type='CrossEntropyLoss', loss_weight=1.0), + topk=(1, 5), + )) + return MODELS.build(model_cfg) + + +# models with dynamicop + + +def register_mutable(module: DynamicChannelMixin, + mutable: MutableChannelUnit, + is_out=True, + start=0, + end=-1): + if end == -1: + end = mutable.num_channels + start + if is_out: + container: MutableChannelContainer = module.get_mutable_attr( + 'out_channels') + else: + container: MutableChannelContainer = module.get_mutable_attr( + 'in_channels') + container.register_mutable(mutable, start, end) + + +class SampleExpandDerivedMutable(BaseMutable): + + def __init__(self, expand_ratio=1) -> None: + super().__init__() + self.ratio = expand_ratio + + def __mul__(self, other): + if isinstance(other, OneShotMutableChannel): + + def _expand_mask(): + mask = other.current_mask + mask = torch.unsqueeze( + mask, + -1).expand(list(mask.shape) + [self.ratio]).flatten(-2) + return mask + + return DerivedMutable(_expand_mask, _expand_mask, [self, other]) + else: + raise NotImplementedError() + + def dump_chosen(self): + return super().dump_chosen() + + def export_chosen(self): + return super().export_chosen() + + def fix_chosen(self, chosen): + return super().fix_chosen(chosen) + + def num_choices(self) -> int: + return super().num_choices + + @property + def current_choice(self): + return super().current_choice + + @current_choice.setter + def current_choice(self, choice): + super().current_choice(choice) + +class DynamicLinearModel(nn.Module): + """ + x + |net0,net1 + |net2 + |net3 + x1 + |fc + output + """ + + def __init__(self) -> None: + super().__init__() + self.net = nn.Sequential( + DynamicConv2d(3, 8, 3, 1, 1), DynamicBatchNorm2d(8), nn.ReLU(), + DynamicConv2d(8, 16, 3, 1, 1), DynamicBatchNorm2d(16), + nn.AdaptiveAvgPool2d(1)) + self.linear = DynamicLinear(16, 1000) + + MutableChannelUnit._register_channel_container( + self, MutableChannelContainer) + self._register_mutable() + + def forward(self, x): + x1 = self.net(x) + x1 = x1.reshape([x1.shape[0], -1]) + return self.linear(x1) + + def _register_mutable(self): + mutable1 = OneShotMutableChannel(8, candidate_choices=[1, 4, 8]) + mutable2 = OneShotMutableChannel(16, candidate_choices=[2, 8, 16]) + mutable_value = SampleExpandDerivedMutable(1) + + MutableChannelContainer.register_mutable_channel_to_module( + self.net[0], mutable1, True) + MutableChannelContainer.register_mutable_channel_to_module( + self.net[1], mutable1.expand_mutable_channel(1), True, 0, 8) + MutableChannelContainer.register_mutable_channel_to_module( + self.net[3], mutable_value * mutable1, False, 0, 8) + + MutableChannelContainer.register_mutable_channel_to_module( + self.net[3], mutable2, True) + MutableChannelContainer.register_mutable_channel_to_module( + self.net[4], mutable2, True) + MutableChannelContainer.register_mutable_channel_to_module( + self.linear, mutable2, False) + + +class DynamicAttention(nn.Module): + """ + x + |blocks: DynamicSequential(depth) + |(blocks) + x1 + |fc (OneShotMutableChannel * OneShotMutableValue) + output + """ + + def __init__(self) -> None: + super().__init__() + + self.mutable_depth = OneShotMutableValue( + value_list=[1, 2], default_value=2) + self.mutable_embed_dims = OneShotMutableChannel( + num_channels=624, candidate_choices=[576, 624]) + self.base_embed_dims = OneShotMutableChannel( + num_channels=64, candidate_choices=[64]) + self.mutable_num_heads = [ + OneShotMutableValue(value_list=[8, 10], default_value=10) + for _ in range(2) + ] + self.mutable_mlp_ratios = [ + OneShotMutableValue(value_list=[3.0, 3.5, 4.0], default_value=4.0) + for _ in range(2) + ] + self.mutable_q_embed_dims = [ + i * self.base_embed_dims for i in self.mutable_num_heads + ] + + self.patch_embed = DynamicPatchEmbed( + img_size=224, + in_channels=3, + embed_dims=self.mutable_embed_dims.num_channels) + + # cls token and pos embed + self.pos_embed = nn.Parameter( + torch.zeros(1, 197, self.mutable_embed_dims.num_channels)) + self.cls_token = nn.Parameter( + torch.zeros(1, 1, self.mutable_embed_dims.num_channels)) + + layers = [] + for i in range(self.mutable_depth.max_choice): + layer = TransformerEncoderLayer( + embed_dims=self.mutable_embed_dims.num_channels, + num_heads=self.mutable_num_heads[i].max_choice, + mlp_ratio=self.mutable_mlp_ratios[i].max_choice) + layers.append(layer) + self.blocks = DynamicSequential(*layers) + + # OneShotMutableChannelUnit + OneShotMutableChannelUnit._register_channel_container( + self, MutableChannelContainer) + + self.register_mutables() + + def register_mutables(self): + # mutablevalue + self.blocks.register_mutable_attr('depth', self.mutable_depth) + # mutablechannel + MutableChannelContainer.register_mutable_channel_to_module( + self.patch_embed, self.mutable_embed_dims, True) + + for i in range(self.mutable_depth.max_choice): + layer = self.blocks[i] + layer.register_mutables( + mutable_num_heads=self.mutable_num_heads[i], + mutable_mlp_ratios=self.mutable_mlp_ratios[i], + mutable_q_embed_dims=self.mutable_q_embed_dims[i], + mutable_head_dims=self.base_embed_dims, + mutable_embed_dims=self.mutable_embed_dims) + + def forward(self, x: torch.Tensor): + B = x.shape[0] + x = self.patch_embed(x) + embed_dims = self.mutable_embed_dims.current_choice + cls_tokens = self.cls_token[..., :embed_dims].expand(B, -1, -1) + x = torch.cat((cls_tokens, x), dim=1) + x = x + self.pos_embed[..., :embed_dims] + x = self.blocks(x) + return torch.mean(x[:, 1:], dim=1) + + +class DynamicMMBlock(nn.Module): + + arch_setting = dict( + kernel_size=[ # [min_kernel_size, max_kernel_size, step] + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + ], + num_blocks=[ # [min_num_blocks, max_num_blocks, step] + [1, 2, 1], + [3, 5, 1], + [3, 6, 1], + [3, 6, 1], + [3, 8, 1], + [3, 8, 1], + [1, 2, 1], + ], + expand_ratio=[ # [min_expand_ratio, max_expand_ratio, step] + [1, 1, 1], + [4, 6, 1], + [4, 6, 1], + [4, 6, 1], + [4, 6, 1], + [6, 6, 1], + [6, 6, 1], + ], + num_out_channels=[ # [min_channel, max_channel, step] + [16, 24, 8], + [24, 32, 8], + [32, 40, 8], + [64, 72, 8], + [112, 128, 8], + [192, 216, 8], + [216, 224, 8], + ]) + + def __init__( + self, + conv_cfg: Dict = dict(type='mmrazor.BigNasConv2d'), + norm_cfg: Dict = dict(type='mmrazor.DynamicBatchNorm2d'), + fine_grained_mode: bool = False, + ) -> None: + super().__init__() + + self.conv_cfg = conv_cfg + self.norm_cfg = norm_cfg + self.act_list = ['Swish'] * 7 + self.stride_list = [1, 2, 2, 2, 1, 2, 1] + self.with_se_list = [False, False, True, False, True, True, True] + self.kernel_size_list = parse_values(self.arch_setting['kernel_size']) + self.num_blocks_list = parse_values(self.arch_setting['num_blocks']) + self.expand_ratio_list = \ + parse_values(self.arch_setting['expand_ratio']) + self.num_channels_list = \ + parse_values(self.arch_setting['num_out_channels']) + assert len(self.kernel_size_list) == len(self.num_blocks_list) == \ + len(self.expand_ratio_list) == len(self.num_channels_list) + + self.fine_grained_mode = fine_grained_mode + self.with_attentive_shortcut = True + self.in_channels = 24 + + self.first_out_channels_list = [16] + self.first_conv = ConvModule( + in_channels=3, + out_channels=24, + kernel_size=3, + stride=2, + padding=1, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=dict(type='Swish')) + + self.layers = [] + for i, (num_blocks, kernel_sizes, expand_ratios, num_channels) in \ + enumerate(zip(self.num_blocks_list, self.kernel_size_list, + self.expand_ratio_list, self.num_channels_list)): + inverted_res_layer = self._make_single_layer( + out_channels=num_channels, + num_blocks=num_blocks, + kernel_sizes=kernel_sizes, + expand_ratios=expand_ratios, + act_cfg=self.act_list[i], + stride=self.stride_list[i], + use_se=self.with_se_list[i]) + layer_name = f'layer{i + 1}' + self.add_module(layer_name, inverted_res_layer) + self.layers.append(inverted_res_layer) + + last_expand_channels = 1344 + self.out_channels = 1984 + self.last_out_channels_list = [1792, 1984] + self.last_expand_ratio_list = [6] + + last_layers = Sequential( + OrderedDict([('final_expand_layer', + ConvModule( + in_channels=self.in_channels, + out_channels=last_expand_channels, + kernel_size=1, + padding=0, + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=dict(type='Swish'))), + ('pool', nn.AdaptiveAvgPool2d((1, 1))), + ('feature_mix_layer', + ConvModule( + in_channels=last_expand_channels, + out_channels=self.out_channels, + kernel_size=1, + padding=0, + bias=False, + conv_cfg=self.conv_cfg, + norm_cfg=None, + act_cfg=dict(type='Swish')))])) + self.add_module('last_conv', last_layers) + self.layers.append(last_layers) + + self.register_mutables() + + def _make_single_layer(self, out_channels, num_blocks, kernel_sizes, + expand_ratios, act_cfg, stride, use_se): + _layers = [] + for i in range(max(num_blocks)): + if i >= 1: + stride = 1 + if use_se: + se_cfg = dict( + act_cfg=(dict(type='ReLU'), dict(type='HSigmoid')), + ratio=4, + conv_cfg=self.conv_cfg) + else: + se_cfg = None # type: ignore + + mb_layer = MBBlock( + in_channels=self.in_channels, + out_channels=max(out_channels), + kernel_size=max(kernel_sizes), + stride=stride, + expand_ratio=max(expand_ratios), + conv_cfg=self.conv_cfg, + norm_cfg=self.norm_cfg, + act_cfg=dict(type=act_cfg), + se_cfg=se_cfg, + with_attentive_shortcut=self.with_attentive_shortcut) + + _layers.append(mb_layer) + self.in_channels = max(out_channels) + + dynamic_seq = DynamicSequential(*_layers) + return dynamic_seq + + def register_mutables(self): + """Mutate the BigNAS-style MobileNetV3.""" + OneShotMutableChannelUnit._register_channel_container( + self, MutableChannelContainer) + + self.first_mutable_channels = OneShotMutableChannel( + alias='backbone.first_channels', + num_channels=max(self.first_out_channels_list), + candidate_choices=self.first_out_channels_list) + + mutate_conv_module( + self.first_conv, mutable_out_channels=self.first_mutable_channels) + + mid_mutable = self.first_mutable_channels + # mutate the built mobilenet layers + for i, layer in enumerate(self.layers[:-1]): + num_blocks = self.num_blocks_list[i] + kernel_sizes = self.kernel_size_list[i] + expand_ratios = self.expand_ratio_list[i] + out_channels = self.num_channels_list[i] + + prefix = 'backbone.layers.' + str(i + 1) + '.' + + mutable_out_channels = OneShotMutableChannel( + alias=prefix + 'out_channels', + candidate_choices=out_channels, + num_channels=max(out_channels)) + + if not self.fine_grained_mode: + mutable_kernel_size = OneShotMutableValue( + alias=prefix + 'kernel_size', value_list=kernel_sizes) + + mutable_expand_ratio = OneShotMutableValue( + alias=prefix + 'expand_ratio', value_list=expand_ratios) + + mutable_depth = OneShotMutableValue( + alias=prefix + 'depth', value_list=num_blocks) + layer.register_mutable_attr('depth', mutable_depth) + + for k in range(max(self.num_blocks_list[i])): + + if self.fine_grained_mode: + mutable_kernel_size = OneShotMutableValue( + alias=prefix + str(k) + '.kernel_size', + value_list=kernel_sizes) + + mutable_expand_ratio = OneShotMutableValue( + alias=prefix + str(k) + '.expand_ratio', + value_list=expand_ratios) + + mutate_mobilenet_layer(layer[k], mid_mutable, + mutable_out_channels, + mutable_expand_ratio, + mutable_kernel_size) + mid_mutable = mutable_out_channels + + self.last_mutable_channels = OneShotMutableChannel( + alias='backbone.last_channels', + num_channels=self.out_channels, + candidate_choices=self.last_out_channels_list) + + last_mutable_expand_value = OneShotMutableValue( + value_list=self.last_expand_ratio_list, + default_value=max(self.last_expand_ratio_list)) + + derived_expand_channels = mid_mutable * last_mutable_expand_value + mutate_conv_module( + self.layers[-1].final_expand_layer, + mutable_in_channels=mid_mutable, + mutable_out_channels=derived_expand_channels) + mutate_conv_module( + self.layers[-1].feature_mix_layer, + mutable_in_channels=derived_expand_channels, + mutable_out_channels=self.last_mutable_channels) + + def forward(self, x): + x = self.first_conv(x) + for _, layer in enumerate(self.layers): + x = layer(x) + + return tuple([x]) diff --git a/cv/distiller/CWD/mmrazor/tests/data/subnet1.yaml b/cv/distiller/CWD/mmrazor/tests/data/subnet1.yaml new file mode 100755 index 000000000..f7886351b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/subnet1.yaml @@ -0,0 +1,24 @@ +op1.mutable_in_channels: + current_choice: 3 + origin_channels: 3 +op1.mutable_out_channels: + current_choice: 4 + origin_channels: 8 +bn1.mutable_num_features: + current_choice: 4 + origin_channels: 8 +op2.mutable_in_channels: + current_choice: 4 + origin_channels: 8 +op2.mutable_out_channels: + current_choice: 4 + origin_channels: 8 +bn2.mutable_num_features: + current_choice: 4 + origin_channels: 8 +op3.mutable_in_channels: + current_choice: 4 + origin_channels: 8 +op3.mutable_out_channels: + current_choice: 8 + origin_channels: 8 \ No newline at end of file diff --git a/cv/distiller/CWD/mmrazor/tests/data/subnet2.yaml b/cv/distiller/CWD/mmrazor/tests/data/subnet2.yaml new file mode 100755 index 000000000..bd49b2c7d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/subnet2.yaml @@ -0,0 +1,24 @@ +op1.mutable_in_channels: + current_choice: 3 + origin_channels: 3 +op1.mutable_out_channels: + current_choice: 8 + origin_channels: 8 +bn1.mutable_num_features: + current_choice: 8 + origin_channels: 8 +op2.mutable_in_channels: + current_choice: 8 + origin_channels: 8 +op2.mutable_out_channels: + current_choice: 8 + origin_channels: 8 +bn2.mutable_num_features: + current_choice: 8 + origin_channels: 8 +op3.mutable_in_channels: + current_choice: 8 + origin_channels: 8 +op3.mutable_out_channels: + current_choice: 8 + origin_channels: 8 \ No newline at end of file diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_models/test_algorithm/MBV2_220M.yaml b/cv/distiller/CWD/mmrazor/tests/data/test_models/test_algorithm/MBV2_220M.yaml new file mode 100755 index 000000000..b96ebeb49 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/test_models/test_algorithm/MBV2_220M.yaml @@ -0,0 +1,474 @@ +backbone.conv1.bn.mutable_num_features: + current_choice: 8 + origin_channels: 48 +backbone.conv1.conv.mutable_in_channels: + current_choice: 3 + origin_channels: 3 +backbone.conv1.conv.mutable_out_channels: + current_choice: 8 + origin_channels: 48 +backbone.conv2.bn.mutable_num_features: + current_choice: 1920 + origin_channels: 1920 +backbone.conv2.conv.mutable_in_channels: + current_choice: 280 + origin_channels: 480 +backbone.conv2.conv.mutable_out_channels: + current_choice: 1920 + origin_channels: 1920 +backbone.layer1.0.conv.0.bn.mutable_num_features: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.0.conv.mutable_in_channels: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.0.conv.mutable_out_channels: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.1.bn.mutable_num_features: + current_choice: 8 + origin_channels: 24 +backbone.layer1.0.conv.1.conv.mutable_in_channels: + current_choice: 8 + origin_channels: 48 +backbone.layer1.0.conv.1.conv.mutable_out_channels: + current_choice: 8 + origin_channels: 24 +backbone.layer2.0.conv.0.bn.mutable_num_features: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.0.conv.mutable_in_channels: + current_choice: 8 + origin_channels: 24 +backbone.layer2.0.conv.0.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.1.bn.mutable_num_features: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.1.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.1.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.2.bn.mutable_num_features: + current_choice: 16 + origin_channels: 40 +backbone.layer2.0.conv.2.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 144 +backbone.layer2.0.conv.2.conv.mutable_out_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer2.1.conv.0.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.0.conv.mutable_in_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer2.1.conv.0.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.1.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.1.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.1.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.2.bn.mutable_num_features: + current_choice: 16 + origin_channels: 40 +backbone.layer2.1.conv.2.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer2.1.conv.2.conv.mutable_out_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer3.0.conv.0.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.0.conv.mutable_in_channels: + current_choice: 16 + origin_channels: 40 +backbone.layer3.0.conv.0.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.1.bn.mutable_num_features: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.1.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.1.conv.mutable_out_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.2.bn.mutable_num_features: + current_choice: 24 + origin_channels: 48 +backbone.layer3.0.conv.2.conv.mutable_in_channels: + current_choice: 96 + origin_channels: 240 +backbone.layer3.0.conv.2.conv.mutable_out_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.1.conv.0.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.0.conv.mutable_in_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.1.conv.0.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.1.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.1.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.1.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.2.bn.mutable_num_features: + current_choice: 24 + origin_channels: 48 +backbone.layer3.1.conv.2.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.1.conv.2.conv.mutable_out_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.2.conv.0.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.0.conv.mutable_in_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer3.2.conv.0.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.1.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.2.bn.mutable_num_features: + current_choice: 24 + origin_channels: 48 +backbone.layer3.2.conv.2.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer3.2.conv.2.conv.mutable_out_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer4.0.conv.0.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.0.conv.mutable_in_channels: + current_choice: 24 + origin_channels: 48 +backbone.layer4.0.conv.0.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.1.bn.mutable_num_features: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.1.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.1.conv.mutable_out_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.2.bn.mutable_num_features: + current_choice: 48 + origin_channels: 96 +backbone.layer4.0.conv.2.conv.mutable_in_channels: + current_choice: 144 + origin_channels: 288 +backbone.layer4.0.conv.2.conv.mutable_out_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.1.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.0.conv.mutable_in_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.1.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.2.bn.mutable_num_features: + current_choice: 48 + origin_channels: 96 +backbone.layer4.1.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.1.conv.2.conv.mutable_out_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.2.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.0.conv.mutable_in_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.2.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.2.bn.mutable_num_features: + current_choice: 48 + origin_channels: 96 +backbone.layer4.2.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.2.conv.2.conv.mutable_out_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.3.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.0.conv.mutable_in_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer4.3.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.2.bn.mutable_num_features: + current_choice: 48 + origin_channels: 96 +backbone.layer4.3.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer4.3.conv.2.conv.mutable_out_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer5.0.conv.0.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.0.conv.mutable_in_channels: + current_choice: 48 + origin_channels: 96 +backbone.layer5.0.conv.0.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.1.bn.mutable_num_features: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.1.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.1.conv.mutable_out_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.2.bn.mutable_num_features: + current_choice: 64 + origin_channels: 144 +backbone.layer5.0.conv.2.conv.mutable_in_channels: + current_choice: 288 + origin_channels: 576 +backbone.layer5.0.conv.2.conv.mutable_out_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer5.1.conv.0.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.0.conv.mutable_in_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer5.1.conv.0.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.1.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.1.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.1.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.2.bn.mutable_num_features: + current_choice: 64 + origin_channels: 144 +backbone.layer5.1.conv.2.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.1.conv.2.conv.mutable_out_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer5.2.conv.0.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.0.conv.mutable_in_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer5.2.conv.0.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.1.bn.mutable_num_features: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.1.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.1.conv.mutable_out_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.2.bn.mutable_num_features: + current_choice: 64 + origin_channels: 144 +backbone.layer5.2.conv.2.conv.mutable_in_channels: + current_choice: 432 + origin_channels: 864 +backbone.layer5.2.conv.2.conv.mutable_out_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer6.0.conv.0.bn.mutable_num_features: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.0.conv.mutable_in_channels: + current_choice: 64 + origin_channels: 144 +backbone.layer6.0.conv.0.conv.mutable_out_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.1.bn.mutable_num_features: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.1.conv.mutable_in_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.1.conv.mutable_out_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.2.bn.mutable_num_features: + current_choice: 176 + origin_channels: 240 +backbone.layer6.0.conv.2.conv.mutable_in_channels: + current_choice: 648 + origin_channels: 864 +backbone.layer6.0.conv.2.conv.mutable_out_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer6.1.conv.0.bn.mutable_num_features: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.0.conv.mutable_in_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer6.1.conv.0.conv.mutable_out_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.1.bn.mutable_num_features: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.1.conv.mutable_in_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.1.conv.mutable_out_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.2.bn.mutable_num_features: + current_choice: 176 + origin_channels: 240 +backbone.layer6.1.conv.2.conv.mutable_in_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.1.conv.2.conv.mutable_out_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer6.2.conv.0.bn.mutable_num_features: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.0.conv.mutable_in_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer6.2.conv.0.conv.mutable_out_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.1.bn.mutable_num_features: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.1.conv.mutable_in_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.1.conv.mutable_out_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.2.bn.mutable_num_features: + current_choice: 176 + origin_channels: 240 +backbone.layer6.2.conv.2.conv.mutable_in_channels: + current_choice: 720 + origin_channels: 1440 +backbone.layer6.2.conv.2.conv.mutable_out_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer7.0.conv.0.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.0.conv.mutable_in_channels: + current_choice: 176 + origin_channels: 240 +backbone.layer7.0.conv.0.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.bn.mutable_num_features: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.1.conv.mutable_out_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.2.bn.mutable_num_features: + current_choice: 280 + origin_channels: 480 +backbone.layer7.0.conv.2.conv.mutable_in_channels: + current_choice: 1440 + origin_channels: 1440 +backbone.layer7.0.conv.2.conv.mutable_out_channels: + current_choice: 280 + origin_channels: 480 +head.fc.mutable_in_features: + current_choice: 1920 + origin_channels: 1920 +head.fc.mutable_out_features: + current_choice: 1000 + origin_channels: 1000 \ No newline at end of file diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_models/test_mutator/subnet1.json b/cv/distiller/CWD/mmrazor/tests/data/test_models/test_mutator/subnet1.json new file mode 100755 index 000000000..2fed960b2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/test_models/test_mutator/subnet1.json @@ -0,0 +1,15 @@ +{ + "op1_(0, 8)_8": { + "init_args":{ + "num_channels":8, + "divisor":1, + "min_value":1, + "min_ratio":0.9, + "candidate_choices":[ + 6 + ], + "choice_mode":"number" + }, + "choice":6 + } +} diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_models/test_subnet/mockmodel_subnet.yaml b/cv/distiller/CWD/mmrazor/tests/data/test_models/test_subnet/mockmodel_subnet.yaml new file mode 100755 index 000000000..b7262da5b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/test_models/test_subnet/mockmodel_subnet.yaml @@ -0,0 +1,6 @@ +mutable1: + chosen: conv1 +mutable2: + chosen: conv2 +mutable3.0.kernel_size: + chosen: 3 diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_models/test_task_modules/mmcls_cfg.py b/cv/distiller/CWD/mmrazor/tests/data/test_models/test_task_modules/mmcls_cfg.py new file mode 100755 index 000000000..117b9383e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/test_models/test_task_modules/mmcls_cfg.py @@ -0,0 +1,2 @@ +# Copyright (c) OpenMMLab. All rights reserved. +_base_ = ['mmcls::resnet/resnet18_8xb32_in1k.py'] \ No newline at end of file diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_architecture_config.py b/cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_architecture_config.py new file mode 100755 index 000000000..d5d220475 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_architecture_config.py @@ -0,0 +1,14 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from platform import architecture + + +supernet = dict( + type='MockModel', +) + +model = dict( + type='MockAlgorithm', + architecture=supernet, + _return_architecture_ = True, +) + diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_subnet_config.py b/cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_subnet_config.py new file mode 100755 index 000000000..7311c1e24 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/test_registry/registry_subnet_config.py @@ -0,0 +1,17 @@ +# Copyright (c) OpenMMLab. All rights reserved. +supernet = dict( + type='mmrazor.sub_model', + cfg=dict( + type='MockModel', + ), + fix_subnet = { + 'backbone.mutable1': {'chosen':'conv1'}, + 'backbone.mutable2': {'chosen':'conv2'}, + }, + extra_prefix='backbone.' +) + +model = dict( + type='MockAlgorithm', + architecture=supernet +) diff --git a/cv/distiller/CWD/mmrazor/tests/data/test_registry/subnet.json b/cv/distiller/CWD/mmrazor/tests/data/test_registry/subnet.json new file mode 100755 index 000000000..4fe63bda2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/test_registry/subnet.json @@ -0,0 +1,141 @@ +{ + "type":"DCFFChannelMutator", + "channel_unit_cfg":{ + "type":"DCFFChannelUnit", + "default_args":{ + "choice_mode":"ratio" + }, + "units":{ + "backbone.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":1.0 + }, + "backbone.layer1.0.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.640625 + }, + "backbone.layer1.1.conv1_(0, 64)_64":{ + "init_args":{ + "num_channels":64, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.640625 + }, + "backbone.layer2.0.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer2.0.conv2_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.59375 + }, + "backbone.layer2.1.conv1_(0, 128)_128":{ + "init_args":{ + "num_channels":128, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer3.0.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer3.0.conv2_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.59765625 + }, + "backbone.layer3.1.conv1_(0, 256)_256":{ + "init_args":{ + "num_channels":256, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.6484375 + }, + "backbone.layer4.0.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + }, + "backbone.layer4.0.conv2_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + }, + "backbone.layer4.1.conv1_(0, 512)_512":{ + "init_args":{ + "num_channels":512, + "choice_mode":"ratio", + "divisor":1, + "min_value":1, + "min_ratio":0.9 + }, + "choice":0.69921875 + } + } + }, + "parse_cfg":{ + "type":"ChannelAnalyzer", + "demo_input":[ + 1, + 3, + 224, + 224 + ], + "tracer_type":"BackwardTracer" + } +} \ No newline at end of file diff --git a/cv/distiller/CWD/mmrazor/tests/data/tracer_passed_models.py b/cv/distiller/CWD/mmrazor/tests/data/tracer_passed_models.py new file mode 100755 index 000000000..ade282141 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/data/tracer_passed_models.py @@ -0,0 +1,520 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .model_library import (MMClsModelLibrary, MMDetModelLibrary, + DefaultModelLibrary, TorchModelLibrary, + MMPoseModelLibrary, MMSegModelLibrary) + + +class PassedModelManager: + + def __init__(self) -> None: + pass + + def include_models(self, full_test=False): + models = [] + for library in self.libraries(full_test): + models.extend(library.include_models()) + return models + + def uninclude_models(self, full_test=False): + models = [] + for library in self.libraries(full_test): + models.extend(library.uninclude_models()) + return models + + def libraries(self, full=False): + return [] + + +class FxPassedModelManager(PassedModelManager): + + _default_library = None + _torch_library = None + _mmcls_library = None + _mmseg_library = None + _mmdet_library = None + _mmpose_library = None + + def libraries(self, full=False): + if full: + return [ + self.__class__.default_library(), + self.__class__.torch_library(), + self.__class__.mmcls_library(), + self.__class__.mmseg_library(), + self.__class__.mmdet_library(), + self.__class__.mmpose_library(), + ] + else: + return [self.__class__.default_library()] + + @classmethod + def default_library(cls): + if cls._default_library is None: + cls._default_library = DefaultModelLibrary(include=[ + 'SingleLineModel', + 'ResBlock', + 'AddCatModel', + 'ConcatModel', + 'MultiConcatModel', + 'MultiConcatModel2', + 'GroupWiseConvModel', + 'Xmodel', + 'MultipleUseModel', + 'Icep', + 'ExpandLineModel', + 'MultiBindModel', + 'DwConvModel', + 'ConvAttnModel', + # mm models + 'resnet', + 'pspnet', + 'yolo' + ],with_mm_models=True) + + return cls._default_library + + @classmethod + def torch_library(cls): + """ + googlenet: return a tuple when training, so it should + trace in eval mode + """ + torch_includes = [ + 'resnext', + 'efficientnet', + 'inception', + 'wide', + 'resnet', + 'regnet', + 'shufflenet', + 'mnasnet', + 'vit', + 'convnext', + 'googlenet', + 'densenet', + 'swin', + 'vgg', + 'mobilenet', + 'squeezenet', + 'alexnet', + ] + if cls._torch_library is None: + cls._torch_library = TorchModelLibrary(include=torch_includes) + return cls._torch_library + + @classmethod + def mmcls_library(cls): + """ + shufflenet consists of chunk operations. + resnest: resnest has two problems. First it uses *x.shape() which is + not tracerable using fx tracer. Second, it uses channel folding. + res2net: res2net consists of split operations. + convnext: consist of layernorm. + """ + mmcls_include = [ + 'tnt', + 'resnet', + 'resnetv1c', + 'mobileone', + 'mlp', + 'densenet', + 'hrnet', + 'seresnet', + 'van', + 'repmlp', + 'repvgg', + 'vgg', + 'vgg11bn', + 'edgenext', + 'vgg19bn', + 'wide', + 'res2net', + 'vgg13bn', + 'resnetv1d', + 'mobilenet', + 'convmixer', + 'resnest', + 'inception', + 'resnext', + 'twins', + 'vgg16bn', + 'shufflenet', + 'conformer', + 'regnet', + 'seresnext', + 'vit', + 'poolformer', + 't2t', + 'efficientnet', + ## error + # 'deit', + # 'swin', + # 'convnext', + # 'mvit' + ] + if cls._mmcls_library is None: + cls._mmcls_library = MMClsModelLibrary(include=mmcls_include) + return cls._mmcls_library + + @classmethod + def mmdet_library(cls): + mmdet_include = [ + 'pafpn', + 'gn+ws', + 'paa', + 'fcos', + 'autoassign', + 'centripetalnet', + 'retinanet', + 'cornernet', + 'gn', + 'instaboost', + 'rpn', + 'fpg', + 'crowddet', + 'resnest', + 'pvt', + 'solo', + 'grid', + 'free', + 'point', + 'yolo', + 'double', + 'dynamic', + 'maskformer', + 'scratch', + 'nas', + 'yolof', + 'faster', + 'atss', + 'yolox', + 'fsaf', + 'ghm', + 'centernet', + 'seesaw', + 'regnet', + 'cityscapes', + 'lvis', + 'sabl', + 'gfl', + 'tridentnet', + 'selfsup', + 'deepfashion', + 'efficientnet', + 'foveabox', + 'mask', + ## errors + # 'timm', + # 'swin', + # 'dyhead', + # 'hrnet', + # 'deformable', + # 'ssd', + # 'empirical', + # 'detectors', + # 'reppoints', + # 'scnet', + # 'legacy', + # 'htc', + # 'dcnv', + # 'carafe', + # 'yolact', + # 'panoptic', + # 'misc', + # 'rtmdet', + # 'pascal', + # 'ddod', + # 'mask2former', + # 'tood', + # 'queryinst', + # 'simple', + # 'pisa', + # 'fast', + # 'cascade', + # 'wider', + # 'openimages', + # '', + # 'strong', + # 'res2net', + # 'libra', + # 'vfnet', + # 'soft', + # 'sparse', + # 'gcnet', + # 'convnext', + # 'ms', + # 'dcn', + # 'guided', + # 'groie', + # 'solov', + # 'detr', + ] + if cls._mmdet_library is None: + cls._mmdet_library = MMDetModelLibrary(mmdet_include) + return cls._mmdet_library + + @classmethod + def mmseg_library(cls): + # a common error: unet related models + include = [ + 'bisenetv', + 'erfnet', + 'dmnet', + 'twins', + 'segformer', + 'isanet', + 'vit', + 'resnest', + 'setr', + 'cgnet', + 'stdc', + 'dpt', + 'pspnet', + 'upernet', + 'apcnet', + 'gcnet', + 'ann', + 'ocrnet', + 'ccnet', + 'deeplabv', + 'dnlnet', + 'point', + 'fastscnn', + 'psanet', + 'segmenter', + 'danet', + 'emanet', + 'icnet', + 'unet', + 'fcn', + 'swin', + 'nonlocal', + 'deeplabv3plus', + 'sem', + ## errors + # 'mobilenet', + # 'mae', + # 'knet', + # 'poolformer', + # 'beit', + # 'encnet', + # 'hrnet', + # 'convnext', + # 'fastfcn' + ] + if cls._mmseg_library is None: + cls._mmseg_library = MMSegModelLibrary(include=include) + return cls._mmseg_library + + + @classmethod + def mmpose_library(cls): + mmpose_include = [ + 'hand', + 'face', + 'wholebody', + 'body', + 'animal', + ] + if cls._mmpose_library is None: + cls._mmpose_library = MMPoseModelLibrary(include=mmpose_include) + + return cls._mmpose_library + + # for backward tracer + + +class BackwardPassedModelManager(PassedModelManager): + + _default_library = None + _torch_library = None + _mmcls_library = None + _mmseg_library = None + _mmdet_library = None + _mmpose_library = None + + + def libraries(self, full=False): + if full: + return [ + self.__class__.default_library(), + self.__class__.torch_library(), + self.__class__.mmcls_library(), + self.__class__.mmseg_library(), + self.__class__.mmdet_library(), + self.__class__.mmpose_library(), + ] + else: + return [self.__class__.default_library()] + + @classmethod + def default_library(cls): + if cls._default_library is None: + cls._default_library = DefaultModelLibrary(include=[ + 'SingleLineModel', + 'ResBlock', + 'AddCatModel', + 'ConcatModel', + 'MultiConcatModel', + 'MultiConcatModel2', + 'GroupWiseConvModel', + 'Xmodel', + # 'MultipleUseModel', # bug + 'Icep', + 'ExpandLineModel', + 'MultiBindModel', + 'DwConvModel', + 'ConvAttnModel', + ]) + return cls._default_library + + @classmethod + def torch_library(cls): + """ + googlenet return a tuple when training, so it + should trace in eval mode + """ + + torch_includes = [ + 'alexnet', + 'densenet', + 'efficientnet', + 'googlenet', + 'inception', + 'mnasnet', + 'mobilenet', + 'regnet', + 'resnet', + 'resnext', + # 'shufflenet', # bug + 'squeezenet', + 'vgg', + 'wide_resnet', + # "vit", + # "swin", + # "convnext" + ] + if cls._torch_library is None: + cls._torch_library = TorchModelLibrary(include=torch_includes) + return cls._torch_library + + @classmethod + def mmcls_library(cls): + """ + shufflenet consists of chunk operations. + resnest: resnest has two problems. First it uses *x.shape() which is + not tracerable using fx tracer. Second, it uses channel folding. + res2net: res2net consists of split operations. + convnext: consist of layernorm. + """ + mmcls_model_include = [ + 'vgg', + 'efficientnet', + 'resnet', + 'mobilenet', + 'resnext', + 'wide-resnet', + # 'shufflenet', # bug + 'hrnet', + # 'resnest', # bug + 'inception', + # 'res2net', # bug + 'densenet', + # 'convnext', # bug + 'regnet', + # 'van', # bug + # 'swin_transformer', # bug + # 'convmixer', # bug + # 't2t', # bug + # 'twins', # bug + # 'repmlp', # bug + # 'tnt', # bug + # 't2t', # bug + # 'mlp_mixer', # bug + # 'conformer', # bug + # 'poolformer', # bug + # 'vit', # bug + # 'efficientformer', + # 'mobileone', + # 'edgenext' + ] + mmcls_exclude = ['cutmix', 'cifar', 'gem'] + if cls._mmcls_library is None: + cls._mmcls_library = MMClsModelLibrary( + include=mmcls_model_include, exclude=mmcls_exclude) + return cls._mmcls_library + + @classmethod + def mmdet_library(cls): + mmdet_include = [ + # 'rpn', # + # 'faster-rcnn', + # 'cascade-rcnn', + # 'fast-rcnn', # mmdet has bug. + # 'retinanet', + # 'mask-rcnn', + # 'ssd300' + ] + if cls._mmdet_library is None: + cls._mmdet_library = MMDetModelLibrary(mmdet_include) + return cls._mmdet_library + + @classmethod + def mmseg_library(cls): + include = [ + # 'cgnet', + # 'gcnet', + # 'setr', + # 'deeplabv3', + # 'twins', + # 'fastfcn', + # 'fpn', + # 'upernet', + # 'dnl', + # 'icnet', + # 'segmenter', + # 'encnet', + # 'erfnet', + # 'segformer', + # 'apcnet', + # 'fast', + # 'ocrnet', + # 'lraspp', + # 'dpt', + # 'fcn', + # 'psanet', + # 'bisenetv2', + # 'pointrend', + # 'ccnet', + 'pspnet', + # 'dmnet', + # 'stdc', + # 'ann', + # 'nonlocal', + # 'isanet', + # 'danet', + # 'emanet', + # 'deeplabv3plus', + # 'bisenetv1', + ] + if cls._mmseg_library is None: + cls._mmseg_library = MMSegModelLibrary(include=include) + return cls._mmseg_library + + @classmethod + def mmpose_library(cls): + mmpose_include = [ + 'hand', + 'face', + 'wholebody', + 'body', + 'animal', + ] + + if cls._mmpose_library is None: + cls._mmpose_library = MMPoseModelLibrary(include=mmpose_include) + return cls._mmpose_library + + +fx_passed_library = FxPassedModelManager() +backward_passed_library = BackwardPassedModelManager() diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_core/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_deliver_manager.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_deliver_manager.py new file mode 100755 index 000000000..a476a7e3e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_deliver_manager.py @@ -0,0 +1,60 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +from mmengine import ConfigDict + +from mmrazor.models.task_modules import DistillDeliveryManager + + +class TestDeliverManager(TestCase): + + def test_init(self): + + distill_deliveries = ConfigDict( + delivery1=dict( + type='MethodOutputs', + max_keep_data=2, + method_path='toy_module.ToyClass.random_int')) + + manager = DistillDeliveryManager(distill_deliveries) + self.assertEquals(len(manager.deliveries), 1) + + manager = DistillDeliveryManager() + self.assertEquals(len(manager.deliveries), 0) + + def test_context_manager(self): + from toy_module import ToyClass + + distill_deliveries = ConfigDict( + delivery1=dict( + type='MethodOutputs', + max_keep_data=2, + method_path='toy_module.ToyClass.random_int')) + + manager = DistillDeliveryManager(distill_deliveries) + + manager.override_data = False + self.assertFalse(manager.override_data) + with manager: + toy_class = ToyClass() + output1_tea = toy_class.random_int() + output2_tea = toy_class.random_int() + + with self.assertRaisesRegex(AssertionError, 'push into an full queue'): + with manager: + _ = toy_class.random_int() + + self.assertFalse(manager.override_data) + manager.override_data = True + self.assertTrue(manager.override_data) + with manager: + output1_stu = toy_class.random_int() + output2_stu = toy_class.random_int() + + # With ``DistillDeliverManager``, outputs of the teacher and + # the student are the same. + assert output1_stu == output1_tea and output2_stu == output2_tea + + with self.assertRaisesRegex(AssertionError, 'pop from an empty queue'): + with manager: + _ = toy_class.random_int() diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_function_outputs_deliver.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_function_outputs_deliver.py new file mode 100755 index 000000000..531e59795 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_function_outputs_deliver.py @@ -0,0 +1,163 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import logging +import os.path as osp +import tempfile +from unittest import TestCase +from unittest.mock import Mock + +import torch +import torch.nn as nn +from mmengine.evaluator import Evaluator +from mmengine.hooks import EMAHook +from mmengine.logging import MMLogger +from mmengine.model import BaseModel, ExponentialMovingAverage +from mmengine.optim import OptimWrapper +from mmengine.runner import Runner +from torch.utils.data import Dataset + +from mmrazor.models.task_modules import FunctionOutputsDelivery + + +class ToyModel(BaseModel): + + def __init__(self): + super().__init__() + self.linear = nn.Linear(2, 1) + # test FunctionOutputsDelivery when ema_hook is used + self.deliver = FunctionOutputsDelivery( + max_keep_data=2, func_path='toy_module.toy_func') + + def forward(self, inputs, data_sample, mode='tensor'): + labels = torch.stack(data_sample) + inputs = torch.stack(inputs) + with self.deliver: + outputs = self.linear(inputs) + if mode == 'tensor': + return outputs + elif mode == 'loss': + loss = (labels - outputs).sum() + outputs = dict(loss=loss) + return outputs + else: + return outputs + + +class DummyDataset(Dataset): + METAINFO = dict() # type: ignore + data = torch.randn(12, 2) + label = torch.ones(12) + + @property + def metainfo(self): + return self.METAINFO + + def __len__(self): + return self.data.size(0) + + def __getitem__(self, index): + return dict(inputs=self.data[index], data_sample=self.label[index]) + + +class TestFuncOutputsDeliver(TestCase): + + def setUp(self): + self.temp_dir = tempfile.TemporaryDirectory() + + def tearDown(self): + # `FileHandler` should be closed in Windows, otherwise we cannot + # delete the temporary directory + logging.shutdown() + MMLogger._instance_dict.clear() + self.temp_dir.cleanup() + + def test_init(self): + + with self.assertRaisesRegex(TypeError, 'func_path should be'): + _ = FunctionOutputsDelivery(max_keep_data=1, func_path=1) + + with self.assertRaisesRegex(AssertionError, 'func_path must have at '): + _ = FunctionOutputsDelivery(max_keep_data=1, func_path='toy_func') + + def test_context_manager(self): + import toy_module + + delivery = FunctionOutputsDelivery(max_keep_data=2, func_path='aaa.bb') + with self.assertRaisesRegex(ImportError, 'aaa is not imported'): + with delivery: + _ = toy_module.toy_func() + + delivery = FunctionOutputsDelivery( + max_keep_data=1, func_path='toy_module.bb') + with self.assertRaisesRegex(AssertionError, 'bb is not in toy_mod'): + with delivery: + _ = toy_module.toy_func() + + delivery = FunctionOutputsDelivery( + max_keep_data=1, func_path='toy_module.TOY_VAR') + with self.assertRaisesRegex(TypeError, 'TOY_VAR should be'): + with delivery: + _ = toy_module.toy_func() + + delivery = FunctionOutputsDelivery( + max_keep_data=2, func_path='toy_module.toy_func') + + delivery.override_data = False + with delivery: + output1_tea = toy_module.toy_func() + output2_tea = toy_module.toy_func() + + with self.assertRaisesRegex(AssertionError, 'push into an full queue'): + with delivery: + _ = toy_module.toy_func() + + delivery.override_data = True + with delivery: + output1_stu = toy_module.toy_func() + output2_stu = toy_module.toy_func() + + # With ``FunctionOutputsDeliver``, outputs of the teacher and + # the student are the same. + assert output1_stu == output1_tea and output2_stu == output2_tea + + with self.assertRaisesRegex(AssertionError, 'pop from an empty queue'): + with delivery: + _ = toy_module.toy_func() + + def test_ema_hook(self): + device = 'cuda:0' if torch.cuda.is_available() else 'cpu' + model = ToyModel().to(device) + evaluator = Evaluator([]) + evaluator.evaluate = Mock(return_value=dict(acc=0.5)) + runner = Runner( + model=model, + train_dataloader=dict( + dataset=DummyDataset(), + sampler=dict(type='DefaultSampler', shuffle=True), + batch_size=3, + num_workers=0), + val_dataloader=dict( + dataset=DummyDataset(), + sampler=dict(type='DefaultSampler', shuffle=False), + batch_size=3, + num_workers=0), + val_evaluator=evaluator, + work_dir=self.temp_dir.name, + default_scope='mmrazor', + optim_wrapper=OptimWrapper( + torch.optim.Adam(ToyModel().parameters())), + train_cfg=dict(by_epoch=True, max_epochs=2, val_interval=1), + val_cfg=dict(), + default_hooks=dict(logger=None), + custom_hooks=[dict(type='EMAHook', )], + experiment_name='test_func_outputs_deliver') + runner.train() + for hook in runner.hooks: + if isinstance(hook, EMAHook): + self.assertTrue( + isinstance(hook.ema_model, ExponentialMovingAverage)) + + self.assertTrue( + osp.exists(osp.join(self.temp_dir.name, 'epoch_2.pth'))) + checkpoint = torch.load(osp.join(self.temp_dir.name, 'epoch_2.pth')) + self.assertTrue('ema_state_dict' in checkpoint) + self.assertTrue(checkpoint['ema_state_dict']['steps'] == 8) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_method_outputs_deliver.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_method_outputs_deliver.py new file mode 100755 index 000000000..a76967977 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/test_method_outputs_deliver.py @@ -0,0 +1,70 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +from mmrazor.models.task_modules import MethodOutputsDelivery + + +class TestMethodOutputsDeliver(TestCase): + + def test_init(self): + with self.assertRaisesRegex(TypeError, 'method_path should be'): + _ = MethodOutputsDelivery(max_keep_data=1, method_path=1) + + with self.assertRaisesRegex(AssertionError, + 'method_path must have at '): + _ = MethodOutputsDelivery(max_keep_data=1, method_path='toy_func') + + with self.assertRaisesRegex(ImportError, 'aaa is not imported'): + _ = MethodOutputsDelivery(max_keep_data=1, method_path='aaa.bb.b') + + with self.assertRaisesRegex(AssertionError, 'bb is not in toy_module'): + _ = MethodOutputsDelivery( + max_keep_data=1, method_path='toy_module.bb.bbb') + + with self.assertRaisesRegex(TypeError, 'toy_func should be a type'): + _ = MethodOutputsDelivery( + max_keep_data=1, method_path='toy_module.toy_func.bbb') + + with self.assertRaisesRegex(AssertionError, 'bbb is not in'): + _ = MethodOutputsDelivery( + max_keep_data=1, method_path='toy_module.ToyClass.bbb') + + with self.assertRaisesRegex(TypeError, 'count should be'): + _ = MethodOutputsDelivery( + max_keep_data=1, method_path='toy_module.ToyClass.count') + + def test_context_manager(self): + from toy_module import ToyClass + + delivery = MethodOutputsDelivery( + max_keep_data=2, method_path='toy_module.ToyClass.random_int') + + # Without ``MethodOutputsDelivery``, outputs of the teacher and the + # student are very likely to be different. + # from toy_module import ToyClass + # toy_class = ToyClass() + # output_tea = toy_class.random_int() + # output_stu = toy_class.random_int() + + delivery.override_data = False + with delivery: + toy_class = ToyClass() + output1_tea = toy_class.random_int() + output2_tea = toy_class.random_int() + + with self.assertRaisesRegex(AssertionError, 'push into an full queue'): + with delivery: + _ = toy_class.random_int() + + delivery.override_data = True + with delivery: + output1_stu = toy_class.random_int() + output2_stu = toy_class.random_int() + + # With ``MethodOutputsDeliver``, outputs of the teacher and the + # student are the same. + assert output1_stu == output1_tea and output2_stu == output2_tea + + with self.assertRaisesRegex(AssertionError, 'pop from an empty queue'): + with delivery: + _ = toy_class.random_int() diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/toy_module.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/toy_module.py new file mode 100755 index 000000000..2bca28d52 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_delivers/toy_module.py @@ -0,0 +1,25 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import random + +TOY_VAR = 'aaa' + + +def toy_func(): + return random.randint(0, 1000) + + +class ToyClass: + + def __init__(self): + self._count = 0 + + def random_int(self): + return random.randint(0, 1000) + + @property + def count(self): + return self._count + + def __call__(self): + self._count += 1 + return self._count diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_flow.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_flow.py new file mode 100755 index 000000000..87dee6747 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_flow.py @@ -0,0 +1,80 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest + +from mmrazor.structures.graph.channel_flow import ChannelElem, ChannelTensor + + +class TestChannelTensor(unittest.TestCase): + + def test_union(self): + tensor1 = ChannelTensor(8) + tensor2 = ChannelTensor(8) + tensor3 = ChannelTensor(8) + tensor4 = ChannelTensor(8) + + ChannelTensor.union_two(tensor1, tensor2) + ChannelTensor.union_two(tensor3, tensor4) + self.assertUionedTensor(tensor1, tensor2) + self.assertUionedTensor(tensor3, tensor4) + + ChannelTensor.union_two(tensor1, tensor4) + + self.assertUionedTensor(tensor1, tensor2) + self.assertUionedTensor(tensor2, tensor3) + self.assertUionedTensor(tensor3, tensor4) + self.assertUionedTensor(tensor1, tensor4) + + def test_cat(self): + tensor1 = ChannelTensor(8) + tensor2 = ChannelTensor(8) + tensor3 = ChannelTensor(16) + + tensor_cat = ChannelTensor.cat([tensor1, tensor2]) + self.assertEqual(len(tensor_cat), 16) + ChannelTensor.union_two(tensor_cat, tensor3) + + tensor31 = tensor3[:8] + tensor32 = tensor3[8:] + self.assertUionedTensor(tensor1, tensor31) + self.assertUionedTensor(tensor2, tensor32) + + def test_add_cat(self): + """8+8 && 4+12 -> 4+4+8.""" + tensor1 = ChannelTensor(8) + tensor2 = ChannelTensor(8) + tensor_cat1 = ChannelTensor.cat([tensor1, tensor2]) + + tensor3 = ChannelTensor(4) + tensor4 = ChannelTensor(12) + tensor_cat2 = ChannelTensor.cat([tensor3, tensor4]) + + ChannelTensor.union_two(tensor_cat1, tensor_cat2) + self.assertUionedTensor(tensor_cat1, tensor_cat2) + + self.assertUionedTensor(tensor_cat1[0:4], tensor3[0:4]) + self.assertUionedTensor(tensor_cat1[4:8], tensor4[0:4]) + self.assertUionedTensor(tensor_cat1[8:16], tensor4[4:12]) + + self.assertUionedTensor(tensor_cat2[0:4], tensor1[0:4]) + self.assertUionedTensor(tensor_cat2[4:8], tensor1[4:8]) + self.assertUionedTensor(tensor_cat2[8:], tensor2) + + def assertUionedTensor(self, tensor1: ChannelTensor, + tensor2: ChannelTensor): + assert len(tensor1) == len(tensor2) + for e1, e2 in zip(tensor1, tensor2): + self.assertEqual(e1.root, e2.root) + + +class TestChannelElem(unittest.TestCase): + + def test_union(self): + tensor = ChannelTensor(10) + elem1 = tensor[1] + elem2 = tensor[2] + ChannelElem.union_two(elem1, elem2) + self.assertEqual(elem1.root, elem2.root) + + elem3 = tensor[3] + ChannelElem.union_two(elem2, elem3) + self.assertEqual(elem1.root, elem3.root) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_graph.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_graph.py new file mode 100755 index 000000000..d6f1c3ffa --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_channel_graph.py @@ -0,0 +1,74 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest + +import torch +from torch import nn + +from mmrazor.models.task_modules import BackwardTracer +from mmrazor.registry import TASK_UTILS +from mmrazor.structures.graph import ModuleGraph +from mmrazor.structures.graph.channel_graph import ChannelGraph +from mmrazor.structures.graph.channel_nodes import \ + default_channel_node_converter +from ...data.models import SingleLineModel + +NodeMap = {} + + +@TASK_UTILS.register_module() +class ImageClassifierPseudoLossWithSixChannel: + """Calculate the pseudo loss to trace the topology of a `ImageClassifier` + in MMClassification with `BackwardTracer`.""" + + def __call__(self, model) -> torch.Tensor: + pseudo_img = torch.rand(1, 6, 224, 224) + pseudo_output = model(pseudo_img) + return sum(pseudo_output) + + +class TestChannelGraph(unittest.TestCase): + + def test_init(self): + model = SingleLineModel() + module_graph = ModuleGraph.init_from_backward_tracer(model) + + _ = ChannelGraph.copy_from(module_graph, + default_channel_node_converter) + + # def test_forward(self): + # for model_data in BackwardPassedModelManager.include_models( # noqa + # ): # noqa + # with self.subTest(model=model_data): + # model = model_data() + # module_graph = ModuleGraph.init_from_backward_tracer(model) + + # channel_graph = ChannelGraph.copy_from( + # module_graph, default_channel_node_converter) + # channel_graph.forward() + + # # units = channel_graph.collect_units() + # _ = channel_graph.generate_units_config() + + def test_forward_with_config_num_in_channel(self): + + class MyModel(nn.Module): + + def __init__(self) -> None: + super().__init__() + self.conv1 = nn.Conv2d(6, 3, 3, 1, 1) + self.net = SingleLineModel() + + def forward(self, x): + return self.net(self.conv1(x)) + + model = MyModel() + module_graph = ModuleGraph.init_from_backward_tracer( + model, + backward_tracer=BackwardTracer( + loss_calculator=ImageClassifierPseudoLossWithSixChannel())) + + channel_graph = ChannelGraph.copy_from(module_graph, + default_channel_node_converter) + channel_graph.forward(num_input_channel=6) + + _ = channel_graph.generate_units_config diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_graph.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_graph.py new file mode 100755 index 000000000..14df464c8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_graph.py @@ -0,0 +1,31 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import sys +from unittest import TestCase + +import torch + +sys.setrecursionlimit(int(1e8)) + +DEVICE = torch.device('cpu') + + +class TestGraph(TestCase): + pass + # def test_init_from_fx_tracer(self) -> None: + # TestData = BackwardPassedModelManager.include_models() + # with SetTorchThread(1): + # with mp.Pool() as p: + # result = p.map(_test_init_from_fx_tracer, TestData) + # for res, model in zip(result, TestData): + # with self.subTest(model=model): + # self.assertTrue(res[0], res[1]) + + # def test_init_from_backward_tracer(self) -> None: + # TestData = FxPassedModelManager.include_models() + # with SetTorchThread(1) as _: + # with mp.Pool() as p: + # result = p.map(_test_init_from_backward_tracer, TestData) + # for res, model in zip(result, TestData): + # # test_init_from_backward_tracer(model) + # with self.subTest(model=model): + # self.assertTrue(res[0], res[1]) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_prune_tracer_model.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_prune_tracer_model.py new file mode 100755 index 000000000..9d459a6d9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_graph/test_prune_tracer_model.py @@ -0,0 +1,193 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import multiprocessing as mp +import os +import signal +import sys +import time +from concurrent.futures import ProcessPoolExecutor +from contextlib import contextmanager +from functools import partial +from unittest import TestCase + +import torch +from mmengine import MMLogger + +from mmrazor.models.task_modules.tracer.channel_analyzer import ChannelAnalyzer +from ...data.model_library import ModelGenerator +from ...data.tracer_passed_models import (PassedModelManager, + backward_passed_library, + fx_passed_library) +from ...utils import SetTorchThread + +sys.setrecursionlimit(int(pow(2, 20))) +# test config + +DEVICE = torch.device('cpu') +FULL_TEST = os.getenv('FULL_TEST') == 'true' +try: + MP = int(os.getenv('MP')) +except Exception: + MP = 1 + +DEBUG = os.getenv('DEBUG') == 'true' +if DEBUG: + import logging + logger = MMLogger.get_current_instance() + logger.handlers[0].setLevel(logging.DEBUG) + logger.setLevel(logging.DEBUG) + +if MP > 1: + POOL_SIZE = MP + TORCH_THREAD_SIZE = mp.cpu_count() // POOL_SIZE + torch.set_num_interop_threads(TORCH_THREAD_SIZE) +else: + POOL_SIZE = 1 + TORCH_THREAD_SIZE = -1 + +print(f'DEBUG: {DEBUG}') +print(f'FULL_TEST: {FULL_TEST}') +print(f'POOL_SIZE: {POOL_SIZE}') +print(f'TORCH_THREAD_SIZE: {TORCH_THREAD_SIZE}') + +# tools for tesing + +# test functions for mp + + +@contextmanager +def time_limit(seconds, msg='', activated=(not DEBUG)): + + class TimeoutException(Exception): + pass + + def signal_handler(signum, frame): + if activated: + raise TimeoutException(f'{msg} run over {seconds} s!') + + signal.signal(signal.SIGALRM, signal_handler) + signal.alarm(seconds) + try: + yield + finally: + signal.alarm(0) + + +def _test_a_model(Model, tracer_type='fx'): + start = time.time() + + try: + print(f'test {Model}.') + model = Model.init_model() + model.eval() + if tracer_type == 'fx': + tracer_type = 'FxTracer' + elif tracer_type == 'backward': + tracer_type = 'BackwardTracer' + else: + raise NotImplementedError() + + tracer = ChannelAnalyzer( + tracer_type=tracer_type, + demo_input={ + 'type': 'DefaultDemoInput', + 'scope': Model.scope + }) + with time_limit(60): + unit_configs = tracer.analyze(model) + + out = len(unit_configs) + print(f'test {Model} successful.') + + return Model.name, True, '', time.time() - start, out + except Exception as e: + if DEBUG: + raise e + else: + print(f'test {Model} failed.') + return Model.name, False, f'{e}', time.time() - start, -1 + + +# TestCase + + +class TestTraceModel(TestCase): + + def test_init_from_fx_tracer(self) -> None: + from mmrazor import digit_version + if digit_version(torch.__version__) < digit_version('1.12.0'): + self.skipTest('version of torch < 1.12.0') + TestData = fx_passed_library.include_models(FULL_TEST) + + with SetTorchThread(TORCH_THREAD_SIZE): + if POOL_SIZE != 1: + with ProcessPoolExecutor(POOL_SIZE) as p: + result = p.map( + partial(_test_a_model, tracer_type='fx'), TestData) + + else: + result = map( + partial(_test_a_model, tracer_type='fx'), TestData) + result = list(result) + self.report(result, fx_passed_library, 'fx') + + def test_init_from_backward_tracer(self) -> None: + TestData = backward_passed_library.include_models(FULL_TEST) + with SetTorchThread(TORCH_THREAD_SIZE): + if POOL_SIZE != 1: + with ProcessPoolExecutor(POOL_SIZE) as p: + result = p.map( + partial(_test_a_model, tracer_type='backward'), + TestData) + else: + result = map( + partial(_test_a_model, tracer_type='fx'), TestData) + self.report(result, backward_passed_library, 'backward') + + def report(self, result, model_manager: PassedModelManager, fx_type='fx'): + print() + print(f'Trace model summary using {fx_type} tracer.') + + passd_test = [res for res in result if res[1] is True] + unpassd_test = [res for res in result if res[1] is False] + + # long summary + + print(f'{len(passd_test)},{len(unpassd_test)},' + f'{len(model_manager.uninclude_models(full_test=FULL_TEST))}') + + print('Passed:') + print('\tmodel\ttime\tlen(mutable)') + for model, passed, msg, used_time, out in passd_test: + with self.subTest(model=model): + print(f'\t{model}\t{int(used_time)}s\t{out}') + self.assertTrue(passed, msg) + + print('UnPassed:') + for model, passed, msg, used_time, out in unpassd_test: + with self.subTest(model=model): + print(f'\t{model}\t{int(used_time)}s\t{out}') + print(f'\t\t{msg}') + self.assertTrue(passed, msg) + + print('UnTest:') + untest_models = model_manager.uninclude_models(full_test=FULL_TEST) + for model in untest_models: + print(f'\t{model}') + + # short summary + short_passed = set( + [ModelGenerator.get_short_name(res[0]) for res in passd_test]) + + short_unpassed = set( + [ModelGenerator.get_short_name(res[0]) for res in unpassd_test]) + + short_untest = set([model.short_name for model in untest_models]) + + for name in short_unpassed: + if name in short_passed: + short_passed.remove(name) + + print('Short Summary:') + print('Passed\n', short_passed) + print('Unpassed\n', short_unpassed) + print('Untest\n', short_untest) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_base_recorder.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_base_recorder.py new file mode 100755 index 000000000..15faf5d95 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_base_recorder.py @@ -0,0 +1,50 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +from toy_mod import Toy + +from mmrazor.models.task_modules import MethodOutputsRecorder + + +class TestFuncOutputsRecorder(TestCase): + + def test_get_record_data(self): + + toy = Toy() + + recorder = MethodOutputsRecorder('toy_mod.Toy.toy_func') + recorder.initialize() + + with recorder: + res0 = toy.toy_func() + res1 = toy.toy_func() + + self.assertEquals(res0, recorder.get_record_data(record_idx=0)) + self.assertEquals(res1, recorder.get_record_data(record_idx=1)) + + with self.assertRaisesRegex( + AssertionError, + 'record_idx is illegal. The length of data_buffer is 2, ' + 'but record_idx is 2'): + _ = recorder.get_record_data(record_idx=2) + + with self.assertRaisesRegex( + TypeError, + 'When data_idx is not None, record should be a list or ' + 'tuple instance'): + _ = recorder.get_record_data(data_idx=0) + + recorder = MethodOutputsRecorder('toy_mod.Toy.toy_list_func') + recorder.initialize() + + with recorder: + res = toy.toy_list_func() + + self.assertEqual(len(res), 3) + + with self.assertRaisesRegex( + AssertionError, + 'data_idx is illegal. The length of record is 3'): + _ = recorder.get_record_data(data_idx=3) + + self.assertEquals(res[2], recorder.get_record_data(data_idx=2)) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_inputs_recorder.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_inputs_recorder.py new file mode 100755 index 000000000..6fa9655a1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_inputs_recorder.py @@ -0,0 +1,138 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import logging +import os.path as osp +import tempfile +from unittest import TestCase +from unittest.mock import Mock + +import torch +import torch.nn as nn +from mmengine.evaluator import Evaluator +from mmengine.hooks import EMAHook +from mmengine.logging import MMLogger +from mmengine.model import BaseModel, ExponentialMovingAverage +from mmengine.optim import OptimWrapper +from mmengine.runner import Runner +from torch.utils.data import Dataset + +from mmrazor.models.task_modules import FunctionInputsRecorder, RecorderManager + + +class ToyModel(BaseModel): + + def __init__(self): + super().__init__() + self.linear = nn.Linear(2, 1) + # test FunctionInputsRecorder when ema_hook is used + recorders_cfg = dict( + out=dict(type='FunctionInputs', source='toy_mod.toy_func')) + self.recorders = RecorderManager(recorders_cfg) + self.recorders.initialize(self) + + def forward(self, inputs, data_sample, mode='tensor'): + labels = torch.stack(data_sample) + inputs = torch.stack(inputs) + with self.recorders: + outputs = self.linear(inputs) + if mode == 'tensor': + return outputs + elif mode == 'loss': + loss = (labels - outputs).sum() + outputs = dict(loss=loss) + return outputs + else: + return outputs + + +class DummyDataset(Dataset): + METAINFO = dict() # type: ignore + data = torch.randn(12, 2) + label = torch.ones(12) + + @property + def metainfo(self): + return self.METAINFO + + def __len__(self): + return self.data.size(0) + + def __getitem__(self, index): + return dict(inputs=self.data[index], data_sample=self.label[index]) + + +class TestFuncInputsRecorder(TestCase): + + def setUp(self): + self.temp_dir = tempfile.TemporaryDirectory() + + def tearDown(self): + # `FileHandler` should be closed in Windows, otherwise we cannot + # delete the temporary directory + logging.shutdown() + MMLogger._instance_dict.clear() + self.temp_dir.cleanup() + + def test_context_manager(self): + from toy_mod import execute_toy_func2 as execute_toy_func + + recorder = FunctionInputsRecorder('toy_mod.toy_func2') + recorder.initialize() + + with recorder: + execute_toy_func(1, 2) + execute_toy_func(1, b=2) + execute_toy_func(b=2, a=1) + + self.assertTrue( + recorder.get_record_data(record_idx=0, data_idx=0) == 1) + self.assertTrue( + recorder.get_record_data(record_idx=0, data_idx=1) == 2) + + self.assertTrue( + recorder.get_record_data(record_idx=1, data_idx=0) == 1) + self.assertTrue( + recorder.get_record_data(record_idx=1, data_idx=1) == 2) + + self.assertTrue( + recorder.get_record_data(record_idx=2, data_idx=0) == 1) + self.assertTrue( + recorder.get_record_data(record_idx=2, data_idx=1) == 2) + + def test_ema_hook(self): + device = 'cuda:0' if torch.cuda.is_available() else 'cpu' + model = ToyModel().to(device) + evaluator = Evaluator([]) + evaluator.evaluate = Mock(return_value=dict(acc=0.5)) + runner = Runner( + model=model, + train_dataloader=dict( + dataset=DummyDataset(), + sampler=dict(type='DefaultSampler', shuffle=True), + batch_size=3, + num_workers=0), + val_dataloader=dict( + dataset=DummyDataset(), + sampler=dict(type='DefaultSampler', shuffle=False), + batch_size=3, + num_workers=0), + val_evaluator=evaluator, + work_dir=self.temp_dir.name, + default_scope='mmrazor', + optim_wrapper=OptimWrapper( + torch.optim.Adam(ToyModel().parameters())), + train_cfg=dict(by_epoch=True, max_epochs=2, val_interval=1), + val_cfg=dict(), + default_hooks=dict(logger=None), + custom_hooks=[dict(type='EMAHook', )], + experiment_name='test_func_inputs_recorder') + runner.train() + for hook in runner.hooks: + if isinstance(hook, EMAHook): + self.assertTrue( + isinstance(hook.ema_model, ExponentialMovingAverage)) + + self.assertTrue( + osp.exists(osp.join(self.temp_dir.name, 'epoch_2.pth'))) + checkpoint = torch.load(osp.join(self.temp_dir.name, 'epoch_2.pth')) + self.assertTrue('ema_state_dict' in checkpoint) + self.assertTrue(checkpoint['ema_state_dict']['steps'] == 8) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_outputs_recorder.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_outputs_recorder.py new file mode 100755 index 000000000..1d6561495 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_func_outputs_recorder.py @@ -0,0 +1,51 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +from mmrazor.models.task_modules import FunctionOutputsRecorder + + +class TestFuncOutputsRecorder(TestCase): + + def test_init(self): + + _ = FunctionOutputsRecorder('toy_mod.toy_func') + + with self.assertRaisesRegex(TypeError, 'source should be'): + _ = FunctionOutputsRecorder([1]) + + with self.assertRaisesRegex(AssertionError, 'source must have at '): + _ = FunctionOutputsRecorder('aaaaa') + + def test_context_manager(self): + from toy_mod import execute_toy_func + + recorder = FunctionOutputsRecorder('aaa.bbb') + recorder.initialize() + with self.assertRaisesRegex(ImportError, 'aaa is not imported'): + with recorder: + execute_toy_func(1) + + recorder = FunctionOutputsRecorder('toy_mod.aaa') + recorder.initialize() + with self.assertRaisesRegex(AssertionError, 'aaa is not in toy_mod'): + with recorder: + execute_toy_func(1) + + recorder = FunctionOutputsRecorder('toy_mod.TOY_VAR') + recorder.initialize() + with self.assertRaisesRegex(TypeError, 'TOY_VAR should be'): + with recorder: + execute_toy_func(1) + + recorder = FunctionOutputsRecorder('toy_mod.toy_func') + recorder.initialize() + + with recorder: + execute_toy_func(1) + + data = recorder.get_record_data() + self.assertTrue(data == 1) + + execute_toy_func(1) + data = recorder.get_record_data() + self.assertTrue(data == 1) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_inputs_recorder.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_inputs_recorder.py new file mode 100755 index 000000000..7450a231c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_inputs_recorder.py @@ -0,0 +1,35 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +from mmrazor.models.task_modules import MethodInputsRecorder + + +class TestFuncOutputsRecorder(TestCase): + + def test_context_manager(self): + from toy_mod import ToyClass + + toy = ToyClass() + + recorder = MethodInputsRecorder('toy_mod.ToyClass.func') + recorder.initialize() + + with recorder: + _ = toy.func(x=1, y=2) + _ = toy.func(1, y=2) + _ = toy.func(y=2, x=1) + + self.assertTrue( + recorder.get_record_data(record_idx=0, data_idx=0) == 1) + self.assertTrue( + recorder.get_record_data(record_idx=0, data_idx=1) == 2) + + self.assertTrue( + recorder.get_record_data(record_idx=1, data_idx=0) == 1) + self.assertTrue( + recorder.get_record_data(record_idx=1, data_idx=1) == 2) + + self.assertTrue( + recorder.get_record_data(record_idx=2, data_idx=0) == 1) + self.assertTrue( + recorder.get_record_data(record_idx=2, data_idx=1) == 2) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_outputs_recorder.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_outputs_recorder.py new file mode 100755 index 000000000..83fdbc3c0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_method_outputs_recorder.py @@ -0,0 +1,55 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +from mmrazor.models.task_modules import MethodOutputsRecorder + + +class TestFuncOutputsRecorder(TestCase): + + def test_init(self): + + _ = MethodOutputsRecorder('toy_mod.ToyClass.toy') + + with self.assertRaisesRegex(TypeError, 'source should be'): + _ = MethodOutputsRecorder([1]) + + with self.assertRaisesRegex(AssertionError, 'source must have at '): + _ = MethodOutputsRecorder('aaaaa') + + with self.assertRaisesRegex(AssertionError, 'source must have at '): + _ = MethodOutputsRecorder('aaa.bbb') + + with self.assertRaisesRegex(ImportError, 'aaa is not imported'): + _ = MethodOutputsRecorder('aaa.bbb.ccc') + + with self.assertRaisesRegex(AssertionError, 'aaa is not in toy_mod'): + _ = MethodOutputsRecorder('toy_mod.aaa.bbb') + + with self.assertRaisesRegex(TypeError, 'toy_func should be'): + _ = MethodOutputsRecorder('toy_mod.toy_func.bbb') + + with self.assertRaisesRegex(AssertionError, 'bbb is not in ToyClass'): + _ = MethodOutputsRecorder('toy_mod.ToyClass.bbb') + + with self.assertRaisesRegex(TypeError, 'TOY_CLS should be'): + _ = MethodOutputsRecorder('toy_mod.ToyClass.TOY_CLS') + + def test_context_manager(self): + from toy_mod import ToyClass + + toy = ToyClass() + + recorder = MethodOutputsRecorder('toy_mod.ToyClass.toy') + recorder.initialize() + + with recorder: + result = toy.toy() + + data = recorder.get_record_data() + self.assertTrue(data == result) + + result_ = toy.toy() + + data = recorder.get_record_data() + self.assertTrue(data == result) + self.assertFalse(result_ == result) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_module_recorders.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_module_recorders.py new file mode 100755 index 000000000..c267903ca --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_module_recorders.py @@ -0,0 +1,75 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch +from torch import nn + +from mmrazor.models.task_modules import (ModuleInputsRecorder, + ModuleOutputsRecorder) + + +class ToyModel(nn.Module): + + def __init__(self): + super().__init__() + self.conv1 = nn.Conv2d(1, 1, 1) + self.conv2 = nn.Conv2d(1, 1, 1) + + def forward(self, x): + return self.conv2(self.conv1(x)) + + +class TestModuleOutputsRecorder(TestCase): + + def test_prepare_from_model(self): + + recorder = ModuleOutputsRecorder('conv1') + with self.assertRaisesRegex(AssertionError, 'model can not be'): + recorder.prepare_from_model() + + recorder = ModuleOutputsRecorder('conv3') + model = ToyModel() + with self.assertRaisesRegex(AssertionError, '"conv3" is not in'): + recorder.prepare_from_model(model) + + recorder = ModuleOutputsRecorder('conv2') + model = ToyModel() + recorder.prepare_from_model(model) + + def test_module_outputs(self): + + recorder = ModuleOutputsRecorder('conv2') + model = ToyModel() + recorder.initialize(model) + + with recorder: + self.assertTrue(recorder.recording) + res = model(torch.randn(1, 1, 1, 1)) + + self.assertEquals(res, recorder.get_record_data()) + + with recorder: + self.assertTrue(len(recorder.data_buffer) == 0) + + _ = model(torch.randn(1, 1, 1, 1)) + self.assertTrue(len(recorder.data_buffer) == 0) + + def test_module_intputs(self): + + recorder = ModuleInputsRecorder('conv1') + model = ToyModel() + recorder.initialize(model) + + tensor = torch.randn(1, 1, 1, 1) + with recorder: + self.assertTrue(recorder.recording) + _ = model(tensor) + + conv1_input = recorder.get_record_data(data_idx=0) + self.assertEquals(conv1_input.sum(), tensor.sum()) + + with recorder: + self.assertTrue(len(recorder.data_buffer) == 0) + + _ = model(torch.randn(1, 1, 1, 1)) + self.assertTrue(len(recorder.data_buffer) == 0) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_param_recorder.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_param_recorder.py new file mode 100755 index 000000000..e604bdf97 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_param_recorder.py @@ -0,0 +1,42 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch +from torch import nn + +from mmrazor.models.task_modules import ParameterRecorder + + +class ToyModel(nn.Module): + + def __init__(self): + super().__init__() + self.toy_conv = nn.Conv2d(1, 1, 1) + self.no_record_conv = nn.Conv2d(1, 1, 1) + + def forward(self, x): + return self.toy_conv(x) + + +class TestParameterRecorder(TestCase): + + def test_prepare_from_model(self): + + model = ToyModel() + recorder = ParameterRecorder('AAA') + with self.assertRaisesRegex(AssertionError, '"AAA" is not in the'): + recorder.initialize(model) + + recorder = ParameterRecorder('toy_conv.bias') + with self.assertRaisesRegex(AssertionError, 'model can not be None'): + recorder.prepare_from_model() + + recorder.initialize(model) + bias_weight = recorder.get_record_data() + + self.assertEquals(bias_weight, model.toy_conv.bias) + + with recorder: + _ = model(torch.randn(1, 1, 1, 1)) + + self.assertEquals(bias_weight, model.toy_conv.bias) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_recorder_manager.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_recorder_manager.py new file mode 100755 index 000000000..beab7477c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/test_recorder_manager.py @@ -0,0 +1,58 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch +from mmengine import ConfigDict +from torch import nn +from toy_mod import Toy + +from mmrazor.models.task_modules import RecorderManager + + +class ToyModel(nn.Module): + + def __init__(self): + super().__init__() + self.conv1 = nn.Conv2d(1, 1, 1) + self.conv2 = nn.Conv2d(1, 1, 1) + self.toy = Toy() + + def forward(self, x): + return self.conv2(self.conv1(x)) + self.toy.toy_func() + + +class TestRecorderManager(TestCase): + + def test_init(self): + + manager = RecorderManager() + self.assertEquals(len(manager.recorders), 0) + + recorders = ConfigDict( + r1=dict(type='ModuleOutputs', source='conv1'), + r2=dict(type='MethodOutputs', source='toy_mod.Toy.toy_func'), + ) + manager = RecorderManager(recorders) + model = ToyModel() + manager.initialize(model) + + def test_context_manager(self): + + recorders = ConfigDict( + r1=dict(type='ModuleOutputs', source='conv2'), + r2=dict(type='MethodOutputs', source='toy_mod.Toy.toy_func'), + ) + manager = RecorderManager(recorders) + model = ToyModel() + manager.initialize(model) + + self.assertEquals(manager.get_recorder('r1'), manager.recorders['r1']) + self.assertEquals(manager.get_recorder('r2'), manager.recorders['r2']) + + with manager: + res = model(torch.ones(1, 1, 1, 1)) + + method_outputs = manager.recorders['r2'].get_record_data() + conv2_outputs = manager.recorders['r1'].get_record_data() + + self.assertEquals(res.sum(), method_outputs + conv2_outputs.sum()) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/toy_mod.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/toy_mod.py new file mode 100755 index 000000000..0df3e2d70 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_recorders/toy_mod.py @@ -0,0 +1,56 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import random + +TOY_VAR = 'aaa' + + +def toy_func(a): + return a + + +def toy_func2(a, b): + return a, b + + +def toy_list_func(a): + return [a, a, a] + + +def execute_toy_func(a): + toy_func(a) + + +def execute_toy_func2(a, b): + toy_func2(a, b) + + +def execute_toy_list_func(a): + toy_list_func(a) + + +class ToyClass: + + TOY_CLS = 'TOY_CLASS' + + def __init__(self): + self._count = 0 + + def toy(self): + self._count += 1 + return self._count + + def func(self, x, y=0): + return x + y + + def __call__(self): + self._count += 1 + return self._count + + +class Toy(): + + def toy_func(self): + return random.randint(0, 1000) + + def toy_list_func(self): + return [random.randint(0, 1000) for _ in range(3)] diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_backward_tracer.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_backward_tracer.py new file mode 100755 index 000000000..55ddaccc0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_backward_tracer.py @@ -0,0 +1,309 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch +from torch import Tensor, nn +from torch.nn import Module + +from mmrazor.models.task_modules import (BackwardTracer, Path, PathConcatNode, + PathConvNode, PathDepthWiseConvNode, + PathLinearNode, PathList, + PathNormNode) + +NONPASS_NODES = (PathConvNode, PathLinearNode, PathConcatNode) +PASS_NODES = (PathNormNode, PathDepthWiseConvNode) + + +class MultiConcatModel(Module): + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.op2 = nn.Conv2d(3, 8, 1) + self.op3 = nn.Conv2d(16, 8, 1) + self.op4 = nn.Conv2d(3, 8, 1) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.op1(x) + x2 = self.op2(x) + cat1 = torch.cat([x1, x2], dim=1) + x3 = self.op3(cat1) + x4 = self.op4(x) + output = torch.cat([x3, x4], dim=1) + + return output + + +class MultiConcatModel2(Module): + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.op2 = nn.Conv2d(3, 8, 1) + self.op3 = nn.Conv2d(3, 8, 1) + self.op4 = nn.Conv2d(24, 8, 1) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.op1(x) + x2 = self.op2(x) + x3 = self.op3(x) + cat1 = torch.cat([x1, x2], dim=1) + cat2 = torch.cat([cat1, x3], dim=1) + output = self.op4(cat2) + + return output + + +class MultiConcatModel3(Module): + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.op2 = nn.Conv2d(3, 8, 1) + self.op3 = nn.Conv2d(3, 8, 1) + self.op4 = nn.Conv2d(24, 8, 1) + self.op5 = nn.Conv2d(24, 8, 1) + self.op6 = nn.Conv2d(24, 8, 1) + self.op7 = nn.Conv2d(24, 8, 1) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.op1(x) + x2 = self.op2(x) + x3 = self.op3(x) + cat1 = torch.cat([x1, x2, x3], dim=1) + x4 = self.op4(cat1) + x5 = self.op5(cat1) + x6 = self.op6(cat1) + x7 = self.op7(cat1) + return torch.cat([x4, x5, x6, x7], dim=1) + + +class ResBlock(Module): + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.bn1 = nn.BatchNorm2d(8) + self.op2 = nn.Conv2d(8, 8, 1) + self.bn2 = nn.BatchNorm2d(8) + self.op3 = nn.Conv2d(8, 8, 1) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.bn1(self.op1(x)) + x2 = self.bn2(self.op2(x1)) + x3 = self.op3(x2 + x1) + return x3 + + +class ToyCNNPseudoLoss: + + def __init__(self, input_shape=(2, 3, 16, 16)): + self.input_shape = input_shape + + def __call__(self, model): + pseudo_img = torch.rand(self.input_shape) + pseudo_output = model(pseudo_img) + return pseudo_output.sum() + + +class TestBackwardTracer(TestCase): + + def test_trace_resblock(self) -> None: + model = ResBlock() + loss_calculator = ToyCNNPseudoLoss() + tracer = BackwardTracer(loss_calculator=loss_calculator) + path_list = tracer.trace(model) + + # test tracer and parser + assert len(path_list) == 2 + assert len(path_list[0]) == 5 + + # test path_list + nonpass2parents = path_list.find_nodes_parents(NONPASS_NODES) + assert len(nonpass2parents) == 3 + assert nonpass2parents['op1'] == list() + assert nonpass2parents['op2'] == list({PathNormNode('bn1')}) + assert nonpass2parents['op3'] == list( + {PathNormNode('bn2'), PathNormNode('bn1')}) + + nonpass2nonpassparents = path_list.find_nodes_parents( + NONPASS_NODES, non_pass=NONPASS_NODES) + assert len(nonpass2parents) == 3 + assert nonpass2nonpassparents['op1'] == list() + assert nonpass2nonpassparents['op2'] == list({PathConvNode('op1')}) + assert nonpass2nonpassparents['op3'] == list( + {PathConvNode('op2'), PathConvNode('op1')}) + + pass2nonpassparents = path_list.find_nodes_parents( + PASS_NODES, non_pass=NONPASS_NODES) + assert len(pass2nonpassparents) == 2 + assert pass2nonpassparents['bn1'] == list({PathConvNode('op1')}) + assert pass2nonpassparents['bn2'] == list({PathConvNode('op2')}) + + def test_trace_multi_cat(self) -> None: + loss_calculator = ToyCNNPseudoLoss() + + model = MultiConcatModel() + tracer = BackwardTracer(loss_calculator=loss_calculator) + path_list = tracer.trace(model) + + assert len(path_list) == 1 + + nonpass2parents = path_list.find_nodes_parents(NONPASS_NODES) + assert len(nonpass2parents) == 4 + assert nonpass2parents['op1'] == list() + assert nonpass2parents['op2'] == list() + path_list1 = PathList(Path(PathConvNode('op1'))) + path_list2 = PathList(Path(PathConvNode('op2'))) + # only one parent + assert len(nonpass2parents['op3']) == 1 + assert isinstance(nonpass2parents['op3'][0], PathConcatNode) + assert len(nonpass2parents['op3'][0]) == 2 + assert nonpass2parents['op3'][0].get_module_names() == ['op1', 'op2'] + assert nonpass2parents['op3'][0].path_lists == [path_list1, path_list2] + assert nonpass2parents['op3'][0][0] == path_list1 + assert nonpass2parents['op4'] == list() + + model = MultiConcatModel2() + tracer = BackwardTracer(loss_calculator=loss_calculator) + path_list = tracer.trace(model) + assert len(path_list) == 1 + + nonpass2parents = path_list.find_nodes_parents(NONPASS_NODES) + assert len(nonpass2parents) == 4 + assert nonpass2parents['op1'] == list() + assert nonpass2parents['op2'] == list() + assert nonpass2parents['op3'] == list() + # only one parent + assert len(nonpass2parents['op4']) == 1 + assert isinstance(nonpass2parents['op4'][0], PathConcatNode) + assert nonpass2parents['op4'][0].get_module_names() == [ + 'op1', 'op2', 'op3' + ] + + model = MultiConcatModel3() + tracer = BackwardTracer(loss_calculator=loss_calculator) + path_list = tracer.trace(model) + assert len(path_list) == 1 + + nonpass2parents = path_list.find_nodes_parents(NONPASS_NODES) + assert nonpass2parents['op1'] == list() + assert nonpass2parents['op2'] == list() + assert nonpass2parents['op3'] == list() + assert nonpass2parents['op4'] == nonpass2parents['op5'] == \ + nonpass2parents['op6'] == nonpass2parents['op7'] + + def test_repr(self): + toy_node = PathConvNode('op1') + assert repr(toy_node) == 'PathConvNode(\'op1\')' + + toy_path = Path([PathConvNode('op1'), PathConvNode('op2')]) + assert repr( + toy_path + ) == 'Path(\n PathConvNode(\'op1\'),\n PathConvNode(\'op2\')\n)' + + toy_path_list = PathList(Path(PathConvNode('op1'))) + assert repr( + toy_path_list + ) == 'PathList(\n Path(\n PathConvNode(\'op1\')\n )\n)' + + path_list1 = PathList(Path(PathConvNode('op1'))) + path_list2 = PathList(Path(PathConvNode('op2'))) + toy_concat_node = PathConcatNode('op3', [path_list1, path_list2]) + assert repr( + toy_concat_node + ) == 'PathConcatNode(\n PathList(\n Path(\n PathConvNode(\'op1\')\n )\n ),\n PathList(\n Path(\n PathConvNode(\'op2\')\n )\n )\n)' # noqa: E501 + + def test_reset_bn_running_stats(self): + _test_reset_bn_running_stats(False) + with pytest.raises(AssertionError): + _test_reset_bn_running_stats(True) + + def test_node(self): + node1 = PathConvNode('conv1') + node2 = PathConvNode('conv2') + assert node1 != node2 + + node1 = PathConvNode('conv1') + node2 = PathConvNode('conv1') + assert node1 == node2 + + def test_path(self): + node1 = PathConvNode('conv1') + node2 = PathConvNode('conv2') + + path1 = Path([node1]) + path2 = Path([node2]) + assert path1 != path2 + + path1 = Path([node1]) + path2 = Path([node1]) + assert path1 == path2 + + assert path1[0] == node1 + + def test_path_list(self): + node1 = PathConvNode('conv1') + node2 = PathConvNode('conv2') + + path1 = Path([node1]) + path2 = Path([node2]) + assert PathList(path1) == PathList([path1]) + assert PathList(path1) != PathList(path2) + + with self.assertRaisesRegex(AssertionError, ''): + _ = PathList({}) + + def test_sum_pseudo_loss(self): + model = ResBlock() + tracer = BackwardTracer(loss_calculator={'type': 'SumPseudoLoss'}) + path = tracer.trace(model) + print(path) + + +def _test_reset_bn_running_stats(should_fail): + import os + import random + + import numpy as np + + def set_seed(seed: int) -> None: + random.seed(seed) + os.environ['PYTHONHASHSEED'] = str(seed) + np.random.seed(seed) + torch.manual_seed(seed) + + set_seed(1024) + imgs = torch.randn(2, 3, 4, 4) + loss_calculator = ToyCNNPseudoLoss() + tracer = BackwardTracer(loss_calculator=loss_calculator) + if should_fail: + tracer._reset_norm_running_stats = lambda *_: None + + torch_rng_state = torch.get_rng_state() + np_rng_state = np.random.get_state() + random_rng_state = random.getstate() + + model1 = ResBlock() + set_seed(1) + tracer.trace(model1) + model1.eval() + output1 = model1(imgs) + + set_seed(1024) + torch.set_rng_state(torch_rng_state) + np.random.set_state(np_rng_state) + random.setstate(random_rng_state) + + model2 = ResBlock() + set_seed(2) + tracer.trace(model2) + model2.eval() + output2 = model2(imgs) + + assert torch.equal(output1.norm(p='fro'), output2.norm(p='fro')) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_fx_tracer.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_fx_tracer.py new file mode 100755 index 000000000..544f2aab8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_fx_tracer.py @@ -0,0 +1,68 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest +from functools import partial + +from mmcls.models.classifiers.image import ImageClassifier + +from mmrazor.utils import get_placeholder + +try: + from torch.fx.graph_module import GraphModule +except ImportError: + GraphModule = get_placeholder('torch>=1.12') +import torch + +from mmrazor import digit_version +from mmrazor.models.task_modules.demo_inputs import DefaultDemoInput +from mmrazor.models.task_modules.tracer.fx_tracer import FxTracer +from ...data.models import UntracableModel + +MODELS = [ + UntracableModel, + partial( + ImageClassifier, + backbone=dict(type='mmrazor.UntracableBackBone'), + head=dict( + type='mmrazor.LinearHeadForTest', + in_channel=16, + )), +] + + +class TestFxTracer(unittest.TestCase): + + def test_model(self): + if digit_version(torch.__version__) < digit_version('1.12.0'): + self.skipTest('version of torch < 1.12.0') + + for Model in MODELS: + with self.subTest(model=Model): + model = Model() + + tracer = FxTracer() + demo_input = DefaultDemoInput() + inputs = demo_input.get_data(model) + + if isinstance(inputs, dict): + # args = copy.copy(inputs) + # args.pop('inputs') + # args['mode'] = 'tensor' + args = {'mode': 'tensor'} + torch_graph = tracer.trace(model, concrete_args=args) + else: + torch_graph = tracer.trace(model) + print(model) + + print(torch_graph) + + graph_module = GraphModule(model, torch_graph) + print(graph_module) + print(graph_module.code) + + inputs = demo_input.get_data(model) + if isinstance(inputs, dict): + inputs['mode_1'] = inputs['mode'] + inputs.pop('mode') + graph_module(**inputs) + else: + graph_module(inputs) diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_loss_calculator.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_loss_calculator.py new file mode 100755 index 000000000..a567c002c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_loss_calculator.py @@ -0,0 +1,39 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch +from mmengine.hub import get_model + +from mmrazor.models.task_modules.tracer import (ImageClassifierPseudoLoss, + SingleStageDetectorPseudoLoss, + SumPseudoLoss) + + +class TestLossCalculator(TestCase): + + def test_image_classifier_pseudo_loss(self): + model = get_model( + 'mmcls::resnet/resnet34_8xb32_in1k.py', pretrained=False) + loss_calculator = ImageClassifierPseudoLoss() + loss = loss_calculator(model) + assert isinstance(loss, torch.Tensor) and loss.dim() == 0 + + def test_single_stage_detector_pseudo_loss(self): + model = get_model( + 'mmdet::retinanet/retinanet_r50_fpn_1x_coco.py', pretrained=False) + loss_calculator = SingleStageDetectorPseudoLoss() + loss = loss_calculator(model) + assert isinstance(loss, torch.Tensor) and loss.dim() == 0 + + def test_sumloss(self): + model = get_model( + 'mmdet::retinanet/retinanet_r50_fpn_1x_coco.py', pretrained=False) + loss_calculator = SumPseudoLoss() + loss = loss_calculator(model) + assert isinstance(loss, torch.Tensor) and loss.dim() == 0 + + model = get_model( + 'mmcls::resnet/resnet34_8xb32_in1k.py', pretrained=False) + loss_calculator = SumPseudoLoss() + loss = loss_calculator(model) + assert isinstance(loss, torch.Tensor) and loss.dim() == 0 diff --git a/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_prune_tracer.py b/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_prune_tracer.py new file mode 100755 index 000000000..63674350d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_core/test_tracer/test_prune_tracer.py @@ -0,0 +1,25 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch + +from mmrazor import digit_version +from mmrazor.models.task_modules.tracer import ChannelAnalyzer +from ...data.models import SingleLineModel + + +class TestChannelAnalyzer(TestCase): + + def test_backward_tracer(self): + model = SingleLineModel() + tracer = ChannelAnalyzer(tracer_type='BackwardTracer') + unit_configs = tracer.analyze(model) + print(unit_configs) + + def test_fx_tracer(self): + if digit_version(torch.__version__) < digit_version('1.12.0'): + self.skipTest('torch<1.12.0') + model = SingleLineModel() + tracer = ChannelAnalyzer(tracer_type='FxTracer') + unit_configs = tracer.analyze(model) + print(unit_configs) diff --git a/cv/distiller/CWD/mmrazor/tests/test_data.py b/cv/distiller/CWD/mmrazor/tests/test_data.py new file mode 100755 index 000000000..df3e07f69 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_data.py @@ -0,0 +1,93 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import unittest + +import torch + +from .data.model_library import (DefaultModelLibrary, MMClsModelLibrary, + MMDetModelLibrary, MMModelLibrary, + MMPoseModelLibrary, MMSegModelLibrary, + ModelGenerator, TorchModelLibrary) +from .data.models import SingleLineModel +from .data.tracer_passed_models import (BackwardPassedModelManager, + FxPassedModelManager) + +TEST_DATA = os.getenv('TEST_DATA') == 'true' + + +class TestModelLibrary(unittest.TestCase): + + def test_mmcls(self): + if not TEST_DATA: + self.skipTest('not test data to save time.') + library = MMClsModelLibrary(exclude=['cutmax', 'cifar']) + self.assertTrue(library.is_default_includes_cover_all_models()) + + def test_defaul_library(self): + if not TEST_DATA: + self.skipTest('not test data to save time.') + library = DefaultModelLibrary() + self.assertTrue(library.is_default_includes_cover_all_models()) + + def test_torchlibrary(self): + if not TEST_DATA: + self.skipTest('not test data to save time.') + library = TorchModelLibrary() + self.assertTrue(library.is_default_includes_cover_all_models()) + + def test_mmdet(self): + if not TEST_DATA: + self.skipTest('not test data to save time.') + library = MMDetModelLibrary() + self.assertTrue(library.is_default_includes_cover_all_models()) + + def test_mmseg(self): + if not TEST_DATA: + self.skipTest('not test data to save time.') + library = MMSegModelLibrary() + print(library.short_names()) + + self.assertTrue(library.is_default_includes_cover_all_models()) + + # New + def test_mmpose(self): + if not TEST_DATA: + self.skipTest('not test data to save time.') + library = MMPoseModelLibrary() + print(library.short_names()) + self.assertTrue(library.is_default_includes_cover_all_models()) + + def test_get_model_by_config(self): + config = 'mmcls::resnet/resnet34_8xb32_in1k.py' + Model = MMModelLibrary.get_model_from_path(config) + _ = Model() + + def test_passed_models(self): + try: + print(FxPassedModelManager().include_models()) + print(BackwardPassedModelManager().include_models()) + except Exception: + self.fail() + + +class TestModels(unittest.TestCase): + + def _test_a_model(self, Model): + model = Model() + x = torch.rand(2, 3, 224, 224) + y = model(x) + self.assertSequenceEqual(y.shape, [2, 1000]) + + def test_models(self): + library = DefaultModelLibrary() + for Model in library.include_models(): + with self.subTest(model=Model): + self._test_a_model(Model) + + def test_generator(self): + Model = ModelGenerator('model', SingleLineModel) + model = Model() + model.eval() + self.assertEqual(model.training, False) + model.train() + self.assertEqual(model.training, True) diff --git a/cv/distiller/CWD/mmrazor/tests/test_datasets/test_datasets.py b/cv/distiller/CWD/mmrazor/tests/test_datasets/test_datasets.py new file mode 100755 index 000000000..1eaf72ec8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_datasets/test_datasets.py @@ -0,0 +1,88 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import os.path as osp +import pickle +import tempfile +from unittest import TestCase + +import numpy as np +from mmcls.registry import DATASETS as CLS_DATASETS + +from mmrazor.registry import DATASETS +from mmrazor.utils import register_all_modules + +register_all_modules() +ASSETS_ROOT = osp.abspath(osp.join(osp.dirname(__file__), '../data/dataset')) + + +class Test_CRD_CIFAR10(TestCase): + ORI_DATASET_TYPE = 'CIFAR10' + DATASET_TYPE = 'CRDDataset' + + @classmethod + def setUpClass(cls) -> None: + super().setUpClass() + + tmpdir = tempfile.TemporaryDirectory() + cls.tmpdir = tmpdir + data_prefix = tmpdir.name + cls.ORI_DEFAULT_ARGS = dict( + data_prefix=data_prefix, pipeline=[], test_mode=False) + cls.DEFAULT_ARGS = dict(neg_num=1, percent=0.5) + + dataset_class = CLS_DATASETS.get(cls.ORI_DATASET_TYPE) + base_folder = osp.join(data_prefix, dataset_class.base_folder) + os.mkdir(base_folder) + + cls.fake_imgs = np.random.randint( + 0, 255, size=(6, 3 * 32 * 32), dtype=np.uint8) + cls.fake_labels = np.random.randint(0, 10, size=(6, )) + cls.fake_classes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + batch1 = dict( + data=cls.fake_imgs[:2], labels=cls.fake_labels[:2].tolist()) + with open(osp.join(base_folder, 'data_batch_1'), 'wb') as f: + f.write(pickle.dumps(batch1)) + + batch2 = dict( + data=cls.fake_imgs[2:4], labels=cls.fake_labels[2:4].tolist()) + with open(osp.join(base_folder, 'data_batch_2'), 'wb') as f: + f.write(pickle.dumps(batch2)) + + test_batch = dict( + data=cls.fake_imgs[4:], fine_labels=cls.fake_labels[4:].tolist()) + with open(osp.join(base_folder, 'test_batch'), 'wb') as f: + f.write(pickle.dumps(test_batch)) + + meta = {dataset_class.meta['key']: cls.fake_classes} + meta_filename = dataset_class.meta['filename'] + with open(osp.join(base_folder, meta_filename), 'wb') as f: + f.write(pickle.dumps(meta)) + + dataset_class.train_list = [['data_batch_1', None], + ['data_batch_2', None]] + dataset_class.test_list = [['test_batch', None]] + dataset_class.meta['md5'] = None + + def test_initialize(self): + dataset_class = DATASETS.get(self.DATASET_TYPE) + + # Test overriding metainfo by `metainfo` argument + ori_cfg = { + **self.ORI_DEFAULT_ARGS, 'metainfo': { + 'classes': ('bus', 'car') + }, + 'type': self.ORI_DATASET_TYPE, + '_scope_': 'mmcls' + } + cfg = {'dataset': ori_cfg, **self.DEFAULT_ARGS} + dataset = dataset_class(**cfg) + self.assertEqual(dataset.dataset.CLASSES, ('bus', 'car')) + + @classmethod + def tearDownClass(cls): + cls.tmpdir.cleanup() + + +class Test_CRD_CIFAR100(Test_CRD_CIFAR10): + ORI_DATASET_TYPE = 'CIFAR100' diff --git a/cv/distiller/CWD/mmrazor/tests/test_datasets/test_transforms/test_formatting.py b/cv/distiller/CWD/mmrazor/tests/test_datasets/test_transforms/test_formatting.py new file mode 100755 index 000000000..69e211aad --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_datasets/test_transforms/test_formatting.py @@ -0,0 +1,56 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os.path as osp +import unittest + +import numpy as np +import torch +from mmcls.structures import ClsDataSample +from mmengine.structures import LabelData + +from mmrazor.datasets.transforms import PackCRDClsInputs + + +class TestPackClsInputs(unittest.TestCase): + + def setUp(self): + """Setup the model and optimizer which are used in every test method. + + TestCase calls functions in this order: setUp() -> testMethod() -> + tearDown() -> cleanUp() + """ + data_prefix = osp.join(osp.dirname(__file__), '../../data') + img_path = osp.join(data_prefix, 'color.jpg') + rng = np.random.RandomState(0) + self.results1 = { + 'sample_idx': 1, + 'img_path': img_path, + 'ori_height': 300, + 'ori_width': 400, + 'height': 600, + 'width': 800, + 'scale_factor': 2.0, + 'flip': False, + 'img': rng.rand(300, 400), + 'gt_label': rng.randint(3, ), + # TODO. + 'contrast_sample_idxs': rng.randint(3, ) + } + self.meta_keys = ('sample_idx', 'img_path', 'ori_shape', 'img_shape', + 'scale_factor', 'flip') + + def test_transform(self): + transform = PackCRDClsInputs(meta_keys=self.meta_keys) + results = transform(copy.deepcopy(self.results1)) + self.assertIn('inputs', results) + self.assertIsInstance(results['inputs'], torch.Tensor) + self.assertIn('data_samples', results) + self.assertIsInstance(results['data_samples'], ClsDataSample) + + data_sample = results['data_samples'] + self.assertIsInstance(data_sample.gt_label, LabelData) + + def test_repr(self): + transform = PackCRDClsInputs(meta_keys=self.meta_keys) + self.assertEqual( + repr(transform), f'PackCRDClsInputs(meta_keys={self.meta_keys})') diff --git a/cv/distiller/CWD/mmrazor/tests/test_doc.py b/cv/distiller/CWD/mmrazor/tests/test_doc.py new file mode 100755 index 000000000..275b9ecec --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_doc.py @@ -0,0 +1,32 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +from unittest import TestCase + +import nbformat +from nbconvert.preprocessors import ExecutePreprocessor + +TEST_DOC = os.getenv('TEST_DOC') == 'true' +notebook_paths = [ + './mmrazor/models/mutators/channel_mutator/channel_mutator.ipynb', + './mmrazor/models/mutables/mutable_channel/units/mutable_channel_unit.ipynb', # noqa + './demo/config_pruning.ipynb' +] + + +class TestDocs(TestCase): + + def setUp(self) -> None: + if not TEST_DOC: + self.skipTest('disabled') + + def test_notebooks(self): + for path in notebook_paths: + with self.subTest(path=path): + with open(path) as file: + nb_in = nbformat.read(file, nbformat.NO_CONVERT) + ep = ExecutePreprocessor( + timeout=600, kernel_name='python3') + try: + _ = ep.preprocess(nb_in) + except Exception: + self.fail() diff --git a/cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_stop_distillation_hook.py b/cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_stop_distillation_hook.py new file mode 100755 index 000000000..49e753b64 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_stop_distillation_hook.py @@ -0,0 +1,26 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase +from unittest.mock import Mock + +from mmrazor.engine import StopDistillHook + + +class TestStopDistillHook(TestCase): + + def setUp(self): + self.hook = StopDistillHook(stop_epoch=5) + runner = Mock() + runner.model = Mock() + runner.model.distillation_stopped = False + + runner.epoch = 0 + self.runner = runner + + def test_before_train_epoch(self): + max_epochs = 10 + target = [False] * 5 + [True] * 5 + for epoch in range(max_epochs): + self.hook.before_train_epoch(self.runner) + self.assertEquals(self.runner.model.distillation_stopped, + target[epoch]) + self.runner.epoch += 1 diff --git a/cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_visualization_hook.py b/cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_visualization_hook.py new file mode 100755 index 000000000..64004843a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_engine/test_hooks/test_visualization_hook.py @@ -0,0 +1,129 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import os.path as osp +import shutil +import time +from os.path import dirname +from typing import Optional +from unittest import TestCase +from unittest.mock import Mock + +import torch +import torch.nn as nn +# TODO: The argument `out_file` has not been supported in MMEngine yet. +# Temporarily, we use `ClsVisualizer` here +from mmcls.visualization import ClsVisualizer +from mmengine import ConfigDict +from mmengine.model import BaseModel + +from mmrazor.engine.hooks import RazorVisualizationHook + + +def get_data_info(idx): + root_path = dirname(dirname(dirname(dirname(__file__)))) + return { + 'img_path': os.path.join(root_path, 'tools/visualizations/demo.jpg') + } + + +class ToyModel(BaseModel): + + def __init__(self): + data_preprocessor = dict( + type='mmcls.ClsDataPreprocessor', + # RGB format normalization parameters + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + # convert image from BGR to RGB + to_rgb=True, + ) + super().__init__(data_preprocessor=data_preprocessor) + self.op = nn.Conv2d(3, 3, 1) + + def forward(self, + inputs: torch.Tensor, + data_samples: Optional[list] = None, + mode: str = 'tensor'): + out = self.op(inputs) + return out + + +class TestVisualizationHook(TestCase): + + def setUp(self) -> None: + # TODO: The argument `out_file` has not been supported in MMEngine yet. + # Temporarily, we use `ClsVisualizer` here + ClsVisualizer.get_instance('visualizer') + + test_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='Resize', scale=(1333, 800), keep_ratio=True), + dict(type='mmcls.PackClsInputs') + ] + + self.runner = Mock() + self.runner.val_loop.dataloader.dataset.get_data_info = get_data_info + self.runner.cfg = ConfigDict( + test_dataloader=dict(dataset=dict(pipeline=test_pipeline))) + self.runner.model = ToyModel() + + self.recorders = ConfigDict( + out=dict(_scope_='mmrazor', type='ModuleOutputs', source='op')) + self.mappings = ConfigDict(out=dict(recorder='out')) + + def test_before_run(self): + hook = RazorVisualizationHook(self.recorders, self.mappings) + hook.before_run(self.runner) + + def test_before_train(self): + timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime()) + out_dir = timestamp + '1' + self.runner.work_dir = timestamp + self.runner.timestamp = '1' + self.runner.epoch = 0 + + hook = RazorVisualizationHook( + self.recorders, self.mappings, out_dir=out_dir, enabled=False) + # initialize recorders + hook.before_run(self.runner) + hook.before_train(self.runner) + self.assertTrue(not osp.exists(f'{timestamp}/1/{out_dir}')) + + hook = RazorVisualizationHook( + self.recorders, self.mappings, out_dir=out_dir, enabled=True) + # initialize recorders + hook.before_run(self.runner) + hook.before_train(self.runner) + self.assertTrue(osp.exists(f'{timestamp}/1/{out_dir}')) + shutil.rmtree(f'{timestamp}') + + def test_after_train_epoch(self): + timestamp = time.strftime('%Y%m%d_%H%M%S', time.localtime()) + out_dir = timestamp + '1' + self.runner.work_dir = timestamp + self.runner.timestamp = '1' + + hook = RazorVisualizationHook( + self.recorders, self.mappings, out_dir=out_dir, enabled=False) + # initialize recorders + hook.before_run(self.runner) + self.runner.epoch = 0 + hook.after_train_epoch(self.runner) + self.assertTrue(not osp.exists(f'{timestamp}/1/{out_dir}')) + + self.runner.epoch = 1 + hook = RazorVisualizationHook( + self.recorders, + self.mappings, + out_dir=out_dir, + enabled=True, + interval=2) + # initialize recorders + hook.before_run(self.runner) + hook.after_train_epoch(self.runner) + self.assertTrue(not osp.exists(f'{timestamp}/1/{out_dir}')) + + self.runner.epoch = 2 + hook.after_train_epoch(self.runner) + self.assertTrue(osp.exists(f'{timestamp}/1/{out_dir}')) + shutil.rmtree(f'{timestamp}') diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_impl/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_impl/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_algorithm.py b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_algorithm.py new file mode 100755 index 000000000..ec2707282 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_algorithm.py @@ -0,0 +1,68 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch +from mmcls.structures import ClsDataSample +from mmengine import MessageHub + +from mmrazor.implementations.pruning.group_fisher.algorithm import \ + GroupFisherAlgorithm +from mmrazor.implementations.pruning.group_fisher.ops import GroupFisherConv2d +from ....data.models import MMClsResNet18 + +if torch.cuda.is_available(): + DEVICE = torch.device('cuda:0') +else: + DEVICE = torch.device('cpu') + + +class TestGroupFisherPruneAlgorithm(TestCase): + + def fake_cifar_data(self): + imgs = torch.randn(16, 3, 32, 32).to(DEVICE) + data_samples = [ + ClsDataSample().set_gt_label(torch.randint(0, 10, + (16, ))).to(DEVICE) + ] + + return {'inputs': imgs, 'data_samples': data_samples} + + def test_group_fisher_prune(self): + data = self.fake_cifar_data() + + MUTATOR_CONFIG = dict( + type='GroupFisherChannelMutator', + parse_cfg=dict( + type='ChannelAnalyzer', tracer_type='BackwardTracer'), + channel_unit_cfg=dict(type='GroupFisherChannelUnit')) + + epoch = 2 + interval = 1 + + algorithm = GroupFisherAlgorithm( + MMClsResNet18(), mutator=MUTATOR_CONFIG, + interval=interval).to(DEVICE) + mutator = algorithm.mutator + + for e in range(epoch): + for ite in range(10): + self._set_epoch_ite(e, ite, epoch) + algorithm.forward( + data['inputs'], data['data_samples'], mode='loss') + self.gen_fake_grad(mutator) + self.assertEqual(interval, algorithm.interval) + + def gen_fake_grad(self, mutator): + for unit in mutator.mutable_units: + for channel in unit.input_related: + module = channel.module + if isinstance(module, GroupFisherConv2d): + module.recorded_grad = module.recorded_input + + def _set_epoch_ite(self, epoch, ite, max_epoch): + iter_per_epoch = 10 + message_hub = MessageHub.get_current_instance() + message_hub.update_info('epoch', epoch) + message_hub.update_info('max_epochs', max_epoch) + message_hub.update_info('max_iters', max_epoch * 10) + message_hub.update_info('iter', ite + iter_per_epoch * epoch) diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_deploy_sub_model.py b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_deploy_sub_model.py new file mode 100755 index 000000000..7ae819bf8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_deploy_sub_model.py @@ -0,0 +1,56 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +from unittest import TestCase + +import torch +from mmengine import fileio + +from mmrazor import digit_version +from mmrazor.implementations.pruning.group_fisher.prune_deploy_sub_model import \ + GroupFisherDeploySubModel # noqa +from ....data.models import MMClsResNet18 +from .test_prune_sub_model import PruneAlgorithm, get_model_structure + + +class TestPruneDeploySubModel(TestCase): + + def check_torch_version(self): + if digit_version(torch.__version__) < digit_version('1.12.0'): + self.skipTest('version of torch < 1.12.0') + + def test_build_sub_model(self): + self.check_torch_version() + model = MMClsResNet18() + + parse_cfg = dict( + _scope_='mmrazor', + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer') + # get structure + algorithm = PruneAlgorithm(copy.deepcopy(model)) + algorithm.random_prune() + strucutrue = algorithm.mutator.current_choices + + # test divisor + wrapper = GroupFisherDeploySubModel( + copy.deepcopy(model), strucutrue, divisor=1, parse_cfg=parse_cfg) + self.assertSequenceEqual( + list(strucutrue.values()), + list(get_model_structure(wrapper).values())) + + wrapper = GroupFisherDeploySubModel( + copy.deepcopy(model), strucutrue, divisor=8, parse_cfg=parse_cfg) + self.assertSequenceEqual( + list(strucutrue.values()), + list(get_model_structure(wrapper).values())) + + mutable_path = os.path.dirname(__file__) + '/mutable.json' + fileio.dump(algorithm.mutator.current_choices, mutable_path) + GroupFisherDeploySubModel( + copy.deepcopy(model), + divisor=1, + mutable_cfg=mutable_path, + parse_cfg=parse_cfg) + os.remove(mutable_path) diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_sub_model.py b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_sub_model.py new file mode 100755 index 000000000..bb85b71a6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_prune_sub_model.py @@ -0,0 +1,70 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Dict, Union +from unittest import TestCase + +import torch + +from mmrazor import digit_version +from mmrazor.implementations.pruning.group_fisher.prune_sub_model import \ + GroupFisherSubModel +from mmrazor.models import BaseAlgorithm +from mmrazor.models.mutators import ChannelMutator +from mmrazor.registry import MODELS +from ....data.models import MMClsResNet18 + + +class PruneAlgorithm(BaseAlgorithm): + + def __init__(self, + architecture, + mutator: Union[Dict, ChannelMutator] = dict( + type='ChannelMutator', + channel_unit_cfg=dict( + type='SequentialMutableChannelUnit')), + data_preprocessor=None, + init_cfg=None) -> None: + super().__init__( + architecture, data_preprocessor, init_cfg, module_inplace=False) + if isinstance(mutator, dict): + mutator = MODELS.build(mutator) + assert isinstance(mutator, ChannelMutator) + self.mutator = mutator + mutator.prepare_from_supernet(self.architecture) + + def random_prune(self): + choices = self.mutator.sample_choices() + self.mutator.set_choices(choices) + + +def get_model_structure(model): + algorithm = PruneAlgorithm(copy.deepcopy(model)) + return algorithm.mutator.current_choices + + +class TestPruneSubModel(TestCase): + + def check_torch_version(self): + if digit_version(torch.__version__) < digit_version('1.12.0'): + self.skipTest('version of torch < 1.12.0') + + def test_build_sub_model(self): + self.check_torch_version() + x = torch.rand([1, 3, 224, 224]) + model = MMClsResNet18() + algorithm = PruneAlgorithm(model) + algorithm.random_prune() + + # test divisor + static_model1 = GroupFisherSubModel(algorithm, divisor=1) + self.assertSequenceEqual( + list(algorithm.mutator.current_choices.values()), + list(get_model_structure(static_model1).values())) + + static_model2 = GroupFisherSubModel(algorithm, divisor=8) + for value in get_model_structure(static_model2).values(): + self.assertTrue(value % 8 == 0) + + y1 = static_model1(x) + y2 = static_model2(x) + self.assertTrue((y1 - y2).abs().max() < 1e-3) diff --git a/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_unit.py b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_unit.py new file mode 100755 index 000000000..712d2fb50 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_impl/test_pruning/test_group_fisher/test_unit.py @@ -0,0 +1,44 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest + +import torch + +from mmrazor.implementations.pruning.group_fisher import \ + GroupFisherChannelMutator +from ....data.models import MMClsResNet18 + + +class TestGroupFisherChannelUnit(unittest.TestCase): + + def test_init(self): + model = MMClsResNet18() + mutator = GroupFisherChannelMutator( + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer')) + mutator.prepare_from_supernet(model) + + x = torch.rand([1, 3, 224, 224]) + mutator.start_record_info() + for i in range(2): + model.train() + loss = model(x).sum() + loss.backward() + mutator.end_record_info() + + for unit in mutator.mutable_units: + for module in unit.input_related_dynamic_ops: + self.assertEqual(len(module.recorded_input), 2) + self.assertEqual(len(module.recorded_grad), 2) + self.assertIsInstance(module.recorded_grad[0], torch.Tensor) + + unit = mutator.mutable_units[0] + fisher = unit._fisher_of_a_module(next(unit.input_related_dynamic_ops)) + self.assertEqual(list(fisher.shape), [1, unit.num_channels]) + + fisher = unit.current_batch_fisher + self.assertEqual(list(fisher.shape), [unit.num_channels]) + + fisher = unit._get_normalized_fisher_info(fisher, unit.delta_type) + unit.update_fisher_info() diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoformer.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoformer.py new file mode 100755 index 000000000..2baa703fe --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoformer.py @@ -0,0 +1,73 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from unittest import TestCase + +import torch + +from mmrazor.models import Autoformer, NasMutator +from mmrazor.registry import MODELS + +arch_setting = dict( + mlp_ratios=[3.0, 3.5, 4.0], + num_heads=[8, 9, 10], + depth=[14, 15, 16], + embed_dims=[528, 576, 624]) + +MUTATOR_CFG = dict(type='NasMutator') + +ARCHITECTURE_CFG = dict( + _scope_='mmrazor', + type='SearchableImageClassifier', + backbone=dict( + _scope_='mmrazor', + type='AutoformerBackbone', + arch_setting=arch_setting), + neck=None, + head=dict( + type='DynamicLinearClsHead', + num_classes=1000, + in_channels=624, + loss=dict( + type='mmcls.LabelSmoothLoss', + mode='original', + num_classes=1000, + label_smooth_val=0.1, + loss_weight=1.0), + topk=(1, 5)), + connect_head=dict(connect_with_backbone='backbone.last_mutable'), +) + +ALGORITHM_CFG = dict( + type='mmrazor.Autoformer', + architecture=ARCHITECTURE_CFG, + mutator=MUTATOR_CFG) + + +class TestAutoFormer(TestCase): + + def test_init(self): + ALGORITHM_CFG_SUPERNET = copy.deepcopy(ALGORITHM_CFG) + # initiate autoformer with built `algorithm`. + autoformer_algo = MODELS.build(ALGORITHM_CFG_SUPERNET) + self.assertIsInstance(autoformer_algo, Autoformer) + self.assertIsInstance(autoformer_algo.mutator, NasMutator) + + # autoformer search_groups + random_subnet = autoformer_algo.mutator.sample_choices() + self.assertIsInstance(random_subnet, dict) + + # initiate autoformer without any `mutator`. + ALGORITHM_CFG_SUPERNET.pop('type') + ALGORITHM_CFG_SUPERNET['mutator'] = None + none_type = type(ALGORITHM_CFG_SUPERNET['mutator']) + with self.assertRaisesRegex( + TypeError, 'mutator should be a `dict` or `NasMutator` ' + f'instance, but got {none_type}.'): + _ = Autoformer(**ALGORITHM_CFG_SUPERNET) + + def test_loss(self): + # supernet + inputs = torch.randn(1, 3, 224, 224) + autoformer = MODELS.build(ALGORITHM_CFG) + loss = autoformer(inputs) + assert loss.size(1) == 1000 diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoslim.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoslim.py new file mode 100755 index 000000000..fed6ca5e0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_autoslim.py @@ -0,0 +1,195 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import unittest +from typing import Dict, List, Tuple, Union +from unittest import TestCase +from unittest.mock import Mock + +import pytest +import torch +import torch.distributed as dist +from mmcls.structures import ClsDataSample +from mmengine.optim import build_optim_wrapper + +from mmrazor import digit_version +from mmrazor.models.algorithms import AutoSlim, AutoSlimDDP + +MUTATOR_TYPE = Union[torch.nn.Module, Dict] +DISTILLER_TYPE = Union[torch.nn.Module, Dict] + +ARCHITECTURE_CFG = dict( + _scope_='mmcls', + type='ImageClassifier', + backbone=dict(type='MobileNetV2', widen_factor=1.5), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='mmcls.LinearClsHead', + num_classes=1000, + in_channels=1920, + loss=dict(type='mmcls.CrossEntropyLoss', loss_weight=1.0), + topk=(1, 5))) + +ONESHOT_MUTABLE_CFG = dict( + type='OneShotMutableChannel', + candidate_choices=[1 / 8, 2 / 8, 3 / 8, 4 / 8, 5 / 8, 6 / 8, 7 / 8, 1.0], + candidate_mode='ratio') +ONESHOT_MUTABLE_CFGS = dict( + in_features=ONESHOT_MUTABLE_CFG, + out_features=ONESHOT_MUTABLE_CFG, + in_channels=ONESHOT_MUTABLE_CFG, + out_channels=ONESHOT_MUTABLE_CFG, + num_features=ONESHOT_MUTABLE_CFG) + +MUTATOR_CFG = dict( + type='OneShotChannelMutator', + channel_unit_cfg=dict( + type='OneShotMutableChannelUnit', + default_args=dict( + candidate_choices=list(i / 12 for i in range(2, 13)), + choice_mode='ratio')), + parse_cfg=dict(type='ChannelAnalyzer')) + +DISTILLER_CFG = dict( + type='ConfigurableDistiller', + teacher_recorders=dict(fc=dict(type='ModuleOutputs', source='head.fc')), + student_recorders=dict(fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=1)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(recorder='fc', from_student=True), + preds_T=dict(recorder='fc', from_student=False)))) + +OPTIM_WRAPPER_CFG = dict( + optimizer=dict( + type='mmcls.SGD', + lr=0.5, + momentum=0.9, + weight_decay=4e-05, + _scope_='mmrazor'), + paramwise_cfg=dict( + bias_decay_mult=0.0, norm_decay_mult=0.0, dwconv_decay_mult=0.0), + clip_grad=None, + accumulative_counts=4) + + +class FakeMutator: + ... + + +class ToyDataPreprocessor(torch.nn.Module): + + def forward( + self, + data: Dict, + training: bool = True) -> Tuple[torch.Tensor, List[ClsDataSample]]: + return data + + +@unittest.skipIf( + digit_version(torch.__version__) == digit_version('1.8.1'), + 'PyTorch version 1.8.1 is not supported by the Backward Tracer.') +class TestAutoSlim(TestCase): + device: str = 'cpu' + + def _prepare_fake_data(self) -> Dict: + imgs = torch.randn(16, 3, 224, 224).to(self.device) + data_samples = [ + ClsDataSample().set_gt_label(torch.randint(0, 1000, + (16, ))).to(self.device) + ] + + return {'inputs': imgs, 'data_samples': data_samples} + + def prepare_model(self, + mutator_cfg: MUTATOR_TYPE = MUTATOR_CFG, + distiller_cfg: DISTILLER_TYPE = DISTILLER_CFG, + architecture_cfg: Dict = ARCHITECTURE_CFG, + num_random_samples: int = 2) -> AutoSlim: + model = AutoSlim( + mutator=mutator_cfg, + distiller=distiller_cfg, + architecture=architecture_cfg, + data_preprocessor=ToyDataPreprocessor(), + num_random_samples=num_random_samples) + model.to(self.device) + + return model + + def test_init(self) -> None: + mutator_wrong_type = FakeMutator() + with pytest.raises(Exception): + _ = self.prepare_model(mutator_wrong_type) + + algo = self.prepare_model() + self.assertSequenceEqual( + algo.mutator.mutable_units[0].candidate_choices, + list(i / 12 for i in range(2, 13)), + ) + + def test_autoslim_train_step(self) -> None: + algo = self.prepare_model() + data = self._prepare_fake_data() + optim_wrapper = build_optim_wrapper(algo, OPTIM_WRAPPER_CFG) + fake_message_hub = Mock() + fake_message_hub.runtime_info = {'iter': 0, 'max_iters': 100} + optim_wrapper.message_hub = fake_message_hub + assert not algo._optim_wrapper_count_status_reinitialized + losses = algo.train_step(data, optim_wrapper) + + assert len(losses) == 7 + assert losses['max_subnet.loss'] > 0 + assert losses['min_subnet.loss'] > 0 + assert losses['min_subnet.loss_kl'] + 1e-5 > 0 + assert losses['random0_subnet.loss'] > 0 + assert losses['random0_subnet.loss_kl'] + 1e-5 > 0 + assert losses['random1_subnet.loss'] > 0 + assert losses['random1_subnet.loss_kl'] + 1e-5 > 0 + + assert algo._optim_wrapper_count_status_reinitialized + assert optim_wrapper._inner_count == 4 + assert optim_wrapper._max_counts == 400 + + losses = algo.train_step(data, optim_wrapper) + assert algo._optim_wrapper_count_status_reinitialized + + +class TestAutoSlimDDP(TestAutoSlim): + + @classmethod + def setUpClass(cls) -> None: + os.environ['MASTER_ADDR'] = 'localhost' + os.environ['MASTER_PORT'] = '12355' + + # initialize the process group + if torch.cuda.is_available(): + backend = 'nccl' + cls.device = 'cuda' + else: + backend = 'gloo' + dist.init_process_group(backend, rank=0, world_size=1) + + def prepare_model(self, + mutator_cfg: MUTATOR_TYPE = MUTATOR_CFG, + distiller_cfg: DISTILLER_TYPE = DISTILLER_CFG, + architecture_cfg: Dict = ARCHITECTURE_CFG, + num_random_samples: int = 2) -> AutoSlim: + model = super().prepare_model( + mutator_cfg=mutator_cfg, + distiller_cfg=distiller_cfg, + architecture_cfg=architecture_cfg, + num_random_samples=num_random_samples) + + return AutoSlimDDP(module=model, find_unused_parameters=True) + + @classmethod + def tearDownClass(cls) -> None: + dist.destroy_process_group() + + @pytest.mark.skipif( + not torch.cuda.is_available(), reason='cuda device is not avaliable') + def test_init(self) -> None: + model = super().prepare_model() + ddp_model = AutoSlimDDP(module=model, device_ids=[0]) + + self.assertIsInstance(ddp_model, AutoSlimDDP) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_base_algorithm.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_base_algorithm.py new file mode 100755 index 000000000..502ed4f5e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_base_algorithm.py @@ -0,0 +1,124 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch +import torch.nn as nn +from mmengine.model import BaseDataPreprocessor, BaseModel + +from mmrazor.models import BaseAlgorithm +from mmrazor.models.task_modules import ModuleOutputsRecorder +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class CustomDataPreprocessor(BaseDataPreprocessor): + + def forward(self, data, training=False): + if training: + return 1 + else: + return 2 + + +@MODELS.register_module() +class ToyModel(BaseModel): + + def __init__(self, data_preprocessor=None): + super().__init__(data_preprocessor=data_preprocessor, init_cfg=None) + self.conv = nn.Conv2d(3, 1, 1) + self.bn = nn.BatchNorm2d(1) + self.relu = nn.ReLU(inplace=True) + + def forward(self, batch_inputs, data_samples=None, mode='tensor'): + if mode == 'loss': + out = self.relu(self.bn(self.conv(batch_inputs))) + return dict(loss=out) + elif mode == 'predict': + out = self.relu(self.bn(self.conv(batch_inputs) + 1)) + return out + elif mode == 'tensor': + out = self.relu(self.bn(self.conv(batch_inputs) + 2)) + return out + + +class TestBaseAlgorithm(TestCase): + + def test_init(self): + # initiate model without `data_preprocessor` + model = ToyModel() + alg = BaseAlgorithm(ToyModel()) + self.assertIsInstance(alg.data_preprocessor, BaseDataPreprocessor) + # self.assertIs(alg.data_preprocessor, model.data_preprocessor) + + # initiate model with unbuilt `data_preprocessor`. + data_preprocessor = dict(type='mmrazor.CustomDataPreprocessor') + alg = BaseAlgorithm(ToyModel(), data_preprocessor=data_preprocessor) + self.assertIsInstance(alg.data_preprocessor, CustomDataPreprocessor) + + # initiate algorithm with built `data_preprocessor`. + data_preprocessor = CustomDataPreprocessor() + alg = BaseAlgorithm( + ToyModel(data_preprocessor), data_preprocessor=data_preprocessor) + self.assertIs(alg.data_preprocessor, data_preprocessor) + self.assertIs(alg.data_preprocessor, + alg.architecture.data_preprocessor) + alg = BaseAlgorithm( + ToyModel(data_preprocessor), data_preprocessor=None) + self.assertIs(alg.data_preprocessor, data_preprocessor) + self.assertIs(alg.data_preprocessor, + alg.architecture.data_preprocessor) + + # initiate algorithm with built `model`. + model = ToyModel() + alg = BaseAlgorithm(model) + self.assertIs(alg.architecture, model) + + # initiate algorithm with unbuilt `model`. + model = dict(type='ToyModel') + alg = BaseAlgorithm(model) + self.assertIsInstance(alg.architecture, ToyModel) + + # initiate algorithm with error type `model`. + with self.assertRaisesRegex(TypeError, 'architecture should be'): + BaseAlgorithm(architecture=[model]) + + def test_forward(self): + + model = ToyModel() + alg = BaseAlgorithm(model) + + inputs = torch.randn(1, 3, 8, 8) + + loss = alg(inputs, mode='loss') + loss_ = alg.loss(inputs) + self.assertEqual(loss['loss'].sum(), loss_['loss'].sum()) + + predict = alg(inputs, mode='predict') + predict_ = alg._predict(inputs) + self.assertEqual(predict.sum(), predict_.sum()) + + tensor = alg(inputs, mode='tensor') + tensor_ = alg._forward(inputs) + self.assertEqual(tensor.sum(), tensor_.sum()) + + with self.assertRaisesRegex(RuntimeError, 'Invalid mode "A"'): + alg(inputs, mode='A') + + def test_set_module_inplace_false(self): + inputs = torch.randn(1, 3, 8, 8) + + model = ToyModel() + res_before = model(inputs) + _ = BaseAlgorithm(model) + + r1 = ModuleOutputsRecorder('bn') + r1.initialize(model) + with r1: + res_after = model(inputs) + self.assertIs(torch.equal(res_before, res_after), True) + + self.assertIs(model.relu.inplace, False) + + self.assertIs( + torch.equal(r1.data_buffer[0], model.bn(model.conv(inputs) + 2)), + True) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_bignas.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_bignas.py new file mode 100755 index 000000000..41ce4673d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_bignas.py @@ -0,0 +1,111 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from unittest import TestCase + +import torch + +from mmrazor.models import BigNAS, NasMutator +from mmrazor.registry import MODELS + +arch_setting = dict( + kernel_size=[ + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + ], + num_blocks=[ + [1, 2, 1], + [3, 6, 1], + [3, 6, 1], + [1, 2, 1], + ], + expand_ratio=[ + [1, 1, 1], + [4, 6, 1], + [4, 6, 1], + [4, 6, 1], + [4, 6, 1], + ], + num_out_channels=[ + [16, 24, 8], # first layer + [16, 24, 8], + [24, 32, 8], + [32, 40, 8], + [64, 72, 8], + [72, 72, 8], # last layer + ]) + +MUTATOR_CFG = dict(type='NasMutator') + +DISTILLER_CFG = dict( + _scope_='mmrazor', + type='ConfigurableDistiller', + teacher_recorders=dict(fc=dict(type='ModuleOutputs', source='head.fc')), + student_recorders=dict(fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=1)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(recorder='fc', from_student=True), + preds_T=dict(recorder='fc', from_student=False)))) + +ARCHITECTURE_CFG = dict( + type='mmrazor.SearchableImageClassifier', + backbone=dict( + type='mmrazor.AttentiveMobileNetV3', + arch_setting=arch_setting, + out_indices=(4, ), + conv_cfg=dict(type='mmrazor.BigNasConv2d'), + norm_cfg=dict(type='mmrazor.DynamicBatchNorm2d', momentum=0.0)), + neck=dict(type='mmcls.GlobalAveragePooling'), + head=dict( + _scope_='mmrazor', + type='DynamicLinearClsHead', + num_classes=1000, + in_channels=72, + loss=dict( + type='mmcls.LabelSmoothLoss', + mode='original', + num_classes=1000, + label_smooth_val=0.1, + loss_weight=1.0), + topk=(1, 5)), + connect_head=dict(connect_with_backbone='backbone.last_mutable_channels'), +) + +ALGORITHM_CFG = dict( + type='mmrazor.BigNAS', + architecture=ARCHITECTURE_CFG, + mutator=MUTATOR_CFG, + distiller=DISTILLER_CFG) + + +class TestBigNAS(TestCase): + + def test_init(self): + ALGORITHM_CFG_SUPERNET = copy.deepcopy(ALGORITHM_CFG) + # initiate bignas with built `algorithm`. + bignas_algo = MODELS.build(ALGORITHM_CFG_SUPERNET) + self.assertIsInstance(bignas_algo, BigNAS) + self.assertIsInstance(bignas_algo.mutator, NasMutator) + + # bignas search_groups + random_subnet = bignas_algo.mutator.sample_choices() + self.assertIsInstance(random_subnet, dict) + + # initiate bignas without any `mutator`. + ALGORITHM_CFG_SUPERNET.pop('type') + ALGORITHM_CFG_SUPERNET['mutator'] = None + none_type = type(ALGORITHM_CFG_SUPERNET['mutator']) + with self.assertRaisesRegex( + TypeError, 'mutator should be a `dict` or `NasMutator` ' + f'instance, but got {none_type}.'): + _ = BigNAS(**ALGORITHM_CFG_SUPERNET) + + def test_loss(self): + # supernet + inputs = torch.randn(1, 3, 224, 224) + bignas = MODELS.build(ALGORITHM_CFG) + loss = bignas(inputs) + assert loss.size(1) == 1000 diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_darts.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_darts.py new file mode 100755 index 000000000..8d0949fa0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_darts.py @@ -0,0 +1,266 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +from typing import Dict +from unittest import TestCase + +import pytest +import torch +import torch.distributed as dist +import torch.nn as nn +from mmcls.structures import ClsDataSample +from mmengine.model import BaseModel +from mmengine.optim import build_optim_wrapper +from mmengine.optim.optimizer import OptimWrapper, OptimWrapperDict +from torch import Tensor +from torch.optim import SGD + +from mmrazor.models import Darts, DiffMutableOP, NasMutator +from mmrazor.models.algorithms.nas.darts import DartsDDP +from mmrazor.registry import MODELS +from mmrazor.structures import load_fix_subnet + +MODELS.register_module(name='torchConv2d', module=nn.Conv2d, force=True) +MODELS.register_module(name='torchMaxPool2d', module=nn.MaxPool2d, force=True) +MODELS.register_module(name='torchAvgPool2d', module=nn.AvgPool2d, force=True) + + +@MODELS.register_module() +class ToyDiffModule2(BaseModel): + + def __init__(self, data_preprocessor=None): + super().__init__(data_preprocessor=data_preprocessor, init_cfg=None) + + self.candidates = dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + padding=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + padding=2, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + padding=3, + ), + ) + module_kwargs = dict( + in_channels=3, + out_channels=8, + stride=1, + ) + self.mutable = DiffMutableOP( + candidates=self.candidates, + module_kwargs=module_kwargs, + alias='normal') + + self.bn = nn.BatchNorm2d(8) + + def forward(self, batch_inputs, data_samples=None, mode='tensor'): + if mode == 'loss': + out = self.bn(self.mutable(batch_inputs)) + return dict(loss=out) + elif mode == 'predict': + out = self.bn(self.mutable(batch_inputs)) + 1 + return out + elif mode == 'tensor': + out = self.bn(self.mutable(batch_inputs)) + 2 + return out + + +class TestDarts(TestCase): + + def setUp(self) -> None: + self.device: str = 'cpu' + + OPTIMIZER_CFG = dict( + type='SGD', + lr=0.5, + momentum=0.9, + nesterov=True, + weight_decay=0.0001) + + self.OPTIM_WRAPPER_CFG = dict(optimizer=OPTIMIZER_CFG) + + def test_init(self) -> None: + # initiate darts when `norm_training` is True. + model = ToyDiffModule2() + mutator = NasMutator() + algo = Darts(architecture=model, mutator=mutator, norm_training=True) + algo.eval() + self.assertTrue(model.bn.training) + + # initiate darts with built mutator + model = ToyDiffModule2() + mutator = NasMutator() + algo = Darts(model, mutator) + self.assertIs(algo.mutator, mutator) + + # initiate darts with unbuilt mutator + mutator = dict(type='NasMutator') + algo = Darts(model, mutator) + self.assertIsInstance(algo.mutator, NasMutator) + + # test load fix_subnet + fix_subnet = { + 'normal': { + 'chosen': ['torch_conv2d_3x3', 'torch_conv2d_7x7'] + } + } + load_fix_subnet(model, fix_subnet) + algo = Darts(model, mutator) + self.assertEqual(algo.architecture.mutable.num_choices, 2) + + # initiate darts with error type `mutator` + with self.assertRaisesRegex(TypeError, 'mutator should be'): + Darts(model, model) + + def test_forward_loss(self) -> None: + inputs = torch.randn(1, 3, 8, 8) + model = ToyDiffModule2() + + # supernet + mutator = NasMutator() + mutator.prepare_from_supernet(model) + mutator.prepare_arch_params() + + # subnet + fix_subnet = fix_subnet = { + 'normal': { + 'chosen': ['torch_conv2d_3x3', 'torch_conv2d_7x7'] + } + } + load_fix_subnet(model, fix_subnet) + loss = model(inputs, mode='loss') + self.assertIsInstance(loss, dict) + + def _prepare_fake_data(self) -> Dict: + imgs = torch.randn(16, 3, 224, 224).to(self.device) + data_samples = [ + ClsDataSample().set_gt_label(torch.randint(0, 1000, + (16, ))).to(self.device) + ] + + return {'inputs': imgs, 'data_samples': data_samples} + + def test_search_subnet(self) -> None: + model = ToyDiffModule2() + + mutator = NasMutator() + mutator.prepare_from_supernet(model) + mutator.prepare_arch_params() + + algo = Darts(model, mutator) + subnet = algo.mutator.sample_choices() + self.assertIsInstance(subnet, dict) + + def test_darts_train_step(self) -> None: + model = ToyDiffModule2() + + mutator = NasMutator() + mutator.prepare_from_supernet(model) + mutator.prepare_arch_params() + + # data is tensor + algo = Darts(model, mutator) + data = self._prepare_fake_data() + optim_wrapper = build_optim_wrapper(algo, self.OPTIM_WRAPPER_CFG) + loss = algo.train_step(data, optim_wrapper) + + self.assertTrue(isinstance(loss['loss'], Tensor)) + + # data is tuple or list + algo = Darts(model, mutator) + data = [self._prepare_fake_data() for _ in range(2)] + optim_wrapper_dict = OptimWrapperDict( + architecture=OptimWrapper(SGD(model.parameters(), lr=0.1)), + mutator=OptimWrapper(SGD(model.parameters(), lr=0.01))) + loss = algo.train_step(data, optim_wrapper_dict) + + self.assertIsNotNone(loss) + + def test_darts_with_unroll(self) -> None: + model = ToyDiffModule2() + + mutator = NasMutator() + mutator.prepare_from_supernet(model) + mutator.prepare_arch_params() + + # data is tuple or list + algo = Darts(model, mutator, unroll=True) + data = [self._prepare_fake_data() for _ in range(2)] + optim_wrapper_dict = OptimWrapperDict( + architecture=OptimWrapper(SGD(model.parameters(), lr=0.1)), + mutator=OptimWrapper(SGD(model.parameters(), lr=0.01))) + loss = algo.train_step(data, optim_wrapper_dict) + + self.assertIsNotNone(loss) + + +class TestDartsDDP(TestDarts): + + @classmethod + def setUpClass(cls) -> None: + os.environ['MASTER_ADDR'] = 'localhost' + os.environ['MASTER_PORT'] = '12345' + + # initialize the process group + backend = 'nccl' if torch.cuda.is_available() else 'gloo' + dist.init_process_group(backend, rank=0, world_size=1) + + def prepare_model(self, unroll=False, device_ids=None) -> Darts: + self.device = 'cuda' if torch.cuda.is_available() else 'cpu' + + model = ToyDiffModule2() + + mutator = NasMutator() + mutator.prepare_from_supernet(model) + mutator.prepare_arch_params() + + algo = Darts(model, mutator, unroll=unroll).to(self.device) + + return DartsDDP( + module=algo, find_unused_parameters=True, device_ids=device_ids) + + @classmethod + def tearDownClass(cls) -> None: + dist.destroy_process_group() + + @pytest.mark.skipif( + not torch.cuda.is_available(), reason='cuda device is not avaliable') + def test_init(self) -> None: + ddp_model = self.prepare_model() + self.assertIsInstance(ddp_model, DartsDDP) + + def test_dartsddp_train_step(self) -> None: + # data is tensor + ddp_model = self.prepare_model() + data = self._prepare_fake_data() + optim_wrapper = build_optim_wrapper(ddp_model, self.OPTIM_WRAPPER_CFG) + loss = ddp_model.train_step(data, optim_wrapper) + + self.assertIsNotNone(loss) + + # data is tuple or list + ddp_model = self.prepare_model() + data = [self._prepare_fake_data() for _ in range(2)] + optim_wrapper_dict = OptimWrapperDict( + architecture=OptimWrapper(SGD(ddp_model.parameters(), lr=0.1)), + mutator=OptimWrapper(SGD(ddp_model.parameters(), lr=0.01))) + loss = ddp_model.train_step(data, optim_wrapper_dict) + + self.assertIsNotNone(loss) + + def test_dartsddp_with_unroll(self) -> None: + # data is tuple or list + ddp_model = self.prepare_model(unroll=True) + data = [self._prepare_fake_data() for _ in range(2)] + optim_wrapper_dict = OptimWrapperDict( + architecture=OptimWrapper(SGD(ddp_model.parameters(), lr=0.1)), + mutator=OptimWrapper(SGD(ddp_model.parameters(), lr=0.01))) + loss = ddp_model.train_step(data, optim_wrapper_dict) + + self.assertIsNotNone(loss) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_datafree_distill.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_datafree_distill.py new file mode 100755 index 000000000..a427e95dd --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_datafree_distill.py @@ -0,0 +1,221 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from unittest import TestCase + +import torch +from mmengine import ConfigDict +from mmengine.optim import build_optim_wrapper + +from mmrazor.models import DAFLDataFreeDistillation, DataFreeDistillation + + +class TestDataFreeDistill(TestCase): + + def test_init(self): + + recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + + alg_kwargs = ConfigDict( + architecture=dict(type='ToyStudent'), + teachers=dict( + tea1=dict(build_cfg=dict(type='ToyTeacher')), + tea2=dict(build_cfg=dict(type='ToyTeacher'))), + generator=dict(type='ToyGenerator'), + distiller=dict( + type='ConfigurableDistiller', + student_recorders=recorders_cfg, + teacher_recorders=dict( + tea1_conv=dict(type='ModuleOutputs', source='tea1.conv')), + distill_losses=dict(loss_dis=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_dis=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='tea1_conv')))), + generator_distiller=dict( + type='ConfigurableDistiller', + student_recorders=recorders_cfg, + teacher_recorders=dict( + tea2_conv=dict(type='ModuleOutputs', source='tea2.conv')), + distill_losses=dict(loss_gen=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_gen=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='tea2_conv')))), + ) + + alg = DataFreeDistillation(**alg_kwargs) + self.assertEquals(len(alg.teachers), len(alg_kwargs['teachers'])) + + alg_kwargs_ = copy.deepcopy(alg_kwargs) + alg_kwargs_['teachers'] = 'ToyTeacher' + with self.assertRaisesRegex(TypeError, + 'teacher should be a `dict` but got '): + alg = DataFreeDistillation(**alg_kwargs_) + + alg_kwargs_ = copy.deepcopy(alg_kwargs) + alg_kwargs_['generator'] = 'ToyGenerator' + with self.assertRaisesRegex( + TypeError, 'generator should be a `dict` instance, but got '): + _ = DataFreeDistillation(**alg_kwargs_) + + def test_loss(self): + + recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + + alg_kwargs = ConfigDict( + architecture=dict(type='ToyStudent'), + teachers=dict( + tea1=dict(build_cfg=dict(type='ToyTeacher')), + tea2=dict(build_cfg=dict(type='ToyTeacher'))), + generator=dict(type='ToyGenerator'), + distiller=dict( + type='ConfigurableDistiller', + student_recorders=recorders_cfg, + teacher_recorders=dict( + tea1_conv=dict(type='ModuleOutputs', source='tea1.conv')), + distill_losses=dict(loss_dis=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_dis=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='tea1_conv')))), + generator_distiller=dict( + type='ConfigurableDistiller', + student_recorders=recorders_cfg, + teacher_recorders=dict( + tea2_conv=dict(type='ModuleOutputs', source='tea2.conv')), + distill_losses=dict(loss_gen=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_gen=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='tea2_conv')))), + ) + + optim_wrapper_cfg = dict( + type='OptimWrapper', + optimizer=dict( + type='SGD', lr=0.1, weight_decay=0.01, momentum=0.9)) + + data = dict(inputs=torch.randn(3, 1, 1), data_samples=None) + + alg = DataFreeDistillation(**alg_kwargs) + optim_wrapper = build_optim_wrapper(alg, optim_wrapper_cfg) + optim_wrapper_dict = dict( + architecture=optim_wrapper, generator=optim_wrapper) + + losses = alg.train_step(data, optim_wrapper_dict) + self.assertIn('distill.loss_dis', losses) + self.assertIn('distill.loss', losses) + self.assertIn('generator.loss_gen', losses) + self.assertIn('generator.loss', losses) + + alg_kwargs_ = copy.deepcopy(alg_kwargs) + alg_kwargs_['student_iter'] = 5 + alg = DataFreeDistillation(**alg_kwargs_) + losses = alg.train_step(data, optim_wrapper_dict) + self.assertIn('distill.loss_dis', losses) + self.assertIn('distill.loss', losses) + self.assertIn('generator.loss_gen', losses) + self.assertIn('generator.loss', losses) + + +class TestDAFLDataFreeDistill(TestCase): + + def test_init(self): + + recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + + alg_kwargs = ConfigDict( + architecture=dict(type='ToyStudent'), + teachers=dict( + tea1=dict(build_cfg=dict(type='ToyTeacher')), + tea2=dict(build_cfg=dict(type='ToyTeacher'))), + generator=dict(type='ToyGenerator'), + distiller=dict( + type='ConfigurableDistiller', + student_recorders=recorders_cfg, + teacher_recorders=dict( + tea1_conv=dict(type='ModuleOutputs', source='tea1.conv')), + distill_losses=dict(loss_dis=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_dis=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='tea1_conv')))), + generator_distiller=dict( + type='ConfigurableDistiller', + student_recorders=recorders_cfg, + teacher_recorders=dict( + tea2_conv=dict(type='ModuleOutputs', source='tea2.conv')), + distill_losses=dict(loss_gen=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_gen=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='tea2_conv'))))) + + alg = DAFLDataFreeDistillation(**alg_kwargs) + self.assertEquals(len(alg.teachers), len(alg_kwargs['teachers'])) + + alg_kwargs_ = copy.deepcopy(alg_kwargs) + alg_kwargs_['teachers'] = 'ToyTeacher' + with self.assertRaisesRegex(TypeError, + 'teacher should be a `dict` but got '): + alg = DAFLDataFreeDistillation(**alg_kwargs_) + + alg_kwargs_ = copy.deepcopy(alg_kwargs) + alg_kwargs_['generator'] = 'ToyGenerator' + with self.assertRaisesRegex( + TypeError, 'generator should be a `dict` instance, but got '): + _ = DAFLDataFreeDistillation(**alg_kwargs_) + + def test_loss(self): + + recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + + alg_kwargs = ConfigDict( + architecture=dict(type='ToyStudent'), + teachers=dict( + tea1=dict(build_cfg=dict(type='ToyTeacher')), + tea2=dict(build_cfg=dict(type='ToyTeacher'))), + generator=dict(type='ToyGenerator'), + distiller=dict( + type='ConfigurableDistiller', + student_recorders=recorders_cfg, + teacher_recorders=dict( + tea1_conv=dict(type='ModuleOutputs', source='tea1.conv')), + distill_losses=dict(loss_dis=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_dis=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='tea1_conv')))), + generator_distiller=dict( + type='ConfigurableDistiller', + student_recorders=recorders_cfg, + teacher_recorders=dict( + tea1_conv=dict(type='ModuleOutputs', source='tea1.conv'), + tea2_conv=dict(type='ModuleOutputs', source='tea2.conv')), + distill_losses=dict(loss_gen=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_gen=dict( + arg1=dict(from_student=False, recorder='tea1_conv'), + arg2=dict(from_student=False, recorder='tea2_conv'))))) + + optim_wrapper_cfg = dict( + type='OptimWrapper', + optimizer=dict( + type='SGD', lr=0.1, weight_decay=0.01, momentum=0.9)) + + data = dict(inputs=torch.randn(3, 1, 1), data_samples=None) + + alg = DAFLDataFreeDistillation(**alg_kwargs) + optim_wrapper = build_optim_wrapper(alg, optim_wrapper_cfg) + optim_wrapper_dict = dict( + architecture=optim_wrapper, generator=optim_wrapper) + + losses = alg.train_step(data, optim_wrapper_dict) + self.assertIn('distill.loss_dis', losses) + self.assertIn('distill.loss', losses) + self.assertIn('generator.loss_gen', losses) + self.assertIn('generator.loss', losses) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dcff_network.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dcff_network.py new file mode 100755 index 000000000..657d7a09b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dcff_network.py @@ -0,0 +1,294 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import json +import os +import os.path as osp +import unittest + +import torch +from mmcls.structures import ClsDataSample +from mmengine import MessageHub +from mmengine.model import BaseModel + +from mmrazor.models.algorithms.pruning.dcff import DCFF +from mmrazor.models.algorithms.pruning.ite_prune_algorithm import \ + ItePruneConfigManager +from mmrazor.registry import MODELS +from mmrazor.structures import export_fix_subnet + + +# @TASK_UTILS.register_module() +class ImageClassifierPseudoLoss: + """Calculate the pseudo loss to trace the topology of a `ImageClassifier` + in MMClassification with `BackwardTracer`.""" + + def __call__(self, model) -> torch.Tensor: + pseudo_img = torch.rand(2, 3, 32, 32) + pseudo_output = model(pseudo_img) + return pseudo_output.sum() + + +MODEL_CFG = dict( + _scope_='mmcls', + type='ImageClassifier', + backbone=dict( + type='ResNet', + depth=18, + num_stages=4, + out_indices=(3, ), + style='pytorch'), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=1000, + in_channels=512, + loss=dict(type='CrossEntropyLoss', loss_weight=1.0), + topk=(1, 5), + )) + +MUTATOR_CONFIG_NUM = dict( + type='DCFFChannelMutator', + channel_unit_cfg={ + 'type': 'DCFFChannelUnit', + 'default_args': { + 'choice_mode': 'number' + } + }) +MUTATOR_CONFIG_FLOAT = dict( + type='DCFFChannelMutator', + channel_unit_cfg={ + 'type': 'DCFFChannelUnit', + 'default_args': { + 'choice_mode': 'ratio' + } + }) + +if torch.cuda.is_available(): + DEVICE = torch.device('cuda:0') +else: + DEVICE = torch.device('cpu') + + +class TestDCFFAlgorithm(unittest.TestCase): + + def _set_epoch_ite(self, epoch, ite, max_epoch): + iter_per_epoch = 10 + message_hub = MessageHub.get_current_instance() + message_hub.update_info('epoch', epoch) + message_hub.update_info('max_epochs', max_epoch) + message_hub.update_info('max_iters', max_epoch * iter_per_epoch) + message_hub.update_info('iter', ite + iter_per_epoch * epoch) + + def fake_cifar_data(self): + imgs = torch.randn(16, 3, 32, 32).to(DEVICE) + data_samples = [ + ClsDataSample().set_gt_label(torch.randint(0, 10, + (16, ))).to(DEVICE) + ] + + return {'inputs': imgs, 'data_samples': data_samples} + + def test_ite_prune_config_manager(self): + iter_per_epoch = 10 + float_origin, float_target = 1.0, 0.5 + int_origin, int_target = 10, 5 + for origin, target, manager in [ + (float_origin, float_target, + ItePruneConfigManager({'a': float_target}, {'a': float_origin}, + 2 * iter_per_epoch, 5)), + (int_origin, int_target, + ItePruneConfigManager({'a': int_target}, {'a': int_origin}, + 2 * iter_per_epoch, 5)) + ]: + times = 1 + for e in range(1, 10): + for ite in range(iter_per_epoch): + self._set_epoch_ite(e, ite, 10) + if (e, ite) in [(0, 0), (2, 0), (4, 0), (6, 0), (8, 0)]: + self.assertTrue( + manager.is_prune_time(e * iter_per_epoch + ite)) + times += 1 + self.assertEqual( + manager.prune_at(e * iter_per_epoch + ite)['a'], + origin - (origin - target) * times / 5) + else: + self.assertFalse( + manager.is_prune_time(e * iter_per_epoch + ite)) + + def test_iterative_prune_int(self): + + data = self.fake_cifar_data() + + model = MODELS.build(MODEL_CFG) + mutator = MODELS.build(MUTATOR_CONFIG_FLOAT) + mutator.prepare_from_supernet(model) + mutator.set_choices(mutator.sample_choices()) + prune_target = mutator.choice_template + + iter_per_epoch = 10 + epoch = 10 + epoch_step = 2 + times = 5 + + algorithm = DCFF( + MODEL_CFG, + target_pruning_ratio=prune_target, + mutator_cfg=MUTATOR_CONFIG_FLOAT, + step_freq=epoch_step).to(DEVICE) + + for e in range(epoch): + for ite in range(10): + self._set_epoch_ite(e, ite, epoch) + + algorithm.forward( + data['inputs'], data['data_samples'], mode='loss') + self.assertEqual(times, algorithm.prune_times) + self.assertEqual(epoch_step * iter_per_epoch, + algorithm.step_freq) + + current_choices = algorithm.mutator.current_choices + target_pruning_ratio = algorithm.set_target_pruning_ratio( + prune_target, mutator.mutable_units) + for key in current_choices: + self.assertAlmostEqual( + current_choices[key], target_pruning_ratio[key], delta=0.1) + + def test_load_pretrained(self): + iter_per_epoch = 10 + epoch_step = 20 + data = self.fake_cifar_data() + + # prepare checkpoint + model_cfg = copy.deepcopy(MODEL_CFG) + model: BaseModel = MODELS.build(model_cfg) + checkpoint_path = os.path.dirname(__file__) + '/checkpoint' + torch.save(model.state_dict(), checkpoint_path) + + # build algorithm + model_cfg['init_cfg'] = { + 'type': 'Pretrained', + 'checkpoint': checkpoint_path + } + algorithm = DCFF( + model_cfg, + mutator_cfg=MUTATOR_CONFIG_FLOAT, + target_pruning_ratio=None, + step_freq=epoch_step).to(DEVICE) + algorithm.init_weights() + self._set_epoch_ite(10, 5, 200) + algorithm.forward(data['inputs'], data['data_samples'], mode='loss') + self.assertEqual(algorithm.step_freq, epoch_step * iter_per_epoch) + + # delete checkpoint + os.remove(checkpoint_path) + + def test_group_target_ratio(self): + + model = MODELS.build(MODEL_CFG) + mutator = MODELS.build(MUTATOR_CONFIG_FLOAT) + mutator.prepare_from_supernet(model) + mutator.set_choices(mutator.sample_choices()) + prune_target = mutator.choice_template + + iter_per_epoch = 10 + epoch_step = 2 + epoch = 6 + data = self.fake_cifar_data() + + prune_target['backbone.layer1.0.conv1_(0, 64)_64'] = 0.1 + prune_target['backbone.layer1.1.conv1_(0, 64)_64'] = 0.1 + + algorithm = DCFF( + MODEL_CFG, + target_pruning_ratio=prune_target, + mutator_cfg=MUTATOR_CONFIG_FLOAT, + step_freq=epoch_step).to(DEVICE) + + algorithm.init_weights() + self._set_epoch_ite(1, 2, epoch) + algorithm.forward(data['inputs'], data['data_samples'], mode='loss') + self.assertEqual(algorithm.step_freq, epoch_step * iter_per_epoch) + + def test_export_subnet(self): + + model = MODELS.build(MODEL_CFG) + mutator = MODELS.build(MUTATOR_CONFIG_FLOAT) + mutator.prepare_from_supernet(model) + mutator.set_choices(mutator.sample_choices()) + + iter_per_epoch = 10 + epoch_step = 2 + epoch = 6 + data = self.fake_cifar_data() + + stage_ratio_1 = 0.65 + stage_ratio_2 = 0.6 + stage_ratio_3 = 0.9 + stage_ratio_4 = 0.7 + + target_pruning_ratio = { + 'backbone.layer1.0.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.0.conv2_(0, 64)_64': stage_ratio_2, + 'backbone.layer1.0.conv3_(0, 256)_256': stage_ratio_3, + 'backbone.layer1.1.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.1.conv2_(0, 64)_64': stage_ratio_2, + 'backbone.layer1.2.conv1_(0, 64)_64': stage_ratio_1, + 'backbone.layer1.2.conv2_(0, 64)_64': stage_ratio_2, + # block 1 [0.65, 0.6] downsample=[0.9] + 'backbone.layer2.0.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.0.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.0.conv3_(0, 512)_512': stage_ratio_3, + 'backbone.layer2.1.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.1.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.2.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.2.conv2_(0, 128)_128': stage_ratio_2, + 'backbone.layer2.3.conv1_(0, 128)_128': stage_ratio_1, + 'backbone.layer2.3.conv2_(0, 128)_128': stage_ratio_2, + # block 2 [0.65, 0.6] downsample=[0.9] + 'backbone.layer3.0.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.0.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.0.conv3_(0, 1024)_1024': stage_ratio_3, + 'backbone.layer3.1.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.1.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.2.conv1_(0, 256)_256': stage_ratio_1, + 'backbone.layer3.2.conv2_(0, 256)_256': stage_ratio_2, + 'backbone.layer3.3.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.3.conv2_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.4.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.4.conv2_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.5.conv1_(0, 256)_256': stage_ratio_4, + 'backbone.layer3.5.conv2_(0, 256)_256': stage_ratio_4, + # block 3 [0.65, 0.6]*2+[0.7, 0.7]*2 downsample=[0.9] + 'backbone.layer4.0.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv2_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.0.conv3_(0, 2048)_2048': stage_ratio_3, + 'backbone.layer4.1.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.1.conv2_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv1_(0, 512)_512': stage_ratio_4, + 'backbone.layer4.2.conv2_(0, 512)_512': stage_ratio_4 + # block 4 [0.7, 0.7] downsample=[0.9] + } + + algorithm = DCFF( + MODEL_CFG, + target_pruning_ratio=target_pruning_ratio, + mutator_cfg=MUTATOR_CONFIG_FLOAT, + step_freq=epoch_step).to(DEVICE) + + algorithm.init_weights() + self._set_epoch_ite(0, 0, epoch) + algorithm.forward(data['inputs'], data['data_samples'], mode='loss') + self.assertEqual(algorithm.step_freq, epoch_step * iter_per_epoch) + + fix_subnet, static_model = export_fix_subnet( + algorithm, export_subnet_mode='mutator', slice_weight=True) + fix_subnet = json.dumps(fix_subnet, indent=4, separators=(',', ':')) + subnet_name = 'subnet.json' + weight_name = 'subnet_weight.pth' + with open(osp.join('tests/data/test_registry/', subnet_name), + 'w') as file: + file.write(fix_subnet) + torch.save({ + 'state_dict': static_model.state_dict(), + 'meta': {} + }, osp.join('tests/data/test_registry/', weight_name)) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dmcp.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dmcp.py new file mode 100755 index 000000000..5ec199b20 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dmcp.py @@ -0,0 +1,193 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +from typing import Dict, Union +from unittest import TestCase + +import pytest +import torch +import torch.distributed as dist +from mmcls.structures import ClsDataSample +from mmengine import MessageHub +from mmengine.optim.optimizer import OptimWrapper, OptimWrapperDict +from torch.optim import SGD + +from mmrazor.models.algorithms import DMCP, DMCPDDP +from mmrazor.models.mutators import DMCPChannelMutator +from mmrazor.registry import MODELS + +MUTATOR_TYPE = Union[torch.nn.Module, Dict] +DISTILLER_TYPE = Union[torch.nn.Module, Dict] + +MUTATOR_CFG = dict( + type='mmrazor.DMCPChannelMutator', + channel_unit_cfg={'type': 'DMCPChannelUnit'}, + parse_cfg=dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer'), +) + +DISTILLER_CFG = dict( + _scope_='mmrazor', + type='ConfigurableDistiller', + teacher_recorders=dict(fc=dict(type='ModuleOutputs', source='head.fc')), + student_recorders=dict(fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=1)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(recorder='fc', from_student=True), + preds_T=dict(recorder='fc', from_student=False)))) + +ALGORITHM_CFG = dict( + type='mmrazor.DMCP', + architecture=dict( + cfg_path='mmcls::resnet/resnet50_8xb32_in1k.py', pretrained=False), + mutator_cfg=MUTATOR_CFG, + distiller=DISTILLER_CFG, + strategy=['max', 'min', 'scheduled_random', 'arch_random'], + arch_start_train=10, + distillation_times=10, + arch_train_freq=10) + + +class TestDMCP(TestCase): + + def _prepare_fake_data(self) -> Dict: + imgs = torch.randn(16, 3, 224, 224).to(self.device) + data_samples = [ + ClsDataSample().set_gt_label(torch.randint(0, 1000, + (16, ))).to(self.device) + ] + + return {'inputs': imgs, 'data_samples': data_samples} + + def test_init(self): + self.device = 'cuda' if torch.cuda.is_available() else 'cpu' + + ALGORITHM_CFG_SUPERNET = copy.deepcopy(ALGORITHM_CFG) + # initiate dmcp with built `algorithm`. + dmcp_algo = MODELS.build(ALGORITHM_CFG_SUPERNET) + self.assertIsInstance(dmcp_algo, DMCP) + # dmcp mutators include channel_mutator and value_mutator + assert isinstance(dmcp_algo.mutator, DMCPChannelMutator) + + ALGORITHM_CFG_SUPERNET.pop('type') + fake_distiller = 'distiller' + # initiate dmcp without `distiller`. + with self.assertRaisesRegex( + TypeError, 'distiller should be a `dict` or ' + '`ConfigurableDistiller` instance, but got ' + f'{type(fake_distiller)}'): + ALGORITHM_CFG_SUPERNET['distiller'] = fake_distiller + _ = DMCP(**ALGORITHM_CFG_SUPERNET) + + # initiate dmcp without any `mutator`. + ALGORITHM_CFG_SUPERNET['mutator_cfg'] = None + with self.assertRaisesRegex( + AttributeError, "'NoneType' object has no attribute 'get'"): + _ = DMCP(**ALGORITHM_CFG_SUPERNET) + + def test_loss(self): + # subernet + inputs = torch.randn(1, 3, 224, 224) + dmcp = MODELS.build(ALGORITHM_CFG) + loss = dmcp(inputs, mode='tensor') + assert loss.size(1) == 1000 + + def test_dmcp_train_step(self): + # supernet + self.device = 'cuda' if torch.cuda.is_available() else 'cpu' + inputs = self._prepare_fake_data() + dmcp = MODELS.build(ALGORITHM_CFG) + optim_wrapper_dict = OptimWrapperDict( + architecture=OptimWrapper(SGD(dmcp.parameters(), lr=0.1)), + mutator=OptimWrapper(SGD(dmcp.parameters(), lr=0.01))) + + message_hub = MessageHub.get_current_instance() + + message_hub.update_info('iter', 20) + dmcp.cur_sample_prob = -1 + + losses = dmcp.train_step(inputs, optim_wrapper_dict) + + assert len(losses) == 9 + assert losses['max_subnet1.loss'] > 0 + assert losses['min_subnet1.loss'] > 0 + assert losses['min_subnet1.loss_kl'] + 1e-5 > 0 + assert losses['direct_subnet1.loss'] > 0 + assert losses['direct_subnet1.loss_kl'] + 1e-5 > 0 + assert losses['direct_subnet2.loss'] > 0 + assert losses['direct_subnet2.loss_kl'] + 1e-5 > 0 + assert losses['arch.loss'] > 0 + assert losses['flops.loss'] > 0 + + message_hub.update_info('iter', 0) + dmcp.arch_train = False + losses = dmcp.train_step(inputs, optim_wrapper_dict) + + assert len(losses) == 4 + assert losses['max_subnet1.loss'] > 0 + assert losses['min_subnet1.loss'] > 0 + assert losses['random_subnet1.loss'] > 0 + assert losses['random_subnet2.loss'] > 0 + + def test_dmcp_compute_flops_loss(self): + dmcp = MODELS.build(ALGORITHM_CFG) + for type in ['l2', 'inverted_log_l1', 'log_l1', 'l1']: + dmcp.flops_loss_type = type + fake_flops = torch.tensor(100) + dmcp._compute_flops_loss(expected_flops=fake_flops) + + +class TestDMCPDDP(TestDMCP): + + @classmethod + def setUpClass(cls) -> None: + os.environ['MASTER_ADDR'] = 'localhost' + os.environ['MASTER_PORT'] = '12345' + + # initialize the process group + backend = 'nccl' if torch.cuda.is_available() else 'gloo' + dist.init_process_group(backend, rank=0, world_size=1) + + def prepare_model(self, device_ids=None) -> DMCPDDP: + self.device = 'cuda' if torch.cuda.is_available() else 'cpu' + + dmcp_algo = MODELS.build(ALGORITHM_CFG).to(self.device) + self.assertIsInstance(dmcp_algo, DMCP) + + return DMCPDDP( + module=dmcp_algo, + find_unused_parameters=True, + device_ids=device_ids) + + @classmethod + def tearDownClass(cls) -> None: + dist.destroy_process_group() + + @pytest.mark.skipif( + not torch.cuda.is_available(), reason='cuda device is not avaliable') + def test_init(self) -> None: + ddp_model = self.prepare_model() + self.assertIsInstance(ddp_model, DMCPDDP) + + def test_dmcpddp_train_step(self) -> None: + ddp_model = self.prepare_model() + data = self._prepare_fake_data() + optim_wrapper_dict = OptimWrapperDict( + architecture=OptimWrapper(SGD(ddp_model.parameters(), lr=0.1)), + mutator=OptimWrapper(SGD(ddp_model.parameters(), lr=0.01))) + + message_hub = MessageHub.get_current_instance() + + message_hub.update_info('iter', 20) + ddp_model.module.cur_sample_prob = -1 + loss = ddp_model.train_step(data, optim_wrapper_dict) + + message_hub.update_info('iter', 0) + ddp_model.module.arch_train = False + loss = ddp_model.train_step(data, optim_wrapper_dict) + + self.assertIsNotNone(loss) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dsnas.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dsnas.py new file mode 100755 index 000000000..c6d28e4c6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_dsnas.py @@ -0,0 +1,217 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +from unittest import TestCase +from unittest.mock import patch + +import pytest +import torch +import torch.distributed as dist +import torch.nn as nn +from mmcls.structures import ClsDataSample +from mmengine.model import BaseModel +from mmengine.optim import build_optim_wrapper +from mmengine.optim.optimizer import OptimWrapper, OptimWrapperDict +from torch import Tensor +from torch.optim import SGD + +from mmrazor.models import DSNAS, NasMutator, OneHotMutableOP +from mmrazor.models.algorithms.nas.dsnas import DSNASDDP +from mmrazor.registry import MODELS +from mmrazor.structures import load_fix_subnet + +MODELS.register_module(name='torchConv2d', module=nn.Conv2d, force=True) +MODELS.register_module(name='torchMaxPool2d', module=nn.MaxPool2d, force=True) +MODELS.register_module(name='torchAvgPool2d', module=nn.AvgPool2d, force=True) + + +@MODELS.register_module() +class ToyDiffModule(BaseModel): + + def __init__(self, data_preprocessor=None): + super().__init__(data_preprocessor=data_preprocessor, init_cfg=None) + self.candidates = dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + padding=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + padding=2, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + padding=3, + ), + ) + module_kwargs = dict(in_channels=3, out_channels=8, stride=1) + + self.mutable = OneHotMutableOP( + candidates=self.candidates, module_kwargs=module_kwargs) + self.bn = nn.BatchNorm2d(8) + + def forward(self, batch_inputs, data_samples=None, mode='tensor'): + if mode == 'loss': + out = self.bn(self.mutable(batch_inputs)) + return dict(loss=out) + elif mode == 'predict': + out = self.bn(self.mutable(batch_inputs)) + 1 + return out + elif mode == 'tensor': + out = self.bn(self.mutable(batch_inputs)) + 2 + return out + + +class TestDsnas(TestCase): + + def setUp(self) -> None: + self.device: str = 'cpu' + + OPTIMIZER_CFG = dict( + type='SGD', + lr=0.5, + momentum=0.9, + nesterov=True, + weight_decay=0.0001) + + self.OPTIM_WRAPPER_CFG = dict(optimizer=OPTIMIZER_CFG) + + def test_init(self) -> None: + # initiate dsnas when `norm_training` is True. + model = ToyDiffModule() + mutator = NasMutator() + algo = DSNAS(architecture=model, mutator=mutator, norm_training=True) + algo.eval() + self.assertTrue(model.bn.training) + + # initiate Dsnas with built mutator + model = ToyDiffModule() + mutator = NasMutator() + algo = DSNAS(model, mutator) + self.assertIs(algo.mutator, mutator) + + # initiate Dsnas with unbuilt mutator + mutator = dict(type='NasMutator') + algo = DSNAS(model, mutator) + self.assertIsInstance(algo.mutator, NasMutator) + + # test load fix_subnet + fix_subnet = {'mutable': {'chosen': 'torch_conv2d_5x5'}} + load_fix_subnet(model, fix_subnet) + algo = DSNAS(model, mutator) + self.assertEqual(algo.architecture.mutable.num_choices, 1) + + # initiate Dsnas with error type `mutator` + with self.assertRaisesRegex(TypeError, 'mutator should be'): + DSNAS(model, model) + + def test_forward_loss(self) -> None: + inputs = torch.randn(1, 3, 8, 8) + model = ToyDiffModule() + + # supernet + mutator = NasMutator() + mutator.prepare_from_supernet(model) + algo = DSNAS(model, mutator) + loss = algo(inputs, mode='loss') + self.assertIsInstance(loss, dict) + + # subnet + fix_subnet = {'mutable': {'chosen': 'torch_conv2d_5x5'}} + load_fix_subnet(model, fix_subnet) + loss = model(inputs, mode='loss') + self.assertIsInstance(loss, dict) + + def _prepare_fake_data(self): + imgs = torch.randn(16, 3, 224, 224).to(self.device) + data_samples = [ + ClsDataSample().set_gt_label(torch.randint(0, 1000, + (16, ))).to(self.device) + ] + return {'inputs': imgs, 'data_samples': data_samples} + + def test_search_subnet(self) -> None: + model = ToyDiffModule() + + mutator = NasMutator() + mutator.prepare_from_supernet(model) + algo = DSNAS(model, mutator) + subnet = algo.mutator.sample_choices() + self.assertIsInstance(subnet, dict) + + @patch('mmengine.logging.message_hub.MessageHub.get_info') + def test_dsnas_train_step(self, mock_get_info) -> None: + model = ToyDiffModule() + mutator = NasMutator() + mutator.prepare_from_supernet(model) + mock_get_info.return_value = 2 + + algo = DSNAS(model, mutator) + data = self._prepare_fake_data() + optim_wrapper = build_optim_wrapper(algo, self.OPTIM_WRAPPER_CFG) + loss = algo.train_step(data, optim_wrapper) + + self.assertTrue(isinstance(loss['loss'], Tensor)) + + algo = DSNAS(model, mutator) + optim_wrapper_dict = OptimWrapperDict( + architecture=OptimWrapper(SGD(model.parameters(), lr=0.1)), + mutator=OptimWrapper(SGD(model.parameters(), lr=0.01))) + loss = algo.train_step(data, optim_wrapper_dict) + + self.assertIsNotNone(loss) + + +class TestDsnasDDP(TestDsnas): + + @classmethod + def setUpClass(cls) -> None: + os.environ['MASTER_ADDR'] = 'localhost' + os.environ['MASTER_PORT'] = '12345' + + # initialize the process group + backend = 'nccl' if torch.cuda.is_available() else 'gloo' + dist.init_process_group(backend, rank=0, world_size=1) + + def prepare_model(self, device_ids=None) -> DSNAS: + self.device = 'cuda' if torch.cuda.is_available() else 'cpu' + + model = ToyDiffModule() + mutator = NasMutator() + mutator.prepare_from_supernet(model) + + algo = DSNAS(model, mutator).to(self.device) + + return DSNASDDP( + module=algo, find_unused_parameters=True, device_ids=device_ids) + + @classmethod + def tearDownClass(cls) -> None: + dist.destroy_process_group() + + @pytest.mark.skipif( + not torch.cuda.is_available(), reason='cuda device is not avaliable') + def test_init(self) -> None: + ddp_model = self.prepare_model() + self.assertIsInstance(ddp_model, DSNASDDP) + + @patch('mmengine.logging.message_hub.MessageHub.get_info') + def test_dsnasddp_train_step(self, mock_get_info) -> None: + ddp_model = self.prepare_model() + mock_get_info.return_value = 2 + + data = self._prepare_fake_data() + optim_wrapper = build_optim_wrapper(ddp_model, self.OPTIM_WRAPPER_CFG) + loss = ddp_model.train_step(data, optim_wrapper) + + self.assertIsNotNone(loss) + + ddp_model = self.prepare_model() + optim_wrapper_dict = OptimWrapperDict( + architecture=OptimWrapper(SGD(ddp_model.parameters(), lr=0.1)), + mutator=OptimWrapper(SGD(ddp_model.parameters(), lr=0.01))) + loss = ddp_model.train_step(data, optim_wrapper_dict) + + self.assertIsNotNone(loss) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_general_quant.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_general_quant.py new file mode 100755 index 000000000..94a2485bc --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_general_quant.py @@ -0,0 +1,34 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch.nn as nn + + +class ToyModel(nn.Module): + + def __init__(self) -> None: + super().__init__() + # TODO + + +class TestGeneralQuant(TestCase): + """TODO. + + Args: + TestCase (_type_): _description_ + """ + + def test_init(self): + pass + + def test_prepare(self): + pass + + def test_convert(self): + pass + + def test_states(self): + pass + + def test_forward(self): + pass diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_mm_architecture.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_mm_architecture.py new file mode 100755 index 000000000..310d42f5e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_mm_architecture.py @@ -0,0 +1,225 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +import shutil +import tempfile +from unittest import TestCase, skipIf + +import torch +import torch.nn as nn + +try: + from torch.fx import GraphModule +except ImportError: + from mmrazor.utils import get_placeholder + GraphModule = get_placeholder('torch>=1.13') + +from mmengine import ConfigDict +from mmengine.model import BaseModel + +try: + import mmdeploy +except ImportError: + from mmrazor.utils import get_package_placeholder + mmdeploy = get_package_placeholder('mmdeploy') + +from mmrazor import digit_version +from mmrazor.models.algorithms import MMArchitectureQuant +from mmrazor.registry import MODELS + + +class BasicBlock(nn.Module): + + def __init__(self, in_channels, out_channels): + super(BasicBlock, self).__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.mid_channels = out_channels + + self.norm1 = nn.BatchNorm2d(self.mid_channels) + self.norm2 = nn.BatchNorm2d(out_channels) + self.conv1 = nn.Conv2d(in_channels, self.mid_channels, 1) + self.conv2 = nn.Conv2d(self.mid_channels, out_channels, 1) + + self.relu = nn.ReLU6() + self.drop_path = nn.Identity() + + def forward(self, x): + + def _inner_forward(x): + identity = x + + out = self.conv1(x) + out = self.norm1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.norm2(out) + + out = self.drop_path(out) + + out += identity + + return out + + out = _inner_forward(x) + + out = self.relu(out) + + return out + + +class ToyModel(nn.Module): + + def __init__(self): + super(ToyModel, self).__init__() + self.stem_layer = nn.Sequential( + nn.Conv2d(3, 3, 1), nn.BatchNorm2d(3), nn.ReLU()) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.block = BasicBlock(3, 3) + self.block2 = BasicBlock(3, 3) + self.gap = nn.AdaptiveAvgPool2d((1, 1)) + self.fc = nn.Linear(3, 4) + + def forward(self, x): + x = self.stem_layer(x) + x = self.maxpool(x) + x = self.block(x) + x = self.block2(x) + x = self.gap(x) + x = x.flatten(1) + x = self.fc(x) + return x + + +class ToyQuantModel(BaseModel): + + def __init__(self): + super().__init__() + self.architecture = ToyModel() + + def loss(self, outputs, data_samples): + return dict(loss=outputs.sum() - data_samples.sum()) + + def forward(self, inputs, data_samples, mode: str = 'tensor'): + if isinstance(inputs, list): + inputs = torch.stack(inputs) + outputs = self.architecture(inputs) + + return outputs + + +DEPLOY_CFG = ConfigDict( + onnx_config=dict( + type='onnx', + export_params=True, + keep_initializers_as_inputs=False, + opset_version=11, + save_file='end2end.onnx', + input_names=['input'], + output_names=['output'], + input_shape=None, + optimize=True, + dynamic_axes={ + 'input': { + 0: 'batch', + 2: 'height', + 3: 'width' + }, + 'output': { + 0: 'batch' + } + }), + backend_config=dict( + type='openvino', + model_inputs=[dict(opt_shapes=dict(input=[1, 3, 224, 224]))]), + codebase_config=dict(type='mmcls', task='Classification'), + function_record_to_pop=[ + 'mmcls.models.classifiers.ImageClassifier.forward', + 'mmcls.models.classifiers.BaseClassifier.forward' + ], +) + + +@skipIf( + digit_version(torch.__version__) < digit_version('1.13.0'), + 'PyTorch version lower than 1.13.0 is not supported.') +class TestMMArchitectureQuant(TestCase): + + def setUp(self): + + MODELS.register_module(module=ToyQuantModel, force=True) + + self.temp_dir = tempfile.mkdtemp() + filename = 'fp_model.pth' + filename = os.path.join(self.temp_dir, filename) + toymodel = ToyQuantModel() + torch.save(toymodel.state_dict(), filename) + + global_qconfig = ConfigDict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', + bit=8, + is_symmetry=True, + is_symmetric_range=True), + a_qscheme=dict( + qdtype='quint8', + bit=8, + is_symmetry=True, + averaging_constant=0.1), + ) + alg_kwargs = ConfigDict( + type='mmrazor.MMArchitectureQuant', + architecture=dict(type='ToyQuantModel'), + float_checkpoint=filename, + quantizer=dict( + type='mmrazor.OpenVINOQuantizer', + global_qconfig=global_qconfig, + tracer=dict(type='mmrazor.CustomTracer'))) + self.alg_kwargs = alg_kwargs + + def tearDown(self): + MODELS.module_dict.pop('ToyQuantModel') + shutil.rmtree(self.temp_dir) + + def test_init(self): + self.toy_model = MODELS.build(self.alg_kwargs) + assert isinstance(self.toy_model, MMArchitectureQuant) + assert hasattr(self.toy_model, 'quantizer') + + alg_kwargs = copy.deepcopy(self.alg_kwargs) + alg_kwargs.deploy_cfg = DEPLOY_CFG + assert isinstance(self.toy_model, MMArchitectureQuant) + assert hasattr(self.toy_model, 'quantizer') + + def test_sync_qparams(self): + self.toy_model = MODELS.build(self.alg_kwargs) + mode = self.toy_model.forward_modes[0] + self.toy_model.sync_qparams(mode) + w_loss = self.toy_model.qmodels[ + 'loss'].architecture.block.conv1.state_dict()['weight'] + w_tensor = self.toy_model.qmodels[ + 'tensor'].architecture.block.conv1.state_dict()['weight'] + w_pred = self.toy_model.qmodels[ + 'predict'].architecture.block.conv1.state_dict()['weight'] + assert w_loss.equal(w_pred) + assert w_loss.equal(w_tensor) + + def test_build_qmodels(self): + self.toy_model = MODELS.build(self.alg_kwargs) + for forward_modes in self.toy_model.forward_modes: + qmodels = self.toy_model.qmodels[forward_modes] + assert isinstance(qmodels, GraphModule) + + def test_get_deploy_model(self): + self.toy_model = MODELS.build(self.alg_kwargs) + deploy_model = self.toy_model.get_deploy_model() + self.assertIsInstance(deploy_model, torch.fx.graph_module.GraphModule) + + def test_calibrate_step(self): + # TODO + pass diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_ofd_algo.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_ofd_algo.py new file mode 100755 index 000000000..4b7442d68 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_ofd_algo.py @@ -0,0 +1,46 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from unittest import TestCase + +from mmengine import ConfigDict + +from mmrazor.models import OverhaulFeatureDistillation +from .toy_models import ToyOFDStudent + + +class TestSingleTeacherDistill(TestCase): + + def test_init(self): + + recorders_cfg = ConfigDict(bn=dict(type='ModuleOutputs', source='bn')) + + alg_kwargs = ConfigDict( + architecture=dict(type='ToyOFDStudent'), + teacher=dict(type='ToyOFDTeacher'), + distiller=dict( + type='OFDDistiller', + student_recorders=recorders_cfg, + teacher_recorders=recorders_cfg, + distill_losses=dict(loss_toy=dict(type='OFDLoss')), + connectors=dict(loss_1_tfeat=dict(type='OFDTeacherConnector')), + loss_forward_mappings=dict( + loss_toy=dict( + s_feature=dict(from_student=True, recorder='bn'), + t_feature=dict( + from_student=False, + recorder='bn', + connector='loss_1_tfeat'))))) + + alg = OverhaulFeatureDistillation(**alg_kwargs) + + teacher = ToyOFDStudent() + alg_kwargs_ = copy.deepcopy(alg_kwargs) + alg_kwargs_['teacher'] = teacher + alg = OverhaulFeatureDistillation(**alg_kwargs_) + self.assertEquals(alg.teacher, teacher) + + alg_kwargs_ = copy.deepcopy(alg_kwargs) + alg_kwargs_['teacher'] = 'teacher' + with self.assertRaisesRegex(TypeError, + 'teacher should be a `dict` or'): + _ = OverhaulFeatureDistillation(**alg_kwargs_) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_prune_algorithm.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_prune_algorithm.py new file mode 100755 index 000000000..00d615815 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_prune_algorithm.py @@ -0,0 +1,264 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +import unittest + +import torch +from mmcls.structures import ClsDataSample +from mmengine import MessageHub +from mmengine.model import BaseModel + +from mmrazor.models.algorithms.pruning.ite_prune_algorithm import ( + ItePruneAlgorithm, ItePruneConfigManager) +from mmrazor.registry import MODELS +from ...utils.set_dist_env import SetDistEnv + + +# @TASK_UTILS.register_module() +class ImageClassifierPseudoLoss: + """Calculate the pseudo loss to trace the topology of a `ImageClassifier` + in MMClassification with `BackwardTracer`.""" + + def __call__(self, model) -> torch.Tensor: + pseudo_img = torch.rand(2, 3, 32, 32) + pseudo_output = model(pseudo_img) + return pseudo_output.sum() + + +MODEL_CFG = dict( + _scope_='mmcls', + type='ImageClassifier', + backbone=dict( + type='ResNet', + depth=18, + num_stages=4, + out_indices=(3, ), + style='pytorch'), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=1000, + in_channels=512, + loss=dict(type='CrossEntropyLoss', loss_weight=1.0), + topk=(1, 5), + )) + +MUTATOR_CONFIG_NUM = dict( + type='ChannelMutator', + channel_unit_cfg={ + 'type': 'SequentialMutableChannelUnit', + 'default_args': { + 'choice_mode': 'number' + } + }) +MUTATOR_CONFIG_FLOAT = dict( + type='ChannelMutator', + channel_unit_cfg={ + 'type': 'SequentialMutableChannelUnit', + 'default_args': { + 'choice_mode': 'ratio' + } + }) + +if torch.cuda.is_available(): + DEVICE = torch.device('cuda:0') +else: + DEVICE = torch.device('cpu') + + +class TestItePruneAlgorithm(unittest.TestCase): + + def _set_epoch_ite(self, epoch, ite, max_epoch): + iter_per_epoch = 10 + message_hub = MessageHub.get_current_instance() + message_hub.update_info('epoch', epoch) + message_hub.update_info('max_epochs', max_epoch) + message_hub.update_info('max_iters', max_epoch * 10) + message_hub.update_info('iter', ite + iter_per_epoch * epoch) + + def fake_cifar_data(self): + imgs = torch.randn(16, 3, 32, 32).to(DEVICE) + data_samples = [ + ClsDataSample().set_gt_label(torch.randint(0, 10, + (16, ))).to(DEVICE) + ] + + return {'inputs': imgs, 'data_samples': data_samples} + + def test_ite_prune_config_manager(self): + iter_per_epoch = 10 + float_origin, float_target = 1.0, 0.5 + int_origin, int_target = 10, 5 + for origin, target, manager in [ + (float_origin, float_target, + ItePruneConfigManager({'a': float_target}, {'a': float_origin}, + 2 * iter_per_epoch, 5)), + (int_origin, int_target, + ItePruneConfigManager({'a': int_target}, {'a': int_origin}, + 2 * iter_per_epoch, 5)) + ]: + times = 1 + for e in range(1, 10): + for ite in range(iter_per_epoch): + self._set_epoch_ite(e, ite, 10) + if (e, ite) in [(0, 0), (2, 0), (4, 0), (6, 0), (8, 0)]: + self.assertTrue( + manager.is_prune_time(e * iter_per_epoch + ite)) + times += 1 + self.assertEqual( + manager.prune_at(e * iter_per_epoch + ite)['a'], + origin - (origin - target) * times / 5) + else: + self.assertFalse( + manager.is_prune_time(e * iter_per_epoch + ite)) + + def test_iterative_prune_int(self): + + data = self.fake_cifar_data() + + model = MODELS.build(MODEL_CFG) + mutator = MODELS.build(MUTATOR_CONFIG_FLOAT) + mutator.prepare_from_supernet(model) + prune_target = mutator.choice_template + + iter_per_epoch = 10 + epoch = 10 + epoch_step = 2 + times = 3 + + algorithm = ItePruneAlgorithm( + MODEL_CFG, + target_pruning_ratio=prune_target, + mutator_cfg=MUTATOR_CONFIG_FLOAT, + step_freq=epoch_step, + prune_times=times).to(DEVICE) + + for e in range(epoch): + for ite in range(10): + self._set_epoch_ite(e, ite, epoch) + + algorithm.forward( + data['inputs'], data['data_samples'], mode='loss') + self.assertEqual(times, algorithm.prune_times) + self.assertEqual(epoch_step * iter_per_epoch, + algorithm.step_freq) + + current_choices = algorithm.mutator.current_choices + target_pruning_ratio = algorithm.set_target_pruning_ratio( + prune_target, mutator.mutable_units) + for key in current_choices: + self.assertAlmostEqual( + current_choices[key], target_pruning_ratio[key], delta=0.1) + + def test_load_pretrained(self): + iter_per_epoch = 10 + epoch_step = 2 + times = 3 + data = self.fake_cifar_data() + + # prepare checkpoint + model_cfg = copy.deepcopy(MODEL_CFG) + model: BaseModel = MODELS.build(model_cfg) + checkpoint_path = os.path.dirname(__file__) + '/checkpoint' + torch.save(model.state_dict(), checkpoint_path) + + # build algorithm + model_cfg['init_cfg'] = { + 'type': 'Pretrained', + 'checkpoint': checkpoint_path + } + algorithm = ItePruneAlgorithm( + model_cfg, + mutator_cfg=MUTATOR_CONFIG_NUM, + target_pruning_ratio=None, + step_freq=epoch_step, + prune_times=times, + ).to(DEVICE) + algorithm.init_weights() + self._set_epoch_ite(4, 5, 6) + algorithm.forward(data['inputs'], data['data_samples'], mode='loss') + self.assertEqual(algorithm.step_freq, epoch_step * iter_per_epoch) + + # delete checkpoint + os.remove(checkpoint_path) + + def test_group_target_ratio(self): + + model = MODELS.build(MODEL_CFG) + mutator = MODELS.build(MUTATOR_CONFIG_FLOAT) + mutator.prepare_from_supernet(model) + mutator.set_choices(mutator.sample_choices()) + prune_target = mutator.choice_template + + iter_per_epoch = 10 + epoch_step = 2 + time = 2 + epoch = 6 + data = self.fake_cifar_data() + + prune_target['backbone.layer1.0.conv1_(0, 64)_64'] = 0.1 + prune_target['backbone.layer1.1.conv1_(0, 64)_64'] = 0.1 + + algorithm = ItePruneAlgorithm( + MODEL_CFG, + target_pruning_ratio=prune_target, + mutator_cfg=MUTATOR_CONFIG_FLOAT, + step_freq=epoch_step, + prune_times=time).to(DEVICE) + + algorithm.init_weights() + self._set_epoch_ite(1, 2, epoch) + algorithm.forward(data['inputs'], data['data_samples'], mode='loss') + self.assertEqual(algorithm.step_freq, epoch_step * iter_per_epoch) + + def test_dist_init(self): + if DEVICE != torch.device('cuda:0'): + self.skipTest('not use cuda') + with SetDistEnv(DEVICE == torch.device('cuda:0')): + iter_per_epoch = 10 + epoch_step = 2 + times = 3 + data = self.fake_cifar_data() + + # prepare checkpoint + model_cfg = copy.deepcopy(MODEL_CFG) + + algorithm = ItePruneAlgorithm( + model_cfg, + mutator_cfg=MUTATOR_CONFIG_NUM, + target_pruning_ratio=None, + step_freq=epoch_step, + prune_times=times, + ).to(DEVICE) + algorithm.init_weights() + self._set_epoch_ite(4, 5, 6) + algorithm.forward( + data['inputs'], data['data_samples'], mode='loss') + self.assertEqual(algorithm.step_freq, epoch_step * iter_per_epoch) + + def test_resume(self): + algorithm: ItePruneAlgorithm = ItePruneAlgorithm( + MODEL_CFG, + mutator_cfg=MUTATOR_CONFIG_NUM, + target_pruning_ratio=None, + step_freq=1, + prune_times=1, + ).to(DEVICE) + algorithm.mutator.set_choices(algorithm.mutator.sample_choices()) + state_dict = algorithm.state_dict() + print(state_dict.keys()) + + algorithm2: ItePruneAlgorithm = ItePruneAlgorithm( + MODEL_CFG, + mutator_cfg=MUTATOR_CONFIG_NUM, + target_pruning_ratio=None, + step_freq=1, + prune_times=1, + ).to(DEVICE) + + algorithm2.load_state_dict(state_dict) + + print(algorithm.mutator.current_choices) + print(algorithm2.mutator.current_choices) + self.assertDictEqual(algorithm.mutator.current_choices, + algorithm2.mutator.current_choices) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_self_distill.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_self_distill.py new file mode 100755 index 000000000..5755d56a7 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_self_distill.py @@ -0,0 +1,57 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch +from mmengine import ConfigDict + +from mmrazor.models import SelfDistill + + +class TestSelfDistill(TestCase): + + def test_init(self): + + student_recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + teacher_recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + + alg_kwargs = ConfigDict( + architecture=dict(type='ToyStudent'), + distiller=dict( + type='BYOTDistiller', + student_recorders=student_recorders_cfg, + teacher_recorders=teacher_recorders_cfg, + distill_losses=dict(loss_toy=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_toy=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='conv'))))) + + _ = SelfDistill(**alg_kwargs) + + def test_loss(self): + + student_recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + teacher_recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + + alg_kwargs = ConfigDict( + architecture=dict(type='ToyStudent'), + distiller=dict( + type='BYOTDistiller', + student_recorders=student_recorders_cfg, + teacher_recorders=teacher_recorders_cfg, + distill_losses=dict(loss_toy=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_toy=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='conv'))))) + + img = torch.randn(1, 3, 1, 1) + + alg = SelfDistill(**alg_kwargs) + losses = alg(img, mode='loss') + self.assertIn('distill.loss_toy', losses) + self.assertIn('student.loss', losses) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_single_teacher_distill.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_single_teacher_distill.py new file mode 100755 index 000000000..249e4878c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_single_teacher_distill.py @@ -0,0 +1,77 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from unittest import TestCase + +import torch +from mmengine import ConfigDict + +from mmrazor.models import SingleTeacherDistill +from .toy_models import ToyStudent + + +class TestSingleTeacherDistill(TestCase): + + def test_init(self): + + recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + + alg_kwargs = ConfigDict( + architecture=dict(type='ToyStudent'), + teacher=dict(type='ToyTeacher'), + distiller=dict( + type='ConfigurableDistiller', + student_recorders=recorders_cfg, + teacher_recorders=recorders_cfg, + distill_losses=dict(loss_toy=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_toy=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='conv'))))) + + alg = SingleTeacherDistill(**alg_kwargs) + + teacher = ToyStudent() + alg_kwargs_ = copy.deepcopy(alg_kwargs) + alg_kwargs_['teacher'] = teacher + alg = SingleTeacherDistill(**alg_kwargs_) + self.assertEquals(alg.teacher, teacher) + + alg_kwargs_ = copy.deepcopy(alg_kwargs) + alg_kwargs_['teacher'] = 'teacher' + with self.assertRaisesRegex(TypeError, + 'teacher should be a `dict` or'): + _ = SingleTeacherDistill(**alg_kwargs_) + + def test_loss(self): + + recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + + alg_kwargs = ConfigDict( + architecture=dict(type='ToyStudent'), + teacher=dict(type='ToyTeacher'), + distiller=dict( + type='ConfigurableDistiller', + student_recorders=recorders_cfg, + teacher_recorders=recorders_cfg, + distill_losses=dict(loss_toy=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_toy=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='conv'))))) + + img = torch.randn(1, 3, 1, 1) + + alg = SingleTeacherDistill(**alg_kwargs) + losses = alg(img, mode='loss') + self.assertIn('distill.loss_toy', losses) + self.assertIn('student.loss', losses) + + alg_kwargs_ = copy.deepcopy(alg_kwargs) + alg_kwargs_['teacher_trainable'] = True + alg = SingleTeacherDistill(**alg_kwargs_) + losses = alg(img, mode='loss') + self.assertIn('distill.loss_toy', losses) + self.assertIn('student.loss', losses) + self.assertIn('teacher.loss', losses) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_slimmable_network.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_slimmable_network.py new file mode 100755 index 000000000..2402e2493 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_slimmable_network.py @@ -0,0 +1,182 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +from typing import Dict, List, Tuple +from unittest import TestCase +from unittest.mock import Mock + +import pytest +import torch +import torch.distributed as dist +from mmcls.structures import ClsDataSample +from mmengine.optim import build_optim_wrapper + +from mmrazor.models.algorithms import SlimmableNetwork, SlimmableNetworkDDP + +MODEL_CFG = dict( + _scope_='mmcls', + type='ImageClassifier', + backbone=dict(type='MobileNetV2', widen_factor=1.5), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='LinearClsHead', + num_classes=1000, + in_channels=1920, + loss=dict(type='CrossEntropyLoss', loss_weight=1.0), + topk=(1, 5))) +CHANNEL_CFG_PATH = 'tests/data/MBV2_slimmable_channel_config.json' + +MUTATOR_CFG = dict( + type='SlimmableChannelMutator', + channel_unit_cfg=dict(type='SlimmableChannelUnit', units=CHANNEL_CFG_PATH), + parse_cfg=dict(type='ChannelAnalyzer')) + +CHANNEL_CFG_PATHS = [ + 'tests/data/MBV2_220M.yaml', + 'tests/data/MBV2_320M.yaml', + 'tests/data/MBV2_530M.yaml', +] + +OPTIMIZER_CFG = dict( + type='SGD', lr=0.5, momentum=0.9, nesterov=True, weight_decay=0.0001) +OPTIM_WRAPPER_CFG = dict(optimizer=OPTIMIZER_CFG, accumulative_counts=3) + + +class FakeMutator: + ... + + +class ToyDataPreprocessor(torch.nn.Module): + + def forward( + self, + data: Dict, + training: bool = True) -> Tuple[torch.Tensor, List[ClsDataSample]]: + return data + + +class TestSlimmable(TestCase): + device: str = 'cpu' + + def test_init(self) -> None: + + mutator_wrong_type = FakeMutator() + with pytest.raises(AttributeError): + _ = self.prepare_model(MODEL_CFG, mutator_wrong_type) + + # assert has prunable units + algo = SlimmableNetwork(MODEL_CFG, MUTATOR_CFG) + self.assertGreater(len(algo.mutator.mutable_units), 0) + + # assert can generate config template + mutator_cfg = copy.deepcopy(MUTATOR_CFG) + mutator_cfg['channel_unit_cfg']['units'] = {} + algo = SlimmableNetwork(MODEL_CFG, mutator_cfg) + try: + algo.mutator.config_template() + except Exception: + self.fail() + + def test_is_deployed(self) -> None: + slimmable_should_not_deployed = \ + SlimmableNetwork(MODEL_CFG, MUTATOR_CFG) + assert not slimmable_should_not_deployed.is_deployed + + slimmable_should_deployed = \ + SlimmableNetwork(MODEL_CFG, MUTATOR_CFG, deploy_index=0) + assert slimmable_should_deployed.is_deployed + + def test_slimmable_train_step(self) -> None: + algo = self.prepare_slimmable_model() + data = self._prepare_fake_data() + optim_wrapper_cfg = copy.deepcopy(OPTIM_WRAPPER_CFG) + optim_wrapper_cfg['accumulative_counts'] = 1 + optim_wrapper = build_optim_wrapper(algo, optim_wrapper_cfg) + fake_message_hub = Mock() + fake_message_hub.runtime_info = {'iter': 0, 'max_iters': 100} + optim_wrapper.message_hub = fake_message_hub + assert not algo._optim_wrapper_count_status_reinitialized + losses = algo.train_step(data, optim_wrapper) + + assert len(losses) == 3 + assert losses['subnet_0.loss'] > 0 + assert losses['subnet_1.loss'] > 0 + assert losses['subnet_2.loss'] > 0 + + self.assertTrue(algo._optim_wrapper_count_status_reinitialized) + self.assertEqual(optim_wrapper._inner_count, 3) + self.assertEqual(optim_wrapper._max_counts, 300) + + losses = algo.train_step(data, optim_wrapper) + assert algo._optim_wrapper_count_status_reinitialized + + def test_fixed_train_step(self) -> None: + algo = self.prepare_fixed_model() + data = self._prepare_fake_data() + optim_wrapper = build_optim_wrapper(algo, OPTIM_WRAPPER_CFG) + losses = algo.train_step(data, optim_wrapper) + + assert len(losses) == 1 + assert losses['loss'] > 0 + + def _prepare_fake_data(self) -> Dict: + imgs = torch.randn(16, 3, 224, 224).to(self.device) + data_samples = [ + ClsDataSample().set_gt_label(torch.randint(0, 1000, + (16, ))).to(self.device) + ] + + return {'inputs': imgs, 'data_samples': data_samples} + + def prepare_slimmable_model(self) -> SlimmableNetwork: + return self.prepare_model(MODEL_CFG, MUTATOR_CFG) + + def prepare_fixed_model(self) -> SlimmableNetwork: + return self.prepare_model(MODEL_CFG, MUTATOR_CFG, deploy=0) + + def prepare_model(self, + model_cfg: Dict, + mutator_cfg: Dict, + deploy=-1) -> SlimmableNetwork: + model = SlimmableNetwork(model_cfg, mutator_cfg, deploy, + ToyDataPreprocessor()) + model.to(self.device) + return model + + +class TestSlimmableDDP(TestSlimmable): + + @classmethod + def setUpClass(cls) -> None: + os.environ['MASTER_ADDR'] = 'localhost' + os.environ['MASTER_PORT'] = '12355' + + # initialize the process group + if torch.cuda.is_available(): + backend = 'nccl' + cls.device = 'cuda' + else: + backend = 'gloo' + dist.init_process_group(backend, rank=0, world_size=1) + + def prepare_model(self, + model_cfg: Dict, + mutator_cfg: Dict, + deploy=-1) -> SlimmableNetwork: + model = super().prepare_model(model_cfg, mutator_cfg, deploy) + return SlimmableNetworkDDP(module=model, find_unused_parameters=True) + + def test_is_deployed(self) -> None: + ... + + @pytest.mark.skipif( + not torch.cuda.is_available(), reason='cuda device is not avaliable') + def test_init(self) -> None: + model = super().prepare_slimmable_model() + ddp_model = SlimmableNetworkDDP(module=model, device_ids=[0]) + + self.assertIsInstance(ddp_model, SlimmableNetworkDDP) + + @classmethod + def tearDownClass(cls) -> None: + dist.destroy_process_group() diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_spos.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_spos.py new file mode 100755 index 000000000..537a16438 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/test_spos.py @@ -0,0 +1,85 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch +import torch.nn as nn +from mmengine.model import BaseModel + +from mmrazor.models import SPOS, NasMutator, OneShotMutableOP +from mmrazor.registry import MODELS +from mmrazor.structures import load_fix_subnet + +MUTATOR_CFG = dict(type='NasMutator') + + +@MODELS.register_module() +class ToySearchableModel(BaseModel): + + def __init__(self, data_preprocessor=None): + super().__init__(data_preprocessor=data_preprocessor, init_cfg=None) + convs = nn.ModuleDict({ + 'conv1': nn.Conv2d(3, 8, 1), + 'conv2': nn.Conv2d(3, 8, 1), + 'conv3': nn.Conv2d(3, 8, 1), + }) + self.mutable = OneShotMutableOP(convs) + self.bn = nn.BatchNorm2d(8) + + def forward(self, batch_inputs, data_samples=None, mode='tensor'): + if mode == 'loss': + out = self.bn(self.mutable(batch_inputs)) + return dict(loss=out) + elif mode == 'predict': + out = self.bn(self.mutable(batch_inputs)) + 1 + return out + elif mode == 'tensor': + out = self.bn(self.mutable(batch_inputs)) + 2 + return out + + +class TestSPOS(TestCase): + + def test_init(self): + # initiate spos when `norm_training` is True. + model = ToySearchableModel() + mutator = MODELS.build(MUTATOR_CFG) + alg = SPOS(model, mutator, norm_training=True) + alg.eval() + self.assertTrue(model.bn.training) + + # initiate spos with built `mutator`. + model = ToySearchableModel() + mutator = MODELS.build(MUTATOR_CFG) + alg = SPOS(model, mutator) + self.assertIs(alg.mutator, mutator) + + # initiate spos with unbuilt `mutator`. + mutator = dict(type='NasMutator') + alg = SPOS(model, mutator) + self.assertIsInstance(alg.mutator, NasMutator) + + # test load fix_subnet + fix_subnet = {'mutable': {'chosen': 'conv1'}} + load_fix_subnet(model, fix_subnet) + algo = SPOS(model, mutator) + self.assertEqual(algo.architecture.mutable.num_choices, 1) + + # initiate spos with error type `mutator`. + with self.assertRaisesRegex(TypeError, 'mutator should be'): + SPOS(model, model) + + def test_forward_loss(self): + inputs = torch.randn(1, 3, 8, 8) + model = ToySearchableModel() + + # supernet + mutator = MODELS.build(MUTATOR_CFG) + alg = SPOS(model, mutator) + loss = alg(inputs, mode='loss') + self.assertIsInstance(loss, dict) + + # subnet + fix_subnet = {'mutable': {'chosen': 'conv1'}} + load_fix_subnet(model, fix_subnet) + loss = model(inputs, mode='loss') + self.assertIsInstance(loss, dict) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/toy_models.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/toy_models.py new file mode 100755 index 000000000..09858afe0 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_algorithms/toy_models.py @@ -0,0 +1,94 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from dataclasses import dataclass + +import torch +from mmengine.model import BaseModel +from torch import nn + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class ToyStudent(BaseModel): + + def __init__(self, data_preprocessor=None): + super().__init__(data_preprocessor=data_preprocessor, init_cfg=None) + self.conv = nn.Conv2d(3, 1, 1) + + def forward(self, batch_inputs, data_samples=None, mode='tensor'): + if mode == 'loss': + out = self.conv(batch_inputs) + return dict(loss=out) + elif mode == 'predict': + out = self.conv(batch_inputs) + 1 + return out + elif mode == 'tensor': + out = self.conv(batch_inputs) + 2 + return out + + +@MODELS.register_module() +class ToyTeacher(ToyStudent): + + def __init__(self): + super().__init__() + + +@MODELS.register_module() +class ToyOFDStudent(BaseModel): + + def __init__(self, data_preprocessor=None): + super().__init__(data_preprocessor=data_preprocessor, init_cfg=None) + self.conv = nn.Conv2d(3, 1, 1) + self.bn = nn.BatchNorm2d(100) + + def forward(self, batch_inputs, data_samples=None, mode='tensor'): + if mode == 'loss': + out = self.bn(self.conv(batch_inputs)) + return dict(loss=out) + elif mode == 'predict': + out = self.bn(self.conv(batch_inputs) + 1) + return out + elif mode == 'tensor': + out = self.bn(self.conv(batch_inputs) + 2) + return out + + +@MODELS.register_module() +class ToyOFDTeacher(ToyOFDStudent): + + def __init__(self): + super().__init__() + + +@dataclass(frozen=True) +class Data: + latent_dim: int = 1 + + +@MODELS.register_module() +class ToyGenerator(BaseModel): + + def __init__(self, latent_dim=4, out_channel=3): + super().__init__(data_preprocessor=None, init_cfg=None) + self.latent_dim = latent_dim + self.out_channel = out_channel + self.conv = nn.Conv2d(self.latent_dim, self.out_channel, 1) + + # Imitate the structure of generator in separate model_wrapper. + self.module = Data(latent_dim=self.latent_dim) + + def forward(self, data=None, batch_size=4): + fakeimg_init = torch.randn(batch_size, self.latent_dim, 1, 1) + fakeimg = self.conv(fakeimg_init) + return fakeimg + + +@MODELS.register_module() +class ToyDistillLoss(nn.Module): + + def __init__(self): + super().__init__() + + def forward(self, arg1, arg2): + return arg1 + arg2 diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_autoformerbackbone.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_autoformerbackbone.py new file mode 100755 index 000000000..25217d1e8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_autoformerbackbone.py @@ -0,0 +1,60 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmrazor.models.architectures.dynamic_ops import ( + DynamicLinear, DynamicMultiheadAttention, DynamicPatchEmbed, + DynamicRelativePosition2D, DynamicSequential) +from mmrazor.models.mutables import MutableChannelContainer +from mmrazor.registry import MODELS + +arch_setting = dict( + mlp_ratios=[3.0, 3.5, 4.0], + num_heads=[8, 9, 10], + depth=[14, 15, 16], + embed_dims=[528, 576, 624]) + +BACKBONE_CFG = dict( + type='mmrazor.AutoformerBackbone', + arch_setting=arch_setting, + img_size=224, + patch_size=16, + in_channels=3, + norm_cfg=dict(type='mmrazor.DynamicLayerNorm'), + act_cfg=dict(type='GELU')) + + +def test_searchable_autoformer_mutable() -> None: + backbone = MODELS.build(BACKBONE_CFG) + + num_heads = backbone.arch_setting['num_heads'] + mlp_ratios = backbone.arch_setting['mlp_ratios'] + depth = backbone.arch_setting['depth'] + embed_dims = backbone.arch_setting['embed_dims'] + embed_dims_expansion = [i * j for i in mlp_ratios for j in embed_dims] + head_expansion = [i * 64 for i in num_heads] + + for name, module in backbone.named_modules(): + if isinstance(module, DynamicRelativePosition2D): + assert len(module.mutable_head_dims.current_choice) == 64 + elif isinstance(module, DynamicMultiheadAttention): + assert len( + module.mutable_embed_dims.current_choice) == max(embed_dims) + assert len(module.mutable_q_embed_dims.current_choice) == max( + head_expansion) + assert module.mutable_num_heads.choices == num_heads + elif isinstance(module, DynamicLinear): + if 'fc1' in name: + assert module.mutable_attrs['in_features'].num_channels == max( + embed_dims) + assert module.mutable_attrs[ + 'out_features'].num_channels == max(embed_dims_expansion) + elif 'fc2' in name: + assert module.mutable_attrs['in_features'].num_channels == max( + embed_dims_expansion) + assert module.mutable_attrs[ + 'out_features'].num_channels == max(embed_dims) + elif isinstance(module, DynamicPatchEmbed): + assert type(module.mutable_embed_dims) == MutableChannelContainer + assert len( + module.mutable_embed_dims.current_choice) == max(embed_dims) + elif isinstance(module, DynamicSequential): + assert module.mutable_depth.choices == depth + assert backbone.last_mutable.num_channels == max(embed_dims) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_dartsbackbone.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_dartsbackbone.py new file mode 100755 index 000000000..a4ae05950 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_dartsbackbone.py @@ -0,0 +1,117 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest +from unittest import TestCase + +import torch +import torch.nn as nn +from mmcls.models import * # noqa:F403,F401 + +from mmrazor.models import * # noqa:F403,F401 +from mmrazor.registry import MODELS + +MODELS.register_module(name='torchConv2d', module=nn.Conv2d, force=True) +MODELS.register_module(name='torchMaxPool2d', module=nn.MaxPool2d, force=True) +MODELS.register_module(name='torchAvgPool2d', module=nn.AvgPool2d, force=True) + + +class TestDartsBackbone(TestCase): + + def setUp(self) -> None: + self.mutable_cfg = dict( + type='DiffMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + padding=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + padding=2, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + padding=3, + ), + )) + + self.route_cfg = dict( + type='DiffChoiceRoute', + with_arch_param=True, + ) + + self.backbone_cfg = dict( + type='mmrazor.DartsBackbone', + in_channels=3, + base_channels=16, + num_layers=8, + num_nodes=4, + stem_multiplier=3, + out_indices=(7, ), + mutable_cfg=self.mutable_cfg, + route_cfg=self.route_cfg) + + self.mutator_cfg = dict( + type='NasMutator', + custom_groups=None, + ) + + def test_darts_backbone(self): + model = MODELS.build(self.backbone_cfg) + custom_group = self.generate_key(model) + + assert model is not None + self.mutable_cfg.update(custom_group=custom_group) + mutator = MODELS.build(self.mutator_cfg) + assert mutator is not None + + mutator.prepare_from_supernet(model) + # mutator.modify_supernet_forward(mutator.arch_params) + + inputs = torch.randn(4, 3, 224, 224) + outputs = model(inputs) + assert outputs is not None + + def test_darts_backbone_with_auxliary(self): + self.backbone_cfg.update( + auxliary=True, aux_channels=256, aux_out_channels=512) + model = MODELS.build(self.backbone_cfg) + custom_group = self.generate_key(model) + + assert model is not None + self.mutable_cfg.update(custom_groups=custom_group) + mutator = MODELS.build(self.mutator_cfg) + assert mutator is not None + mutator.prepare_from_supernet(model) + # mutator.modify_supernet_forward(mutator.arch_params) + + inputs = torch.randn(4, 3, 224, 224) + outputs = model(inputs) + assert outputs is not None + + def generate_key(self, model): + """auto generate custom group for darts.""" + tmp_dict = dict() + + for key, _ in model.named_modules(): + node_type = key.split('._candidates')[0].split('.')[-1].split( + '_')[0] + if node_type not in ['normal', 'reduce']: + # not supported type + continue + + node_name = key.split('._candidates')[0].split('.')[-1] + if node_name not in tmp_dict.keys(): + tmp_dict[node_name] = [key.split('._candidates')[0]] + else: + current_key = key.split('._candidates')[0] + if current_key not in tmp_dict[node_name]: + tmp_dict[node_name].append(current_key) + + return list(tmp_dict.values()) + + +if __name__ == '__main__': + unittest.main() diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v2.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v2.py new file mode 100755 index 000000000..e4ae70d5c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v2.py @@ -0,0 +1,116 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import sys + +import pytest +import torch +from mmcls.models import * # noqa: F401,F403 +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.models import * # noqa: F401,F403 +from mmrazor.models.mutables import * # noqa: F401,F403 +from mmrazor.registry import MODELS + +sys.path.append('tests/test_models/test_architectures/test_backbones') +from utils import MockMutable # noqa: E402 + +_FIRST_STAGE_MUTABLE = dict(type='MockMutable', choices=['c1']) +_OTHER_STAGE_MUTABLE = dict( + type='MockMutable', choices=['c1', 'c2', 'c3', 'c4']) +ARCHSETTING_CFG = [ + # Parameters to build layers. 4 parameters are needed to construct a + # layer, from left to right: channel, num_blocks, stride, mutable cfg. + [16, 1, 1, _FIRST_STAGE_MUTABLE], + [24, 2, 2, _OTHER_STAGE_MUTABLE], + [32, 3, 2, _OTHER_STAGE_MUTABLE], + [64, 4, 2, _OTHER_STAGE_MUTABLE], + [96, 3, 1, _OTHER_STAGE_MUTABLE], + [160, 3, 2, _OTHER_STAGE_MUTABLE], + [320, 1, 1, _OTHER_STAGE_MUTABLE] +] +NORM_CFG = dict(type='BN') +BACKBONE_CFG = dict( + type='mmrazor.SearchableMobileNetV2', + first_channels=32, + last_channels=1280, + widen_factor=1.0, + norm_cfg=NORM_CFG, + arch_setting=ARCHSETTING_CFG) + + +def test_searchable_mobilenet_mutable() -> None: + backbone = MODELS.build(BACKBONE_CFG) + + choices = ['c1', 'c2', 'c3', 'c4'] + mutable_nums = 0 + + for name, module in backbone.named_modules(): + if isinstance(module, MockMutable): + if 'layer1' in name: + assert module.choices == ['c1'] + else: + assert module.choices == choices + mutable_nums += 1 + + arch_setting = backbone.arch_setting + target_mutable_nums = 0 + for layer_cfg in arch_setting: + target_mutable_nums += layer_cfg[1] + assert mutable_nums == target_mutable_nums + + +def test_searchable_mobilenet_train() -> None: + backbone = MODELS.build(BACKBONE_CFG) + backbone.train(mode=True) + for m in backbone.modules(): + assert m.training + + backbone.norm_eval = True + backbone.train(mode=True) + for m in backbone.modules(): + if isinstance(m, _BatchNorm): + assert not m.training + else: + assert m.training + + x = torch.rand(10, 3, 224, 224) + assert len(backbone(x)) == 1 + + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['frozen_stages'] = 5 + backbone = MODELS.build(backbone_cfg) + backbone.train() + + for param in backbone.conv1.parameters(): + assert not param.requires_grad + for i in range(1, 8): + layer = getattr(backbone, f'layer{i}') + for m in layer.modules(): + if i <= 5: + assert not m.training + else: + assert m.training + for param in layer.parameters(): + if i <= 5: + assert not param.requires_grad + else: + assert param.requires_grad + + +def test_searchable_mobilenet_init() -> None: + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['out_indices'] = (10, ) + + with pytest.raises(ValueError): + MODELS.build(backbone_cfg) + + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['frozen_stages'] = 8 + + with pytest.raises(ValueError): + MODELS.build(backbone_cfg) + + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['widen_factor'] = 1.5 + backbone = MODELS.build(backbone_cfg) + assert backbone.out_channel == 1920 diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v3.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v3.py new file mode 100755 index 000000000..558e002af --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_mobilenet_v3.py @@ -0,0 +1,124 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import sys + +import pytest +import torch +from mmcls.models import * # noqa: F401,F403 +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.models.architectures.dynamic_ops import (BigNasConv2d, + DynamicBatchNorm2d, + DynamicSequential) +from mmrazor.models.mutables import (MutableChannelContainer, + OneShotMutableValue) +from mmrazor.models.utils import parse_values +from mmrazor.registry import MODELS + +sys.path.append('tests/test_models/test_architectures/test_backbones') + +arch_setting = dict( + kernel_size=[ + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + [3, 5, 2], + ], + num_blocks=[ + [1, 2, 1], + [3, 6, 1], + [3, 6, 1], + [1, 2, 1], + ], + expand_ratio=[ + [1, 1, 1], + [4, 6, 1], + [4, 6, 1], + [4, 6, 1], + [4, 6, 1], + ], + num_out_channels=[ + [16, 24, 8], # first layer + [16, 24, 8], + [24, 32, 8], + [32, 40, 8], + [64, 72, 8], + [72, 72, 8], # last layer + ]) + +BACKBONE_CFG = dict( + type='mmrazor.AttentiveMobileNetV3', + arch_setting=arch_setting, + out_indices=(4, ), + conv_cfg=dict(type='mmrazor.BigNasConv2d'), + norm_cfg=dict(type='mmrazor.DynamicBatchNorm2d', momentum=0.0)) + + +def test_attentive_mobilenet_mutable() -> None: + backbone = MODELS.build(BACKBONE_CFG) + + out_channels = backbone.arch_setting['num_out_channels'] + out_channels = parse_values(out_channels) + + for module in backbone.modules(): + if isinstance(module, BigNasConv2d): + assert isinstance(module.mutable_attrs.in_channels, + MutableChannelContainer) + assert isinstance(module.mutable_attrs.out_channels, + MutableChannelContainer) + elif isinstance(module, DynamicBatchNorm2d): + assert isinstance(module.mutable_attrs.num_features, + MutableChannelContainer) + elif isinstance(module, DynamicSequential): + assert isinstance(module.mutable_depth, OneShotMutableValue) + + assert backbone.last_mutable_channels.num_channels == max(out_channels[-1]) + + +def test_attentive_mobilenet_train() -> None: + backbone = MODELS.build(BACKBONE_CFG) + backbone.train(mode=True) + for m in backbone.modules(): + assert m.training + + backbone.norm_eval = True + backbone.train(mode=True) + for m in backbone.modules(): + if isinstance(m, _BatchNorm): + assert not m.training + + x = torch.rand(10, 3, 224, 224) + assert len(backbone(x)) == 1 + + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['frozen_stages'] = 2 + backbone = MODELS.build(backbone_cfg) + backbone.train() + + for param in backbone.first_conv.parameters(): + assert not param.requires_grad + for i, layer in enumerate(backbone.layers): + for param in layer.parameters(): + if i <= 1: + assert not param.requires_grad + else: + assert param.requires_grad + + +def test_searchable_mobilenet_init() -> None: + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['out_indices'] = (10, ) + + with pytest.raises(ValueError): + MODELS.build(backbone_cfg) + + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['frozen_stages'] = 8 + + with pytest.raises(ValueError): + MODELS.build(backbone_cfg) + + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['widen_factor'] = 1.5 + backbone = MODELS.build(backbone_cfg) + assert backbone.out_channels == 112 diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_shufflenet_v2.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_shufflenet_v2.py new file mode 100755 index 000000000..70060e4bb --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/test_searchable_shufflenet_v2.py @@ -0,0 +1,160 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +import sys +import tempfile + +import pytest +import torch +from mmcls.models import * # noqa: F401,F403 +from torch.nn import GroupNorm +from torch.nn.modules.batchnorm import _BatchNorm + +from mmrazor.models import * # noqa: F401,F403 +from mmrazor.models.mutables import * # noqa: F401,F403 +from mmrazor.registry import MODELS + +sys.path.append('tests/test_models/test_architectures/test_backbones') +from utils import MockMutable # noqa: E402 + +STAGE_MUTABLE = dict(type='MockMutable', choices=['c1', 'c2', 'c3', 'c4']) +ARCHSETTING_CFG = [ + # Parameters to build layers. 3 parameters are needed to construct a + # layer, from left to right: channel, num_blocks, mutable_cfg. + [64, 4, STAGE_MUTABLE], + [160, 4, STAGE_MUTABLE], + [320, 8, STAGE_MUTABLE], + [640, 4, STAGE_MUTABLE], +] + +NORM_CFG = dict(type='BN') +BACKBONE_CFG = dict( + type='mmrazor.SearchableShuffleNetV2', + widen_factor=1.0, + norm_cfg=NORM_CFG, + arch_setting=ARCHSETTING_CFG) + + +def test_searchable_shufflenet_v2_mutable() -> None: + backbone = MODELS.build(BACKBONE_CFG) + + choices = ['c1', 'c2', 'c3', 'c4'] + mutable_nums = 0 + + for module in backbone.modules(): + if isinstance(module, MockMutable): + assert module.choices == choices + mutable_nums += 1 + + arch_setting = backbone.arch_setting + target_mutable_nums = 0 + for layer_cfg in arch_setting: + target_mutable_nums += layer_cfg[1] + assert mutable_nums == target_mutable_nums + + +def test_searchable_shufflenet_v2_train() -> None: + backbone = MODELS.build(BACKBONE_CFG) + backbone.train(mode=True) + for m in backbone.modules(): + assert m.training + + backbone.norm_eval = True + backbone.train(mode=True) + for m in backbone.modules(): + if isinstance(m, _BatchNorm): + assert not m.training + else: + assert m.training + + x = torch.rand(10, 3, 224, 224) + assert len(backbone(x)) == 1 + + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['frozen_stages'] = 2 + backbone = MODELS.build(backbone_cfg) + backbone.train() + + for param in backbone.conv1.parameters(): + assert not param.requires_grad + for i in range(2): + layer = backbone.layers[i] + for m in layer.modules(): + if i < 2: + assert not m.training + else: + assert m.training + for param in layer.parameters(): + if i < 2: + assert not param.requires_grad + else: + assert param.requires_grad + + +def test_searchable_shufflenet_v2_init() -> None: + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['out_indices'] = (5, ) + + with pytest.raises(ValueError): + MODELS.build(backbone_cfg) + + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['frozen_stages'] = 5 + + with pytest.raises(ValueError): + MODELS.build(backbone_cfg) + + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['with_last_layer'] = False + with pytest.raises(ValueError): + MODELS.build(backbone_cfg) + + backbone_cfg['out_indices'] = (3, ) + backbone = MODELS.build(backbone_cfg) + assert len(backbone.layers) == 4 + + +def test_searchable_shufflenet_v2_init_weights() -> None: + backbone = MODELS.build(BACKBONE_CFG) + backbone.init_weights() + + for m in backbone.modules(): + if isinstance(m, (_BatchNorm, GroupNorm)): + if hasattr(m, 'weight') and m.weight is not None: + assert torch.equal(m.weight, torch.ones_like(m.weight)) + if hasattr(m, 'bias') and m.bias is not None: + bias_tensor = torch.ones_like(m.bias) + bias_tensor *= 0.0001 + assert torch.equal(bias_tensor, m.bias) + + temp_dir = tempfile.mkdtemp() + checkpoint_path = os.path.join(temp_dir, 'checkpoint.pth') + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone = MODELS.build(backbone_cfg) + torch.save(backbone.state_dict(), checkpoint_path) + backbone_cfg['init_cfg'] = dict( + type='Pretrained', checkpoint=checkpoint_path) + backbone = MODELS.build(backbone_cfg) + + name2weight = dict() + for name, m in backbone.named_modules(): + if isinstance(m, (_BatchNorm, GroupNorm)): + if hasattr(m, 'weight') and m.weight is not None: + name2weight[name] = m.weight.clone() + + backbone.init_weights() + for name, m in backbone.named_modules(): + if isinstance(m, (_BatchNorm, GroupNorm)): + if hasattr(m, 'weight') and m.weight is not None: + if name in name2weight: + assert torch.equal(name2weight[name], m.weight) + + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['norm_cfg'] = dict(type='BN', track_running_stats=False) + backbone = MODELS.build(backbone_cfg) + backbone.init_weights() + + backbone_cfg = copy.deepcopy(BACKBONE_CFG) + backbone_cfg['norm_cfg'] = dict(type='GN', num_groups=1) + backbone = MODELS.build(backbone_cfg) + backbone.init_weights() diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/utils.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/utils.py new file mode 100755 index 000000000..593faa4aa --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_backbones/utils.py @@ -0,0 +1,21 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, List + +from torch import Tensor +from torch.nn import Conv2d, Module + +from mmrazor.registry import MODELS + + +@MODELS.register_module() +class MockMutable(Module): + + def __init__(self, choices: List[str], module_kwargs: Dict) -> None: + super().__init__() + + self.choices = choices + self.module_kwargs = module_kwargs + self.conv = Conv2d(**module_kwargs, kernel_size=3, padding=3 // 2) + + def forward(self, x: Tensor) -> Tensor: + return self.conv(x) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_connectors/test_connectors.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_connectors/test_connectors.py new file mode 100755 index 000000000..80b3f88b2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_connectors/test_connectors.py @@ -0,0 +1,169 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch + +from mmrazor.models import (BYOTConnector, ConvModuleConnector, CRDConnector, + FBKDStudentConnector, FBKDTeacherConnector, + MGDConnector, NormConnector, Paraphraser, + TorchFunctionalConnector, TorchNNConnector, + Translator) + + +class TestConnector(TestCase): + + @classmethod + def setUpClass(cls): + cls.s_feat = torch.randn(1, 1, 5, 5) + cls.t_feat = torch.randn(1, 3, 5, 5) + + def test_convmodule_connector(self): + convmodule_connector_cfg = dict( + in_channel=1, out_channel=3, norm_cfg=dict(type='BN')) + convmodule_connector = ConvModuleConnector(**convmodule_connector_cfg) + + output = convmodule_connector.forward_train(self.s_feat) + assert output.size() == self.t_feat.size() + + convmodule_connector_cfg['order'] = ('conv', 'norm') + with self.assertRaises(AssertionError): + _ = ConvModuleConnector(**convmodule_connector_cfg) + + convmodule_connector_cfg['act_cfg'] = 'ReLU' + with self.assertRaises(AssertionError): + _ = ConvModuleConnector(**convmodule_connector_cfg) + + convmodule_connector_cfg['norm_cfg'] = 'BN' + with self.assertRaises(AssertionError): + _ = ConvModuleConnector(**convmodule_connector_cfg) + + convmodule_connector_cfg['conv_cfg'] = 'conv2d' + with self.assertRaises(AssertionError): + _ = ConvModuleConnector(**convmodule_connector_cfg) + + def test_crd_connector(self): + dim_out = 128 + crd_stu_connector = CRDConnector( + **dict(dim_in=1 * 5 * 5, dim_out=dim_out)) + + crd_tea_connector = CRDConnector( + **dict(dim_in=3 * 5 * 5, dim_out=dim_out)) + + assert crd_stu_connector.linear.in_features == 1 * 5 * 5 + assert crd_stu_connector.linear.out_features == dim_out + assert crd_tea_connector.linear.in_features == 3 * 5 * 5 + assert crd_tea_connector.linear.out_features == dim_out + + s_output = crd_stu_connector.forward_train(self.s_feat) + t_output = crd_tea_connector.forward_train(self.t_feat) + assert s_output.size() == t_output.size() + + def test_ft_connector(self): + stu_connector = Translator(**dict(in_channel=1, out_channel=2)) + + tea_connector = Paraphraser(**dict(in_channel=3, out_channel=2)) + + s_connect = stu_connector.forward_train(self.s_feat) + t_connect = tea_connector.forward_train(self.t_feat) + assert s_connect.size() == t_connect.size() + t_pretrain = tea_connector.forward_pretrain(self.t_feat) + assert t_pretrain.size() == torch.Size([1, 3, 5, 5]) + + def test_byot_connector(self): + byot_connector_cfg = dict( + in_channel=16, + out_channel=32, + num_classes=10, + expansion=4, + pool_size=4, + kernel_size=3, + stride=2, + init_cfg=None) + byot_connector = BYOTConnector(**byot_connector_cfg) + + s_feat = torch.randn(1, 16 * 4, 8, 8) + t_feat = torch.randn(1, 32 * 4) + labels = torch.randn(1, 10) + + output, logits = byot_connector.forward_train(s_feat) + assert output.size() == t_feat.size() + assert logits.size() == labels.size() + + def test_fbkd_connector(self): + fbkd_stuconnector_cfg = dict( + in_channels=16, reduction=2, sub_sample=True) + fbkd_stuconnector = FBKDStudentConnector(**fbkd_stuconnector_cfg) + + fbkd_teaconnector_cfg = dict( + in_channels=16, reduction=2, sub_sample=True) + fbkd_teaconnector = FBKDTeacherConnector(**fbkd_teaconnector_cfg) + + s_feat = torch.randn(1, 16, 8, 8) + t_feat = torch.randn(1, 16, 8, 8) + + s_output = fbkd_stuconnector(s_feat) + t_output = fbkd_teaconnector(t_feat) + + assert len(s_output) == 6 + assert len(t_output) == 5 + assert torch.equal(t_output[-1], t_feat) + + def test_torch_connector(self): + tensor1 = torch.rand(3, 3, 16, 16) + functional_pool_connector = TorchFunctionalConnector( + function_name='avg_pool2d', func_args=dict(kernel_size=4)) + tensor2 = functional_pool_connector.forward_train(tensor1) + assert tensor2.shape == torch.Size([3, 3, 4, 4]) + + with self.assertRaises(AssertionError): + functional_pool_connector = TorchFunctionalConnector() + with self.assertRaises(ValueError): + functional_pool_connector = TorchFunctionalConnector( + function_name='fake') + + nn_pool_connector = TorchNNConnector( + module_name='AvgPool2d', module_args=dict(kernel_size=4)) + tensor3 = nn_pool_connector.forward_train(tensor1) + assert tensor3.shape == torch.Size([3, 3, 4, 4]) + assert torch.equal(tensor2, tensor3) + + with self.assertRaises(AssertionError): + functional_pool_connector = TorchFunctionalConnector() + with self.assertRaises(ValueError): + functional_pool_connector = TorchNNConnector(module_name='fake') + + def test_mgd_connector(self): + s_feat = torch.randn(1, 16, 8, 8) + mgd_connector1 = MGDConnector( + student_channels=16, teacher_channels=16, lambda_mgd=0.65) + mgd_connector2 = MGDConnector( + student_channels=16, teacher_channels=32, lambda_mgd=0.65) + s_output1 = mgd_connector1.forward_train(s_feat) + s_output2 = mgd_connector2.forward_train(s_feat) + + assert s_output1.shape == torch.Size([1, 16, 8, 8]) + assert s_output2.shape == torch.Size([1, 32, 8, 8]) + + mgd_connector1 = MGDConnector( + student_channels=16, + teacher_channels=16, + lambda_mgd=0.65, + mask_on_channel=True) + mgd_connector2 = MGDConnector( + student_channels=16, + teacher_channels=32, + lambda_mgd=0.65, + mask_on_channel=True) + s_output1 = mgd_connector1.forward_train(s_feat) + s_output2 = mgd_connector2.forward_train(s_feat) + + assert s_output1.shape == torch.Size([1, 16, 8, 8]) + assert s_output2.shape == torch.Size([1, 32, 8, 8]) + + def test_norm_connector(self): + s_feat = torch.randn(2, 3, 2, 2) + norm_cfg = dict(type='BN', affine=False, track_running_stats=False) + norm_connector = NormConnector(3, norm_cfg) + output = norm_connector.forward_train(s_feat) + + assert output.shape == torch.Size([2, 3, 2, 2]) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_attention.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_attention.py new file mode 100755 index 000000000..4ed47c0ce --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_attention.py @@ -0,0 +1,50 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch + +from mmrazor.models.architectures.dynamic_ops import DynamicMultiheadAttention +from mmrazor.models.architectures.ops import MultiheadAttention +from mmrazor.models.mutables import (MutableChannelContainer, + OneShotMutableChannel, + OneShotMutableChannelUnit, + OneShotMutableValue) + + +class TestDynamicMHA(TestCase): + + def setUp(self) -> None: + self.mutable_num_heads = OneShotMutableValue( + value_list=[2, 4, 8], default_value=8) + self.mutable_embed_dims = OneShotMutableChannel(num_channels=128) + self.base_embed_dims = OneShotMutableChannel( + num_channels=8, candidate_choices=[8]) + self.mutable_q_embed_dims = self.mutable_num_heads * \ + self.base_embed_dims + + self.dynamic_m = DynamicMultiheadAttention(embed_dims=128, num_heads=8) + + OneShotMutableChannelUnit._register_channel_container( + self.dynamic_m, MutableChannelContainer) + + self.dynamic_m.register_mutable_attr('num_heads', + self.mutable_num_heads) + + MutableChannelContainer.register_mutable_channel_to_module( + self.dynamic_m, self.mutable_embed_dims, False) + MutableChannelContainer.register_mutable_channel_to_module( + self.dynamic_m, self.mutable_q_embed_dims, True, end=64) + MutableChannelContainer.register_mutable_channel_to_module( + self.dynamic_m.rel_pos_embed_k, self.base_embed_dims, False) + MutableChannelContainer.register_mutable_channel_to_module( + self.dynamic_m.rel_pos_embed_v, self.base_embed_dims, False) + + def test_forward(self) -> None: + x = torch.randn(8, 197, 128) + output = self.dynamic_m(x) + self.assertIsNotNone(output) + + def test_convert(self) -> None: + static_m = MultiheadAttention(embed_dims=100, num_heads=10) + dynamic_m = DynamicMultiheadAttention.convert_from(static_m) + self.assertIsNotNone(dynamic_m) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_container.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_container.py new file mode 100755 index 000000000..469ce0a9b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_container.py @@ -0,0 +1,46 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch.nn as nn +from torch.nn import Sequential + +from mmrazor.models.architectures.dynamic_ops import DynamicSequential +from mmrazor.models.mutables import OneShotMutableValue + + +class TestDynamicSequential(TestCase): + + def setUp(self) -> None: + self.layers = [ + nn.Linear(4, 5), + nn.Linear(5, 6), + nn.Linear(6, 7), + nn.Linear(7, 8), + ] + self.dynamic_m = DynamicSequential(*self.layers) + mutable_depth = OneShotMutableValue( + value_list=[2, 3, 4], default_value=3) + + self.dynamic_m.register_mutable_attr('depth', mutable_depth) + + def test_init(self) -> None: + self.assertEqual( + self.dynamic_m.get_mutable_attr('depth').current_choice, 3) + + def test_to_static_op(self) -> None: + with pytest.raises(RuntimeError): + self.dynamic_m.to_static_op() + + current_mutable = self.dynamic_m.get_mutable_attr('depth') + current_mutable.fix_chosen(current_mutable.dump_chosen().chosen) + + static_op = self.dynamic_m.to_static_op() + self.assertIsNotNone(static_op) + + def test_convert_from(self) -> None: + static_m = Sequential(*self.layers) + + dynamic_m = DynamicSequential.convert_from(static_m) + + self.assertIsNotNone(dynamic_m) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_conv.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_conv.py new file mode 100755 index 000000000..fd41d6b5c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_conv.py @@ -0,0 +1,314 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from typing import Type +from unittest import TestCase +from unittest.mock import MagicMock + +import pytest +import torch +from torch import nn + +from mmrazor.models.architectures.dynamic_ops import ( + BigNasConv2d, DynamicConv2d, DynamicConv2dAdaptivePadding, FuseConv2d, + OFAConv2d) +from mmrazor.models.mutables import (OneShotMutableValue, SimpleMutableChannel, + SquentialMutableChannel) +from mmrazor.structures.subnet import export_fix_subnet, load_fix_subnet +from ..utils import fix_dynamic_op + + +class TestDynamicConv2d(TestCase): + + def test_dynamic_conv2d_depthwise(self) -> None: + d_conv2d = DynamicConv2d( + in_channels=10, + out_channels=10, + groups=10, + kernel_size=3, + stride=1, + bias=True) + + mock_mutable = MagicMock() + with pytest.raises(ValueError): + d_conv2d.register_mutable_attr('in_channels', mock_mutable) + with pytest.raises(ValueError): + d_conv2d.register_mutable_attr('out_channels', mock_mutable) + + mock_mutable.current_mask = torch.rand(4) + with pytest.raises(ValueError): + d_conv2d.register_mutable_attr('in_channels', mock_mutable) + with pytest.raises(ValueError): + d_conv2d.register_mutable_attr('out_channels', mock_mutable) + + mutable_in_channels = SquentialMutableChannel(10) + mutable_out_channels = SquentialMutableChannel(10) + + d_conv2d.register_mutable_attr('in_channels', mutable_in_channels) + d_conv2d.register_mutable_attr('out_channels', mutable_out_channels) + + with pytest.raises(RuntimeError): + d_conv2d.to_static_op() + + d_conv2d.get_mutable_attr('in_channels').current_choice = 8 + d_conv2d.get_mutable_attr('out_channels').current_choice = 8 + + x = torch.rand(10, 8, 224, 224) + out1 = d_conv2d(x) + assert out1.size(1) == 8 + + with pytest.raises(RuntimeError): + _ = d_conv2d.to_static_op() + + fix_mutables = export_fix_subnet(d_conv2d)[0] + with pytest.raises(RuntimeError): + load_fix_subnet(d_conv2d, fix_mutables) + fix_dynamic_op(d_conv2d, fix_mutables) + + s_conv2d = d_conv2d.to_static_op() + assert s_conv2d.weight.size(0) == 8 + assert s_conv2d.weight.size(1) == 1 + assert s_conv2d.bias.size(0) == 8 + out2 = s_conv2d(x) + + assert torch.equal(out1, out2) + + +def mock_layeri_choice(d_conv2d: FuseConv2d) -> None: + # mock selected out channel proxy for `FuseConv2d` + c_out, _, _, _ = d_conv2d.weight.size() + print('d_conv2d.mutable_attrs:', d_conv2d.mutable_attrs) + if ('out_channels' in d_conv2d.mutable_attrs): + c_current_out = \ + d_conv2d.mutable_attrs['out_channels'].current_mask.sum().item() + else: + c_current_out = c_out + device = d_conv2d.weight.device + layeri_mock = torch.rand(c_current_out, c_out).to(device) + d_conv2d.set_forward_args(choice=layeri_mock) + + +@pytest.mark.parametrize('dynamic_class', [ + BigNasConv2d, DynamicConv2d, FuseConv2d, OFAConv2d, + DynamicConv2dAdaptivePadding +]) +@pytest.mark.parametrize('bias', [True, False]) +def test_dynamic_conv2d(bias: bool, dynamic_class: Type[nn.Conv2d]) -> None: + d_conv2d = dynamic_class( + in_channels=4, out_channels=10, kernel_size=3, stride=1, bias=bias) + + x_max = torch.rand(10, 4, 224, 224) + if (isinstance(d_conv2d, FuseConv2d)): + mock_layeri_choice(d_conv2d) + out_before_mutate = d_conv2d(x_max) + + mutable_in_channels = SquentialMutableChannel(4) + mutable_out_channels = SquentialMutableChannel(10) + d_conv2d.register_mutable_attr('in_channels', mutable_in_channels) + d_conv2d.register_mutable_attr('out_channels', mutable_out_channels) + + with pytest.raises(RuntimeError): + d_conv2d.to_static_op() + + d_conv2d.get_mutable_attr('in_channels').current_choice = 4 + d_conv2d.mutate_out_channels = 10 + + if (isinstance(d_conv2d, FuseConv2d)): + mock_layeri_choice(d_conv2d) + out_max = d_conv2d(x_max) + assert torch.equal(out_before_mutate, out_max) + + d_conv2d.get_mutable_attr('in_channels').current_choice = 3 + d_conv2d.mutable_out_channels.current_choice = 4 + + x = torch.rand(10, 3, 224, 224) + if (isinstance(d_conv2d, FuseConv2d)): + mock_layeri_choice(d_conv2d) + out1 = d_conv2d(x) + assert out1.size(1) == 4 + + fix_mutables = export_fix_subnet(d_conv2d)[0] + with pytest.raises(RuntimeError): + load_fix_subnet(d_conv2d, fix_mutables) + fix_dynamic_op(d_conv2d, fix_mutables) + + s_conv2d = d_conv2d.to_static_op() + assert s_conv2d.weight.size(0) == 4 + assert s_conv2d.weight.size(1) == 3 + if bias: + assert s_conv2d.bias.size(0) == 4 + out2 = s_conv2d(x) + + assert torch.equal(out1, out2) + + +@pytest.mark.parametrize('dynamic_class', + [BigNasConv2d, DynamicConv2d, FuseConv2d, OFAConv2d]) +@pytest.mark.parametrize( + ['is_mutate_in_channels', 'in_channels', 'out_channels'], [(True, 6, 10), + (False, 10, 4)]) +def test_dynamic_conv2d_mutable_single_channels( + is_mutate_in_channels: bool, in_channels: int, out_channels: int, + dynamic_class: Type[nn.Conv2d]) -> None: + d_conv2d = dynamic_class( + in_channels=10, out_channels=10, kernel_size=3, stride=1, bias=True) + mutable_channels = SquentialMutableChannel(10) + + if is_mutate_in_channels: + d_conv2d.register_mutable_attr('in_channels', mutable_channels) + else: + d_conv2d.register_mutable_attr('out_channels', mutable_channels) + + if (isinstance(d_conv2d, FuseConv2d)): + mock_layeri_choice(d_conv2d) + with pytest.raises(RuntimeError): + d_conv2d.to_static_op() + + if is_mutate_in_channels: + d_conv2d.get_mutable_attr('in_channels').current_choice = in_channels + assert d_conv2d.get_mutable_attr('out_channels') is None + else: + d_conv2d.get_mutable_attr('out_channels').current_choice = out_channels + assert d_conv2d.get_mutable_attr('in_channels') is None + + x = torch.rand(3, in_channels, 224, 224) + if (isinstance(d_conv2d, FuseConv2d)): + mock_layeri_choice(d_conv2d) + out1 = d_conv2d(x) + + assert out1.size(1) == out_channels + + with pytest.raises(RuntimeError): + _ = d_conv2d.to_static_op() + + fix_mutables = export_fix_subnet(d_conv2d)[0] + with pytest.raises(RuntimeError): + load_fix_subnet(d_conv2d, fix_mutables) + fix_dynamic_op(d_conv2d, fix_mutables) + + s_conv2d = d_conv2d.to_static_op() + assert s_conv2d.weight.size(0) == out_channels + assert s_conv2d.weight.size(1) == in_channels + out2 = s_conv2d(x) + + assert torch.equal(out1, out2) + + +@pytest.mark.parametrize('dynamic_class', [OFAConv2d, BigNasConv2d]) +@pytest.mark.parametrize('kernel_size_list', [[5], [3, 5, 7]]) +def test_kernel_dynamic_conv2d(dynamic_class: Type[nn.Conv2d], + kernel_size_list: bool) -> None: + + mutable_in_channels = SquentialMutableChannel(10) + mutable_out_channels = SquentialMutableChannel(10) + + mutable_kernel_size = OneShotMutableValue(value_list=kernel_size_list) + + d_conv2d = dynamic_class( + in_channels=10, + out_channels=10, + groups=1, + kernel_size=3 if kernel_size_list is None else max(kernel_size_list), + stride=1, + bias=True) + d_conv2d.register_mutable_attr('in_channels', mutable_in_channels) + d_conv2d.register_mutable_attr('out_channels', mutable_out_channels) + if kernel_size_list is not None: + copied_mutable_kernel_size = copy.deepcopy(mutable_kernel_size) + copied_d_conv2d = copy.deepcopy(d_conv2d) + + copied_mutable_kernel_size._value_list = [] + with pytest.raises(ValueError): + _ = copied_d_conv2d.register_mutable_attr( + 'kernel_size', copied_mutable_kernel_size) + + d_conv2d.register_mutable_attr('kernel_size', mutable_kernel_size) + assert d_conv2d.kernel_size_list == kernel_size_list + + with pytest.raises(RuntimeError): + d_conv2d.to_static_op() + + d_conv2d.get_mutable_attr('in_channels').current_choice = 8 + d_conv2d.get_mutable_attr('out_channels').current_choice = 8 + if kernel_size_list is not None: + kernel_size = mutable_kernel_size.sample_choice() + d_conv2d.mutable_attrs['kernel_size'].current_choice = kernel_size + + x = torch.rand(3, 8, 224, 224) + if (isinstance(d_conv2d, FuseConv2d)): + mock_layeri_choice(d_conv2d) + out1 = d_conv2d(x) + assert out1.size(1) == 8 + + fix_mutables = export_fix_subnet(d_conv2d)[0] + with pytest.raises(RuntimeError): + load_fix_subnet(d_conv2d, fix_mutables) + fix_dynamic_op(d_conv2d, fix_mutables) + + s_conv2d = d_conv2d.to_static_op() + assert s_conv2d.weight.size(0) == 8 + assert s_conv2d.weight.size(1) == 8 + assert s_conv2d.bias.size(0) == 8 + if kernel_size_list is not None: + assert s_conv2d.kernel_size == (kernel_size, kernel_size) + assert tuple(s_conv2d.weight.shape[2:]) == (kernel_size, kernel_size) + out2 = s_conv2d(x) + + assert torch.equal(out1, out2) + + +@pytest.mark.parametrize('dynamic_class', [OFAConv2d, BigNasConv2d]) +def test_mutable_kernel_dynamic_conv2d_grad( + dynamic_class: Type[nn.Conv2d]) -> None: + from mmrazor.models.architectures.dynamic_ops.mixins import \ + dynamic_conv_mixins + + kernel_size_list = [3, 5, 7] + d_conv2d = dynamic_class( + in_channels=3, + out_channels=10, + groups=1, + kernel_size=max(kernel_size_list), + stride=1, + bias=False) + + mutable_kernel_size = OneShotMutableValue(value_list=kernel_size_list) + d_conv2d.register_mutable_attr('kernel_size', mutable_kernel_size) + + x = torch.rand(3, 3, 224, 224, requires_grad=True) + + for kernel_size in kernel_size_list: + mutable_kernel_size.current_choice = kernel_size + if (isinstance(d_conv2d, FuseConv2d)): + mock_layeri_choice(d_conv2d) + out = d_conv2d(x).sum() + out.backward() + + start_offset, end_offset = dynamic_conv_mixins._get_current_kernel_pos( + max(kernel_size_list), kernel_size) + + mask = torch.ones_like( + d_conv2d.weight, requires_grad=False, dtype=torch.bool) + mask[:, :, start_offset:end_offset, start_offset:end_offset] = 0 + assert d_conv2d.weight.grad[mask].norm().item() == 0 + + d_conv2d.weight.grad.zero_() + + +def test_dynamic_group_wise_conv(): + conv = DynamicConv2d(8, 16, 3, 1, 1, groups=4) + in_mutable = SimpleMutableChannel(8) + out_mutable = SimpleMutableChannel(16) + in_mutable.current_choice = torch.tensor([0, 1] * 4).bool() + out_mutable.current_choice = torch.tensor([0, 1, 1, 0] * 4).bool() + conv.register_mutable_attr('in_channels', in_mutable) + conv.register_mutable_attr('out_channels', out_mutable) + + input = torch.rand([2, 4, 32, 32]) + y1 = conv(input) + assert list(y1.shape) == [2, 8, 32, 32] + + in_mutable.fix_chosen() + out_mutable.fix_chosen() + static_conv = conv.to_static_op() + y2 = static_conv(input) + assert torch.equal(y1, y2) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_embed.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_embed.py new file mode 100755 index 000000000..a656b2d5b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_embed.py @@ -0,0 +1,64 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +from mmcls.models.utils import PatchEmbed + +from mmrazor.models.architectures.dynamic_ops import DynamicPatchEmbed +from mmrazor.models.mutables import SquentialMutableChannel + + +class TestPatchEmbed(TestCase): + + def setUp(self): + self.dynamic_embed = DynamicPatchEmbed( + img_size=224, + in_channels=3, + embed_dims=100, + norm_cfg=dict(type='BN')) + + mutable_embed_dims = SquentialMutableChannel(num_channels=100) + mutable_embed_dims.current_choice = 50 + self.dynamic_embed.register_mutable_attr('embed_dims', + mutable_embed_dims) + + def test_patch_embed(self): + mutable = SquentialMutableChannel(num_channels=120) + + with pytest.raises(ValueError): + self.dynamic_embed.register_mutable_attr('embed_dims', mutable) + + self.assertTrue( + self.dynamic_embed.get_mutable_attr('embed_dims').current_choice == + 50) + + def test_convert(self): + static_m = PatchEmbed( + img_size=224, + in_channels=3, + embed_dims=768, + conv_cfg=dict(type='mmrazor.BigNasConv2d'), + norm_cfg=dict(type='mmrazor.DynamicBatchNorm2d')) + + dynamic_m = DynamicPatchEmbed.convert_from(static_m) + + self.assertIsNotNone(dynamic_m) + + mutable_embed_dims = SquentialMutableChannel(num_channels=768) + dynamic_m.register_mutable_attr('embed_dims', mutable_embed_dims) + mutable_embed_dims.current_choice = 512 + + def test_to_static_op(self): + mutable_embed_dims = SquentialMutableChannel(num_channels=100) + + mutable_embed_dims.current_choice = 10 + + with pytest.raises(RuntimeError): + self.dynamic_embed.to_static_op() + + mutable_embed_dims.fix_chosen(mutable_embed_dims.dump_chosen().chosen) + self.dynamic_embed.register_mutable_attr('embed_dims', + mutable_embed_dims) + static_op = self.dynamic_embed.to_static_op() + + self.assertIsNotNone(static_op) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_layernorm.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_layernorm.py new file mode 100755 index 000000000..619881f33 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_layernorm.py @@ -0,0 +1,45 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +from torch.nn import LayerNorm + +from mmrazor.models.architectures.dynamic_ops import DynamicLayerNorm +from mmrazor.models.mutables import SquentialMutableChannel + + +class TestDynamicLayerNorm(TestCase): + + def setUp(self) -> None: + self.dynamic_m = DynamicLayerNorm(100) + + mutable_num_features = SquentialMutableChannel(num_channels=100) + + mutable_num_features.current_choice = 50 + + self.dynamic_m.register_mutable_attr('num_features', + mutable_num_features) + + def test_init(self) -> None: + mutable = SquentialMutableChannel(num_channels=100) + self.dynamic_m.register_mutable_attr('in_channels', mutable) + self.dynamic_m.register_mutable_attr('out_channels', mutable) + + self.assertEqual( + self.dynamic_m.get_mutable_attr('num_features').current_choice, 50) + + def test_to_static_op(self): + with pytest.raises(RuntimeError): + self.dynamic_m.to_static_op() + + current_mutable = self.dynamic_m.get_mutable_attr('num_features') + current_mutable.fix_chosen(current_mutable.dump_chosen().chosen) + static_op = self.dynamic_m.to_static_op() + + self.assertIsNotNone(static_op) + + def test_convert(self) -> None: + static_m = LayerNorm(100) + dynamic_m = DynamicLayerNorm.convert_from(static_m) + + self.assertIsNotNone(dynamic_m) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_linear.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_linear.py new file mode 100755 index 000000000..aef840c2c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_linear.py @@ -0,0 +1,113 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Optional +from unittest.mock import MagicMock + +import pytest +import torch +from torch import nn + +from mmrazor.models.mutables import SquentialMutableChannel +from mmrazor.structures.subnet import export_fix_subnet, load_fix_subnet +from ..utils import fix_dynamic_op + +from mmrazor.models.architectures.dynamic_ops import ( # isort:skip + DynamicLinear, DynamicLinearMixin) + + +@pytest.mark.parametrize('bias', [True, False]) +def test_dynamic_linear(bias) -> None: + mutable_in_features = SquentialMutableChannel(10) + mutable_out_features = SquentialMutableChannel(10) + + d_linear = DynamicLinear(in_features=10, out_features=10, bias=bias) + + mock_mutable = MagicMock() + with pytest.raises(ValueError): + d_linear.register_mutable_attr('in_features', mock_mutable) + with pytest.raises(ValueError): + d_linear.register_mutable_attr('out_features', mock_mutable) + + mock_mutable.current_mask = torch.rand(8) + with pytest.raises(ValueError): + d_linear.register_mutable_attr('in_features', mock_mutable) + with pytest.raises(ValueError): + d_linear.register_mutable_attr('out_features', mock_mutable) + + d_linear.register_mutable_attr('in_features', mutable_in_features) + d_linear.register_mutable_attr('out_features', mutable_out_features) + + with pytest.raises(RuntimeError): + d_linear.to_static_op() + + d_linear.get_mutable_attr('in_channels').current_choice = 8 + d_linear.get_mutable_attr('out_channels').current_choice = 4 + + x = torch.rand(10, 8) + out1 = d_linear(x) + assert out1.size(1) == 4 + + with pytest.raises(RuntimeError): + _ = d_linear.to_static_op() + + fix_mutables = export_fix_subnet(d_linear)[0] + with pytest.raises(RuntimeError): + load_fix_subnet(d_linear, fix_mutables) + fix_dynamic_op(d_linear, fix_mutables) + assert isinstance(d_linear, nn.Linear) + assert isinstance(d_linear, DynamicLinearMixin) + + s_linear = d_linear.to_static_op() + assert s_linear.weight.size(0) == 4 + assert s_linear.weight.size(1) == 8 + if bias: + assert s_linear.bias.size(0) == 4 + assert not isinstance(s_linear, DynamicLinearMixin) + assert isinstance(s_linear, nn.Linear) + out2 = s_linear(x) + + assert torch.equal(out1, out2) + + +@pytest.mark.parametrize( + ['is_mutate_in_features', 'in_features', 'out_features'], [(True, 6, 10), + (False, 10, 4), + (None, 10, 10)]) +def test_dynamic_linear_mutable_single_features( + is_mutate_in_features: Optional[bool], in_features: int, + out_features: int) -> None: + d_linear = DynamicLinear(in_features=10, out_features=10, bias=True) + mutable_channels = SquentialMutableChannel(10) + + if is_mutate_in_features is not None: + if is_mutate_in_features: + d_linear.register_mutable_attr('in_channels', mutable_channels) + else: + d_linear.register_mutable_attr('out_channels', mutable_channels) + + if is_mutate_in_features: + d_linear.get_mutable_attr('in_channels').current_choice = in_features + assert d_linear.get_mutable_attr('out_channels') is None + elif is_mutate_in_features is False: + d_linear.get_mutable_attr('out_channels').current_choice = out_features + assert d_linear.get_mutable_attr('in_channels') is None + + x = torch.rand(3, in_features) + out1 = d_linear(x) + + assert out1.size(1) == out_features + + if is_mutate_in_features is not None: + with pytest.raises(RuntimeError): + _ = d_linear.to_static_op() + + fix_mutables = export_fix_subnet(d_linear)[0] + with pytest.raises(RuntimeError): + load_fix_subnet(d_linear, fix_mutables) + fix_dynamic_op(d_linear, fix_mutables) + + s_linear = d_linear.to_static_op() + assert s_linear.weight.size(0) == out_features + assert s_linear.weight.size(1) == in_features + out2 = s_linear(x) + + assert torch.equal(out1, out2) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_norm.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_norm.py new file mode 100755 index 000000000..9a5319a09 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_norm.py @@ -0,0 +1,154 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest +from typing import Tuple, Type +from unittest.mock import MagicMock + +import pytest +import torch +import torch.distributed as dist +from torch import nn + +from mmrazor.models.architectures.dynamic_ops import (DynamicBatchNorm1d, + DynamicBatchNorm2d, + DynamicBatchNorm3d, + DynamicMixin, + DynamicSyncBatchNorm) +from mmrazor.models.mutables import SquentialMutableChannel +from mmrazor.structures.subnet import export_fix_subnet, load_fix_subnet +from ..utils import fix_dynamic_op + + +@pytest.mark.parametrize('dynamic_class,input_shape', + [(DynamicBatchNorm1d, (10, 8, 224)), + (DynamicBatchNorm2d, (10, 8, 224, 224)), + (DynamicBatchNorm3d, (10, 8, 3, 224, 224))]) +@pytest.mark.parametrize('affine', [True, False]) +@pytest.mark.parametrize('track_running_stats', [True, False]) +def test_dynamic_bn(dynamic_class: Type[nn.modules.batchnorm._BatchNorm], + input_shape: Tuple[int], affine: bool, + track_running_stats: bool) -> None: + mutable_num_features = SquentialMutableChannel(10) + + d_bn = dynamic_class( + num_features=10, + affine=affine, + track_running_stats=track_running_stats) + if not affine and not track_running_stats: + with pytest.raises(RuntimeError): + d_bn.register_mutable_attr('num_features', mutable_num_features) + else: + mock_mutable = MagicMock() + with pytest.raises(ValueError): + d_bn.register_mutable_attr('num_features', mock_mutable) + mock_mutable.current_mask = torch.rand(5) + with pytest.raises(ValueError): + d_bn.register_mutable_attr('num_features', mock_mutable) + + d_bn.register_mutable_attr('num_features', mutable_num_features) + assert d_bn.get_mutable_attr('in_channels') is d_bn.get_mutable_attr( + 'out_channels') + + if affine or track_running_stats: + d_bn.get_mutable_attr('in_channels').current_choice = 8 + + with pytest.raises(ValueError): + wrong_shape_x = torch.rand(8) + _ = d_bn(wrong_shape_x) + + x = torch.rand(*input_shape) + out1 = d_bn(x) + assert out1.size(1) == 8 + + fix_mutables = export_fix_subnet(d_bn)[0] + with pytest.raises(RuntimeError): + load_fix_subnet(d_bn, fix_mutables) + fix_dynamic_op(d_bn, fix_mutables) + assert isinstance(d_bn, dynamic_class) + assert isinstance(d_bn, DynamicMixin) + + s_bn = d_bn.to_static_op() + if affine: + assert s_bn.weight.size(0) == 8 + assert s_bn.bias.size(0) == 8 + if track_running_stats: + assert s_bn.running_mean.size(0) == 8 + assert s_bn.running_var.size(0) == 8 + assert not isinstance(s_bn, DynamicMixin) + assert isinstance(s_bn, d_bn.static_op_factory) + out2 = s_bn(x) + + assert torch.equal(out1, out2) + + +@pytest.mark.parametrize(['static_class', 'dynamic_class', 'input_shape'], + [(nn.BatchNorm1d, DynamicBatchNorm1d, (10, 8, 224)), + (nn.BatchNorm2d, DynamicBatchNorm2d, + (10, 8, 224, 224)), + (nn.BatchNorm3d, DynamicBatchNorm3d, + (10, 8, 3, 224, 224))]) +def test_bn_track_running_stats( + static_class: Type[nn.modules.batchnorm._BatchNorm], + dynamic_class: Type[nn.modules.batchnorm._BatchNorm], + input_shape: Tuple[int], +) -> None: + mutable_num_features = SquentialMutableChannel(10) + mutable_num_features.current_choice = 8 + d_bn = dynamic_class( + num_features=10, track_running_stats=True, affine=False) + d_bn.register_mutable_attr('num_features', mutable_num_features) + + s_bn = static_class(num_features=8, track_running_stats=True, affine=False) + + d_bn.train() + s_bn.train() + mask = d_bn._get_num_features_mask() + for _ in range(10): + x = torch.rand(*input_shape) + _ = d_bn(x) + _ = s_bn(x) + + d_running_mean = d_bn.running_mean[mask] + d_running_var = d_bn.running_var[mask] + + assert torch.equal(s_bn.running_mean, d_running_mean) + assert torch.equal(s_bn.running_var, d_running_var) + + d_bn.eval() + s_bn.eval() + x = torch.rand(*input_shape) + + assert torch.equal(d_bn(x), s_bn(x)) + + +class TestDynamicSyncBn(unittest.TestCase): + + def test_init(self): + if not torch.cuda.is_available(): + self.skipTest('no cuda') + import os + os.environ['MASTER_ADDR'] = 'localhost' + os.environ['MASTER_PORT'] = '12355' + + # initialize the process group + if torch.cuda.is_available(): + backend = 'nccl' + device = torch.device('cuda:0') + else: + backend = 'gloo' + device = torch.device('cpu') + dist.init_process_group(backend, rank=0, world_size=1) + + x = torch.rand([2, 8, 224, 224]).to(device) + norm = DynamicSyncBatchNorm(8).to(device) + _ = norm(x) + + mutable_num_features = SquentialMutableChannel(8) + mutable_num_features.current_choice = 4 + norm.register_mutable_attr('in_channels', mutable_num_features) + + with pytest.raises(Exception): + norm(x) + + x = torch.rand([2, 4, 32, 32]).to(device) + _ = norm(x) + dist.destroy_process_group() diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_relative_position.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_relative_position.py new file mode 100755 index 000000000..9f82fe1d3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_relative_position.py @@ -0,0 +1,55 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch + +from mmrazor.models.architectures.dynamic_ops import DynamicRelativePosition2D +from mmrazor.models.architectures.ops import RelativePosition2D +from mmrazor.models.mutables import SquentialMutableChannel + + +class TestDynamicRP(TestCase): + + def setUp(self) -> None: + mutable_head_dims = SquentialMutableChannel(num_channels=8) + + self.dynamic_rp = DynamicRelativePosition2D( + head_dims=8, max_relative_position=14) + + mutable_head_dims.current_choice = 6 + self.dynamic_rp.register_mutable_attr('head_dims', mutable_head_dims) + + def test_mutable_attrs(self) -> None: + + assert self.dynamic_rp.mutable_head_dims.current_choice == 6 + + embed = self.dynamic_rp.forward(14, 14) + + self.assertIsNotNone(embed) + + def test_convert(self): + static_model = RelativePosition2D( + head_dims=10, max_relative_position=14) + + dynamic_model = DynamicRelativePosition2D.convert_from(static_model) + + self.assertIsNotNone(dynamic_model) + + def test_to_static_op(self): + with pytest.raises(RuntimeError): + static_m = self.dynamic_rp.to_static_op() + + mutable = SquentialMutableChannel(num_channels=8) + mutable.current_choice = 4 + + mutable.fix_chosen(mutable.dump_chosen().chosen) + + self.dynamic_rp.register_mutable_attr('head_dims', mutable) + static_m = self.dynamic_rp.to_static_op() + + self.assertIsNotNone(static_m) + + dynamic_output = self.dynamic_rp.forward(14, 14) + static_output = static_m.forward(14, 14) + self.assertTrue(torch.equal(dynamic_output, static_output)) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_resizer.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_resizer.py new file mode 100755 index 000000000..7fc93094e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/test_bricks/test_dynamic_resizer.py @@ -0,0 +1,81 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch + +from mmrazor.models.architectures.dynamic_ops import DynamicInputResizer +from mmrazor.models.architectures.ops import InputResizer +from mmrazor.models.mutables import OneShotMutableValue +from mmrazor.registry import MODELS + +_INPUT_MUTABLE = dict( + input_resizer=dict(type='DynamicInputResizer'), + mutable_shape=dict( + type='OneShotMutableValue', + value_list=[[192, 192], [224, 224], [256, 256], [288, 288]], + default_value=[224, 224])) + + +class TestInputResizer(TestCase): + + def setUp(self): + input_resizer_cfg_ = _INPUT_MUTABLE['input_resizer'] + self.dynamic_input_resizer = MODELS.build(input_resizer_cfg_) + + if not isinstance(self.dynamic_input_resizer, DynamicInputResizer): + raise TypeError('input_resizer should be a `dict` or ' + '`DynamicInputResizer` instance, but got ' + f'{type(self.dynamic_input_resizer)}') + + self.mutable_shape = OneShotMutableValue( + value_list=[[192, 192], [224, 224], [256, 256], [288, 288]], + default_value=[224, 224]) + + self.dynamic_input_resizer.register_mutable_attr( + 'shape', self.mutable_shape) + + self.assertTrue( + self.dynamic_input_resizer.get_mutable_attr('shape').current_choice + == [224, 224]) + + def test_convert(self): + static_m = InputResizer() + + dynamic_m = DynamicInputResizer.convert_from(static_m) + + self.assertIsNotNone(dynamic_m) + + def test_to_static_op(self): + input = torch.randn(1, 3, 224, 224) + + mutable_shape = OneShotMutableValue( + value_list=[192, 224, 256], default_value=224) + mutable_shape.current_choice = 192 + + with pytest.raises(RuntimeError): + self.dynamic_input_resizer.to_static_op() + + mutable_shape.fix_chosen(mutable_shape.dump_chosen().chosen) + self.dynamic_input_resizer.register_mutable_attr( + 'shape', mutable_shape) + static_op = self.dynamic_input_resizer.to_static_op() + x = static_op(input) + static_m = InputResizer() + output = static_m(input, mutable_shape.current_choice) + self.assertTrue(torch.equal(x, output)) + + mutable_shape = OneShotMutableValue( + value_list=[[192, 192], [224, 224], [256, 256], [288, 288]], + default_value=[224, 224]) + mutable_shape.current_choice = [192, 192] + mutable_shape.fix_chosen(mutable_shape.dump_chosen().chosen) + self.dynamic_input_resizer.register_mutable_attr( + 'shape', mutable_shape) + + static_op = self.dynamic_input_resizer.to_static_op() + self.assertIsNotNone(static_op) + x = self.dynamic_input_resizer(input) + assert torch.equal( + self.dynamic_input_resizer(input), + static_op(input, mutable_shape.current_choice)) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/utils.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/utils.py new file mode 100755 index 000000000..e448f300e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_dynamic_op/utils.py @@ -0,0 +1,20 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Dict, Optional + +from mmrazor.models.architectures.dynamic_ops import DynamicMixin +from mmrazor.utils.typing import DumpChosen + + +def fix_dynamic_op(op: DynamicMixin, + fix_mutables: Optional[Dict] = None) -> None: + for name, mutable in op.mutable_attrs.items(): + + if fix_mutables is not None: + chosen = fix_mutables[f'mutable_attrs.{name}'] + else: + chosen = mutable.dump_chosen() + + if not isinstance(chosen, DumpChosen): + chosen = DumpChosen(**chosen) + + mutable.fix_chosen(chosen.chosen) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_generators/test_generators.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_generators/test_generators.py new file mode 100755 index 000000000..93548c067 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_architectures/test_generators/test_generators.py @@ -0,0 +1,73 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmrazor.models import DAFLGenerator, ZSKTGenerator + + +def test_dafl_generator(): + dafl_generator = DAFLGenerator( + img_size=32, latent_dim=10, hidden_channels=32) + z_batch = torch.randn(8, 10) + fake_img = dafl_generator(z_batch) + assert fake_img.size() == torch.Size([8, 3, 32, 32]) + with pytest.raises(AssertionError): + z_batch = torch.randn(8, 11) + fake_img = dafl_generator(z_batch) + with pytest.raises(ValueError): + z_batch = torch.randn(8, 10, 1, 1) + fake_img = dafl_generator(z_batch) + + fake_img = dafl_generator(batch_size=8) + assert fake_img.size() == torch.Size([8, 3, 32, 32]) + + # scale_factor = 4 + dafl_generator = DAFLGenerator( + img_size=32, latent_dim=10, hidden_channels=32, scale_factor=4) + z_batch = torch.randn(8, 10) + fake_img = dafl_generator(z_batch) + assert fake_img.size() == torch.Size([8, 3, 32, 32]) + + # hidden_channels=64 + dafl_generator = DAFLGenerator( + img_size=32, latent_dim=10, hidden_channels=64) + z_batch = torch.randn(8, 10) + fake_img = dafl_generator(z_batch) + assert fake_img.size() == torch.Size([8, 3, 32, 32]) + + with pytest.raises(AssertionError): + fake_img = dafl_generator(data=None, batch_size=0) + + +def test_zskt_generator(): + zskt_generator = ZSKTGenerator( + img_size=32, latent_dim=10, hidden_channels=32) + z_batch = torch.randn(8, 10) + fake_img = zskt_generator(z_batch) + assert fake_img.size() == torch.Size([8, 3, 32, 32]) + with pytest.raises(AssertionError): + z_batch = torch.randn(8, 11) + fake_img = zskt_generator(z_batch) + with pytest.raises(ValueError): + z_batch = torch.randn(8, 10, 1, 1) + fake_img = zskt_generator(z_batch) + + fake_img = zskt_generator(batch_size=8) + assert fake_img.size() == torch.Size([8, 3, 32, 32]) + + # scale_factor = 4 + zskt_generator = ZSKTGenerator( + img_size=32, latent_dim=10, hidden_channels=32, scale_factor=4) + z_batch = torch.randn(8, 10) + fake_img = zskt_generator(z_batch) + assert fake_img.size() == torch.Size([8, 3, 32, 32]) + + # hidden_channels=64 + zskt_generator = ZSKTGenerator( + img_size=32, latent_dim=10, hidden_channels=64) + z_batch = torch.randn(8, 10) + fake_img = zskt_generator(z_batch) + assert fake_img.size() == torch.Size([8, 3, 32, 32]) + + with pytest.raises(AssertionError): + fake_img = zskt_generator(data=None, batch_size=0) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_classifier/test_imageclassifier.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_classifier/test_imageclassifier.py new file mode 100755 index 000000000..169d34995 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_classifier/test_imageclassifier.py @@ -0,0 +1,45 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +from mmrazor.models import SearchableImageClassifier + + +class TestSearchableImageClassifier(TestCase): + + def test_init(self): + + arch_setting = dict( + mlp_ratios=[3.0, 3.5, 4.0], + num_heads=[8, 9, 10], + depth=[14, 15, 16], + embed_dims=[528, 576, 624]) + + supernet_kwargs = dict( + backbone=dict( + _scope_='mmrazor', + type='AutoformerBackbone', + arch_setting=arch_setting), + neck=None, + head=dict( + _scope_='mmrazor', + type='DynamicLinearClsHead', + num_classes=1000, + in_channels=624, + loss=dict( + type='mmcls.LabelSmoothLoss', + mode='original', + num_classes=1000, + label_smooth_val=0.1, + loss_weight=1.0), + topk=(1, 5)), + connect_head=dict(connect_with_backbone='backbone.last_mutable'), + ) + + supernet = SearchableImageClassifier(**supernet_kwargs) + + # test connect_with_backbone + self.assertEqual( + supernet.backbone.last_mutable.activated_channels, + len( + supernet.head.fc.get_mutable_attr( + 'in_channels').current_choice)) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_byot_distill.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_byot_distill.py new file mode 100755 index 000000000..c75381c7f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_byot_distill.py @@ -0,0 +1,69 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from unittest import TestCase + +from mmengine import ConfigDict + +from mmrazor.models import BYOTDistiller + + +class TestBYOTDistiller(TestCase): + + def test_init(self): + + student_recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + teacher_recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + + distiller_kwargs = ConfigDict( + student_recorders=student_recorders_cfg, + teacher_recorders=teacher_recorders_cfg, + distill_losses=dict(loss_toy=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_toy=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='conv'), + )), + ) + + _ = BYOTDistiller(**distiller_kwargs) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_['distill_losses'] = None + with self.assertRaisesRegex(AssertionError, + '"loss_toy" is not in distill'): + _ = BYOTDistiller(**distiller_kwargs_) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_['distill_losses'] = dict( + toy=dict(type='ToyDistillLoss')) + distiller_kwargs_['loss_forward_mappings'] = dict( + toy=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='conv'))) + with self.assertWarnsRegex(UserWarning, 'Warning: If toy is a'): + _ = BYOTDistiller(**distiller_kwargs_) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_['loss_forward_mappings'] = None + _ = BYOTDistiller(**distiller_kwargs_) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_['loss_forward_mappings'] = list('AAA') + + with self.assertRaisesRegex(TypeError, + 'loss_forward_mappings should be '): + _ = BYOTDistiller(**distiller_kwargs_) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_['loss_forward_mappings']['loss_toy'] = list() + with self.assertRaisesRegex( + TypeError, 'Each item of loss_forward_mappings should be '): + _ = BYOTDistiller(**distiller_kwargs_) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_.loss_forward_mappings.loss_toy.arg1.from_student = '' + with self.assertRaisesRegex(TypeError, + 'from_student should be a bool'): + _ = BYOTDistiller(**distiller_kwargs_) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_configurable_distill.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_configurable_distill.py new file mode 100755 index 000000000..62e0292d5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_distillers/test_configurable_distill.py @@ -0,0 +1,115 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from unittest import TestCase + +import torch +import torch.nn as nn +from mmengine import ConfigDict + +from mmrazor.models import ConfigurableDistiller +from mmrazor.registry import MODELS + + +class ToyDistillLoss(torch.nn.Module): + + def __init__(self): + super().__init__() + + def forward(self, arg1, arg2): + return arg1 + arg2 + + +class TestConfigurableDistiller(TestCase): + + def setUp(self): + MODELS.register_module(module=ToyDistillLoss, force=True) + + def tearDown(self): + MODELS.module_dict.pop('ToyDistillLoss') + + def test_init(self): + + recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + + distiller_kwargs = ConfigDict( + student_recorders=recorders_cfg, + teacher_recorders=recorders_cfg, + distill_losses=dict(loss_toy=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_toy=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='conv'), + )), + ) + + _ = ConfigurableDistiller(**distiller_kwargs) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_['distill_losses'] = None + with self.assertRaisesRegex(AssertionError, + '"loss_toy" is not in distill'): + _ = ConfigurableDistiller(**distiller_kwargs_) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_['distill_losses'] = dict( + toy=dict(type='ToyDistillLoss')) + distiller_kwargs_['loss_forward_mappings'] = dict( + toy=dict( + arg1=dict(from_student=True, recorder='conv'), + arg2=dict(from_student=False, recorder='conv'))) + with self.assertWarnsRegex(UserWarning, 'Warning: If toy is a'): + _ = ConfigurableDistiller(**distiller_kwargs_) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_['loss_forward_mappings'] = None + _ = ConfigurableDistiller(**distiller_kwargs_) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_['loss_forward_mappings'] = list('AAA') + + with self.assertRaisesRegex(TypeError, + 'loss_forward_mappings should be '): + _ = ConfigurableDistiller(**distiller_kwargs_) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_['loss_forward_mappings']['loss_toy'] = list() + with self.assertRaisesRegex( + TypeError, 'Each item of loss_forward_mappings should be '): + _ = ConfigurableDistiller(**distiller_kwargs_) + + distiller_kwargs_ = copy.deepcopy(distiller_kwargs) + distiller_kwargs_.loss_forward_mappings.loss_toy.arg1.from_student = '' + with self.assertRaisesRegex(TypeError, + 'from_student should be a bool'): + _ = ConfigurableDistiller(**distiller_kwargs_) + + def test_connector_list(self): + recorders_cfg = ConfigDict( + conv=dict(type='ModuleOutputs', source='conv')) + norm_cfg = dict(type='BN', affine=False, track_running_stats=False) + + distiller_kwargs = ConfigDict( + student_recorders=recorders_cfg, + teacher_recorders=recorders_cfg, + distill_losses=dict(loss_toy=dict(type='ToyDistillLoss')), + loss_forward_mappings=dict( + loss_toy=dict( + arg1=dict( + from_student=True, + recorder='conv', + connector='loss_1_sfeat'), + arg2=dict(from_student=False, recorder='conv'), + )), + connectors=dict(loss_1_sfeat=[ + dict( + type='ConvModuleConnector', + in_channel=3, + out_channel=4, + act_cfg=None), + dict(type='NormConnector', norm_cfg=norm_cfg, in_channels=4) + ])) + + distiller = ConfigurableDistiller(**distiller_kwargs) + connectors = distiller.connectors + self.assertIsInstance(connectors['loss_1_sfeat'], nn.Sequential) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_lsq_fake_quants.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_lsq_fake_quants.py new file mode 100755 index 000000000..dcbda5d40 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_lsq_fake_quants.py @@ -0,0 +1,208 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch +from torch.nn.parameter import Parameter + +from mmrazor import digit_version +from mmrazor.models import LearnableFakeQuantize + +try: + from torch.ao.quantization import (MovingAverageMinMaxObserver, + MovingAveragePerChannelMinMaxObserver) +except ImportError: + from mmrazor.utils import get_placeholder + MovingAverageMinMaxObserver = get_placeholder('torch>=1.13') + MovingAveragePerChannelMinMaxObserver = get_placeholder('torch>=1.13') + + +class TestLearnableFakeQuantize(TestCase): + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + self.zero_point_trainable_fakequant = LearnableFakeQuantize.with_args( + observer=MovingAverageMinMaxObserver, + quant_min=0, + quant_max=255, + dtype=torch.quint8, + qscheme=torch.per_tensor_affine, + reduce_range=True, + zero_point_trainable=True) + + self.zero_point_untrainable_fakequant = \ + LearnableFakeQuantize.with_args( + observer=MovingAverageMinMaxObserver, + quant_min=0, + quant_max=255, + dtype=torch.quint8, + qscheme=torch.per_tensor_affine, + reduce_range=True, + zero_point_trainable=False) + + self.zero_point_untrainable_per_channel_fakequant = \ + LearnableFakeQuantize.with_args( + observer=MovingAveragePerChannelMinMaxObserver, + quant_min=0, + quant_max=255, + dtype=torch.quint8, + qscheme=torch.per_channel_affine, + reduce_range=True, + zero_point_trainable=False) + + def test_repr(self): + fq_module = self.zero_point_untrainable_fakequant() + repr_str = f'static_enabled={torch.tensor([1], dtype=torch.uint8)}, ' + repr_str += f'fake_quant_enabled=' \ + f'{torch.tensor([1], dtype=torch.uint8)}, ' + repr_str += 'quant_min=0, ' + repr_str += 'quant_max=127, ' + repr_str += f'dtype={torch.quint8}, ' + repr_str += f'qscheme={torch.per_tensor_affine}, ' + repr_str += f'scale={Parameter(torch.tensor([1.0]))}, ' + repr_str += f'zero_point={torch.tensor([0.])}, ' + repr_str += 'zero_point_trainable=False' + self.assertEqual(fq_module.extra_repr(), repr_str) + + fq_module = self.zero_point_trainable_fakequant() + repr_str = f'static_enabled={torch.tensor([1], dtype=torch.uint8)}, ' + repr_str += f'fake_quant_enabled=' \ + f'{torch.tensor([1], dtype=torch.uint8)}, ' + repr_str += 'quant_min=0, ' + repr_str += 'quant_max=127, ' + repr_str += f'dtype={torch.quint8}, ' + repr_str += f'qscheme={torch.per_tensor_affine}, ' + repr_str += f'scale={Parameter(torch.tensor([1.0]))}, ' + repr_str += f'zero_point={Parameter(torch.tensor([0.]))}, ' + repr_str += 'zero_point_trainable=True' + self.assertEqual(fq_module.extra_repr(), repr_str) + + def test_calculate_qparams(self): + fq_module = self.zero_point_untrainable_fakequant() + scale, zero_point = fq_module.calculate_qparams() + self.assertEqual(scale, 1.) + self.assertEqual(zero_point, 0.) + + fq_module = self.zero_point_trainable_fakequant() + scale, zero_point = fq_module.calculate_qparams() + self.assertEqual(scale, 1.) + self.assertEqual(zero_point, 0.) + + def test_forward(self): + fq_module = self.zero_point_untrainable_fakequant() + torch.manual_seed(42) + X = torch.rand(20, 10, dtype=torch.float32) + # Output of fake quant is not identical to input + Y = fq_module(X) + self.assertFalse(torch.equal(Y, X)) + # self.assertNotEqual(Y, X) + fq_module.toggle_fake_quant(False) + X = torch.rand(20, 10, dtype=torch.float32) + Y = fq_module(X) + # Fake quant is disabled,output is identical to input + self.assertTrue(torch.equal(Y, X)) + + # Explicit copy at this point in time, because FakeQuant keeps internal + # state in mutable buffers. + scale = fq_module.scale.clone().detach() + zero_point = fq_module.zero_point.clone().detach() + + fq_module.toggle_observer_update(False) + fq_module.toggle_fake_quant(True) + X = 10.0 * torch.rand(20, 10, dtype=torch.float32) - 5.0 + Y = fq_module(X) + self.assertFalse(torch.equal(Y, X)) + # Observer is disabled, scale and zero-point do not change + self.assertEqual(fq_module.scale, scale) + self.assertEqual(fq_module.zero_point, zero_point) + + fq_module.toggle_observer_update(True) + Y = fq_module(X) + self.assertFalse(torch.equal(Y, X)) + # Observer is enabled, scale and zero-point are different + self.assertNotEqual(fq_module.scale, scale) + self.assertNotEqual(fq_module.zero_point, zero_point) + + fq_module = self.zero_point_trainable_fakequant() + torch.manual_seed(42) + X = torch.rand(20, 10, dtype=torch.float32) + # Output of fake quant is not identical to input + Y = fq_module(X) + self.assertFalse(torch.equal(Y, X)) + # self.assertNotEqual(Y, X) + fq_module.toggle_fake_quant(False) + X = torch.rand(20, 10, dtype=torch.float32) + Y = fq_module(X) + # Fake quant is disabled,output is identical to input + self.assertTrue(torch.equal(Y, X)) + + # Explicit copy at this point in time, because FakeQuant keeps internal + # state in mutable buffers. + scale = fq_module.scale.clone().detach() + zero_point = fq_module.zero_point.clone().detach() + + fq_module.toggle_observer_update(False) + fq_module.toggle_fake_quant(True) + X = 10.0 * torch.rand(20, 10, dtype=torch.float32) - 5.0 + Y = fq_module(X) + self.assertFalse(torch.equal(Y, X)) + # Observer is disabled, scale and zero-point do not change + self.assertEqual(fq_module.scale, scale) + self.assertEqual(fq_module.zero_point, zero_point) + + fq_module.toggle_observer_update(True) + Y = fq_module(X) + self.assertFalse(torch.equal(Y, X)) + # Observer is enabled, scale and zero-point are different + self.assertNotEqual(fq_module.scale, scale) + self.assertNotEqual(fq_module.zero_point, zero_point) + + def test_state(self): + fq_module = self.zero_point_untrainable_fakequant() + + fq_module.enable_param_learning() + self.assertEqual(fq_module.learning_enabled[0], 1) + self.assertEqual(fq_module.scale.requires_grad, 1) + self.assertEqual(fq_module.zero_point.requires_grad, 0) + self.assertEqual(fq_module.fake_quant_enabled[0], 1) + self.assertEqual(fq_module.static_enabled[0], 0) + + fq_module.enable_static_estimate() + self.assertEqual(fq_module.learning_enabled[0], 0) + self.assertEqual(fq_module.scale.requires_grad, 0) + self.assertEqual(fq_module.zero_point.requires_grad, 0) + self.assertEqual(fq_module.fake_quant_enabled[0], 1) + self.assertEqual(fq_module.static_enabled[0], 1) + + fq_module.enable_val() + self.assertEqual(fq_module.learning_enabled[0], 0) + self.assertEqual(fq_module.scale.requires_grad, 0) + self.assertEqual(fq_module.zero_point.requires_grad, 0) + self.assertEqual(fq_module.fake_quant_enabled[0], 1) + self.assertEqual(fq_module.static_enabled[0], 0) + + fq_module.enable_static_observation() + self.assertEqual(fq_module.learning_enabled[0], 0) + self.assertEqual(fq_module.scale.requires_grad, 0) + self.assertEqual(fq_module.zero_point.requires_grad, 0) + self.assertEqual(fq_module.fake_quant_enabled[0], 0) + self.assertEqual(fq_module.static_enabled[0], 1) + + fq_module = self.zero_point_trainable_fakequant() + + fq_module.enable_param_learning() + self.assertEqual(fq_module.learning_enabled[0], 1) + self.assertEqual(fq_module.scale.requires_grad, 1) + self.assertEqual(fq_module.zero_point.requires_grad, 1) + self.assertEqual(fq_module.fake_quant_enabled[0], 1) + self.assertEqual(fq_module.static_enabled[0], 0) + + def test_load_state_dict(self): + fq_module = self.zero_point_untrainable_per_channel_fakequant() + state_dict = fq_module.state_dict() + X = torch.rand(32, 16, 3, 3, dtype=torch.float32) + # After forwarding, the shape of `scale` and `zero_point` in + # `fq_module` will be in shape (32, ), while the shape of those in + # `state_dict` are in shape (1, ). + _ = fq_module(X) + fq_module.load_state_dict(state_dict) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_torch_fake_quants.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_torch_fake_quants.py new file mode 100755 index 000000000..485113e90 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_fake_quants/test_torch_fake_quants.py @@ -0,0 +1,18 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmrazor import digit_version +from mmrazor.models.fake_quants import register_torch_fake_quants +from mmrazor.registry import MODELS + + +@pytest.mark.skipif( + digit_version(torch.__version__) < digit_version('1.13.0'), + reason='version of torch < 1.13.0') +def test_register_torch_fake_quants(): + + TORCH_fake_quants = register_torch_fake_quants() + assert isinstance(TORCH_fake_quants, list) + for fake_quant in TORCH_fake_quants: + assert MODELS.get(fake_quant) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_distillation_losses.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_distillation_losses.py new file mode 100755 index 000000000..77233b81f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_distillation_losses.py @@ -0,0 +1,213 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch +from mmengine.structures import BaseDataElement + +from mmrazor import digit_version +from mmrazor.models import (ABLoss, ActivationLoss, ATLoss, CRDLoss, DKDLoss, + FBKDLoss, FTLoss, InformationEntropyLoss, + KDSoftCELoss, MGDLoss, OFDLoss, OnehotLikeLoss, + PKDLoss) + + +class TestLosses(TestCase): + + @classmethod + def setUpClass(cls): + cls.feats_1d = torch.randn(5, 6) + cls.feats_2d = torch.randn(5, 2, 3) + cls.feats_3d = torch.randn(5, 2, 3, 3) + + num_classes = 6 + cls.labels = torch.randint(0, num_classes, [5]) + + def test_ofd_loss(self): + ofd_loss = OFDLoss() + self.normal_test_1d(ofd_loss) + self.normal_test_3d(ofd_loss) + + # test the calculation + s_feat_0 = torch.Tensor([[1, 1], [2, 2], [3, 3]]) + t_feat_0 = torch.Tensor([[0, 0], [1, 1], [2, 2]]) + ofd_loss_num_0 = ofd_loss.forward(s_feat_0, t_feat_0) + assert ofd_loss_num_0 != torch.tensor(0.0) + + s_feat_1 = torch.Tensor([[1, 1], [2, 2], [3, 3]]) + t_feat_1 = torch.Tensor([[2, 2], [3, 3], [4, 4]]) + ofd_loss_num_1 = ofd_loss.forward(s_feat_1, t_feat_1) + assert ofd_loss_num_1 != torch.tensor(0.0) + + s_feat_2 = torch.Tensor([[-3, -3], [-2, -2], [-1, -1]]) + t_feat_2 = torch.Tensor([[-2, -2], [-1, -1], [0, 0]]) + ofd_loss_num_2 = ofd_loss.forward(s_feat_2, t_feat_2) + assert ofd_loss_num_2 == torch.tensor(0.0) + + def normal_test_1d(self, loss_instance, labels=False): + args = tuple([self.feats_1d, self.feats_1d]) + if labels: + args += (self.labels, ) + loss_1d = loss_instance.forward(*args) + self.assertTrue(loss_1d.numel() == 1) + + def normal_test_2d(self, loss_instance, labels=False): + args = tuple([self.feats_2d, self.feats_2d]) + if labels: + args += (self.labels, ) + loss_2d = loss_instance.forward(*args) + self.assertTrue(loss_2d.numel() == 1) + + def normal_test_3d(self, loss_instance, labels=False): + args = tuple([self.feats_3d, self.feats_3d]) + if labels: + args += (self.labels, ) + loss_3d = loss_instance.forward(*args) + self.assertTrue(loss_3d.numel() == 1) + + def test_ab_loss(self): + ab_loss_cfg = dict(loss_weight=1.0, margin=1.0) + ab_loss = ABLoss(**ab_loss_cfg) + self.normal_test_1d(ab_loss) + self.normal_test_2d(ab_loss) + self.normal_test_3d(ab_loss) + + def _mock_crd_data_sample(self, sample_idx_list): + data_samples = [] + for _idx in sample_idx_list: + data_sample = BaseDataElement() + data_sample.set_data(dict(sample_idx=_idx)) + data_samples.append(data_sample) + return data_samples + + def test_crd_loss(self): + crd_loss = CRDLoss(**dict(neg_num=5, sample_n=10, dim_out=6)) + sample_idx_list = torch.tensor(list(range(5))) + data_samples = self._mock_crd_data_sample(sample_idx_list) + loss = crd_loss.forward(self.feats_1d, self.feats_1d, data_samples) + self.assertTrue(loss.numel() == 1) + + # test the calculation + s_feat_0 = torch.randn((5, 6)) + t_feat_0 = torch.randn((5, 6)) + crd_loss_num_0 = crd_loss.forward(s_feat_0, t_feat_0, data_samples) + assert crd_loss_num_0 != torch.tensor(0.0) + + s_feat_1 = torch.randn((5, 6)) + t_feat_1 = torch.rand((5, 6)) + sample_idx_list_1 = torch.tensor(list(range(5))) + data_samples_1 = self._mock_crd_data_sample(sample_idx_list_1) + crd_loss_num_1 = crd_loss.forward(s_feat_1, t_feat_1, data_samples_1) + assert crd_loss_num_1 != torch.tensor(0.0) + + def test_dkd_loss(self): + dkd_loss_cfg = dict(loss_weight=1.0) + dkd_loss = DKDLoss(**dkd_loss_cfg) + # dkd requires label logits + self.normal_test_1d(dkd_loss, labels=True) + + def test_ft_loss(self): + ft_loss_cfg = dict(loss_weight=1.0) + ft_loss = FTLoss(**ft_loss_cfg) + + assert ft_loss.loss_weight == 1.0 + + self.normal_test_1d(ft_loss) + self.normal_test_2d(ft_loss) + self.normal_test_3d(ft_loss) + + def test_dafl_loss(self): + dafl_loss_cfg = dict(loss_weight=1.0) + ac_loss = ActivationLoss(**dafl_loss_cfg, norm_type='abs') + oh_loss = OnehotLikeLoss(**dafl_loss_cfg) + ie_loss = InformationEntropyLoss(**dafl_loss_cfg, gather=False) + + # normal test with only one input + loss_ac = ac_loss.forward(self.feats_1d) + self.assertTrue(loss_ac.numel() == 1) + loss_oh = oh_loss.forward(self.feats_1d) + self.assertTrue(loss_oh.numel() == 1) + loss_ie = ie_loss.forward(self.feats_1d) + self.assertTrue(loss_ie.numel() == 1) + + with self.assertRaisesRegex(AssertionError, + '"norm_type" must be "norm" or "abs"'): + _ = ActivationLoss(**dafl_loss_cfg, norm_type='random') + + # test gather_tensors + ie_loss = InformationEntropyLoss(**dafl_loss_cfg, gather=True) + ie_loss.world_size = 2 + + if digit_version(torch.__version__) >= digit_version('1.8.0'): + with self.assertRaisesRegex( + RuntimeError, + 'Default process group has not been initialized'): + loss_ie = ie_loss.forward(self.feats_1d) + else: + with self.assertRaisesRegex( + AssertionError, + 'Default process group is not initialized'): + loss_ie = ie_loss.forward(self.feats_1d) + + def test_kdSoftce_loss(self): + kdSoftce_loss_cfg = dict(loss_weight=1.0) + kdSoftce_loss = KDSoftCELoss(**kdSoftce_loss_cfg) + # kd soft ce loss requires label logits + self.normal_test_1d(kdSoftce_loss, labels=True) + + def test_at_loss(self): + at_loss_cfg = dict(loss_weight=1.0) + at_loss = ATLoss(**at_loss_cfg) + + assert at_loss.loss_weight == 1.0 + + self.normal_test_1d(at_loss) + self.normal_test_2d(at_loss) + self.normal_test_3d(at_loss) + + def test_fbkdloss(self): + fbkdloss_cfg = dict(loss_weight=1.0) + fbkdloss = FBKDLoss(**fbkdloss_cfg) + + spatial_mask = torch.randn(1, 1, 3, 3) + channel_mask = torch.randn(1, 4, 1, 1) + channel_pool_adapt = torch.randn(1, 4) + relation_adpt = torch.randn(1, 4, 3, 3) + + s_input = (spatial_mask, channel_mask, channel_pool_adapt, + spatial_mask, channel_mask, relation_adpt) + t_input = (spatial_mask, channel_mask, spatial_mask, channel_mask, + relation_adpt) + + fbkd_loss = fbkdloss(s_input, t_input) + self.assertTrue(fbkd_loss.numel() == 1) + + def test_pkdloss(self): + pkd_loss = PKDLoss(loss_weight=1.0) + feats_S, feats_T = torch.rand(2, 256, 4, 4), torch.rand(2, 256, 4, 4) + loss = pkd_loss(feats_S, feats_T) + self.assertTrue(loss.numel() == 1) + self.assertTrue(0. <= loss <= 1.) + + num_stages = 4 + feats_S = (torch.rand(2, 256, 4, 4) for _ in range(num_stages)) + feats_T = (torch.rand(2, 256, 4, 4) for _ in range(num_stages)) + loss = pkd_loss(feats_S, feats_T) + self.assertTrue(loss.numel() == 1) + self.assertTrue(0. <= loss <= num_stages * 1.) + + feats_S, feats_T = torch.rand(2, 256, 2, 2), torch.rand(2, 256, 4, 4) + loss = pkd_loss(feats_S, feats_T) + self.assertTrue(loss.numel() == 1) + self.assertTrue(0. <= loss <= 1.) + + pkd_loss = PKDLoss(loss_weight=1.0, resize_stu=False) + feats_S, feats_T = torch.rand(2, 256, 2, 2), torch.rand(2, 256, 4, 4) + loss = pkd_loss(feats_S, feats_T) + self.assertTrue(loss.numel() == 1) + self.assertTrue(0. <= loss <= 1.) + + def test_mgd_loss(self): + mgd_loss = MGDLoss(alpha_mgd=0.00002) + feats_S, feats_T = torch.rand(2, 256, 4, 4), torch.rand(2, 256, 4, 4) + loss = mgd_loss(feats_S, feats_T) + self.assertTrue(loss.numel() == 1) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_general_losses.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_general_losses.py new file mode 100755 index 000000000..946de27aa --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_losses/test_general_losses.py @@ -0,0 +1,52 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch + +from mmrazor.models import L1Loss, L2Loss + + +class TestLosses(TestCase): + + @classmethod + def setUpClass(cls): + cls.feats_1d = torch.randn(5, 6) + cls.feats_2d = torch.randn(5, 2, 3) + cls.feats_3d = torch.randn(5, 2, 3, 3) + + def normal_test_1d(self, loss_instance): + loss_1d = loss_instance.forward(self.feats_1d, self.feats_1d) + self.assertTrue(loss_1d.numel() == 1) + + def normal_test_2d(self, loss_instance): + loss_2d = loss_instance.forward(self.feats_2d, self.feats_2d) + self.assertTrue(loss_2d.numel() == 1) + + def normal_test_3d(self, loss_instance): + loss_3d = loss_instance.forward(self.feats_3d, self.feats_3d) + self.assertTrue(loss_3d.numel() == 1) + + def test_l1_loss(self): + l1_loss_cfg = dict(loss_weight=10) + l1_loss = L1Loss(**l1_loss_cfg) + self.normal_test_1d(l1_loss) + self.normal_test_2d(l1_loss) + self.normal_test_3d(l1_loss) + + l1_loss_cfg = dict(loss_weight=10, reduction='avg') + with pytest.raises(AssertionError): + l1_loss = L1Loss(**l1_loss_cfg) + + def test_l2_loss(self): + l2_loss_cfg = dict(loss_weight=10, normalize=True) + l2_loss = L2Loss(**l2_loss_cfg) + self.normal_test_1d(l2_loss) + self.normal_test_2d(l2_loss) + self.normal_test_3d(l2_loss) + + l2_loss_cfg['div_element'] = True + l2_loss = L2Loss(**l2_loss_cfg) + self.normal_test_1d(l2_loss) + self.normal_test_2d(l2_loss) + self.normal_test_3d(l2_loss) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_derived_mutable.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_derived_mutable.py new file mode 100755 index 000000000..8ec7c5cd5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_derived_mutable.py @@ -0,0 +1,318 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch + +from mmrazor.models.mutables import (DerivedMutable, OneShotMutableValue, + SquentialMutableChannel) +from mmrazor.models.mutables.base_mutable import BaseMutable + + +class TestDerivedMutable(TestCase): + + def test_is_fixed(self) -> None: + mc = SquentialMutableChannel(num_channels=10) + mc.current_choice = 2 + + mv = OneShotMutableValue(value_list=[2, 3, 4]) + mv.current_choice = 3 + + derived_mutable = mc * mv + assert not derived_mutable.is_fixed + + with pytest.raises(RuntimeError): + derived_mutable.is_fixed = True + + mc.fix_chosen(mc.dump_chosen().chosen) + assert not derived_mutable.is_fixed + mv.fix_chosen(mv.dump_chosen().chosen) + assert derived_mutable.is_fixed + + def test_fix_dump_chosen(self) -> None: + mv = OneShotMutableValue(value_list=[2, 3, 4]) + mv.current_choice = 3 + + derived_mutable = mv * 2 + assert derived_mutable.dump_chosen().chosen == 6 + + mv.current_choice = 4 + assert derived_mutable.dump_chosen().chosen == 8 + + # nothing will happen + derived_mutable.fix_chosen(derived_mutable.dump_chosen().chosen) + + def test_derived_same_mutable(self) -> None: + mc = SquentialMutableChannel(num_channels=3) + mc_derived = mc.derive_same_mutable() + assert mc_derived.source_mutables == {mc} + + mc.current_choice = 2 + assert mc_derived.current_choice == 2 + assert torch.equal(mc_derived.current_mask, + torch.tensor([1, 1, 0], dtype=torch.bool)) + + def test_mutable_concat_derived(self) -> None: + mc1 = SquentialMutableChannel(num_channels=3) + mc2 = SquentialMutableChannel(num_channels=4) + ms = [mc1, mc2] + + mc_derived = DerivedMutable.derive_concat_mutable(ms) + assert mc_derived.source_mutables == set(ms) + + mc1.current_choice = 1 + mc2.current_choice = 4 + assert mc_derived.current_choice == 5 + assert torch.equal( + mc_derived.current_mask, + torch.tensor([1, 0, 0, 1, 1, 1, 1], dtype=torch.bool)) + + mc1.current_choice = 1 + mc2.current_choice = 1 + assert mc_derived.current_choice == 2 + assert torch.equal( + mc_derived.current_mask, + torch.tensor([1, 0, 0, 1, 0, 0, 0], dtype=torch.bool)) + + mv = OneShotMutableValue(value_list=[1, 2, 3]) + ms = [mc1, mv] + with pytest.raises(RuntimeError): + _ = DerivedMutable.derive_concat_mutable(ms) + + def test_mutable_channel_derived(self) -> None: + mc = SquentialMutableChannel(num_channels=3) + mc_derived = mc * 3 + assert mc_derived.source_mutables == {mc} + + mc.current_choice = 1 + assert mc_derived.current_choice == 3 + assert torch.equal( + mc_derived.current_mask, + torch.tensor([1, 1, 1, 0, 0, 0, 0, 0, 0], dtype=torch.bool)) + + mc.current_choice = 2 + assert mc_derived.current_choice == 6 + assert torch.equal( + mc_derived.current_mask, + torch.tensor([1, 1, 1, 1, 1, 1, 0, 0, 0], dtype=torch.bool)) + + with pytest.raises(RuntimeError): + mc_derived.current_mask = torch.ones( + mc_derived.current_mask.size()) + + def test_mutable_divide(self) -> None: + mc = SquentialMutableChannel(num_channels=128) + mc_derived = mc // 8 + assert mc_derived.source_mutables == {mc} + + mc.current_choice = 128 + assert mc_derived.current_choice == 16 + assert torch.equal(mc_derived.current_mask, + torch.ones(16, dtype=torch.bool)) + mc.current_choice = 120 + assert mc_derived.current_choice == 16 + assert torch.equal(mc_derived.current_mask, + torch.ones(16, dtype=torch.bool)) + + mv = OneShotMutableValue(value_list=[112, 120, 128]) + mv_derived = mv // 8 + assert mv_derived.source_mutables == {mv} + + mv.current_choice == 128 + assert mv_derived.current_choice == 16 + mv.current_choice == 120 + assert mv_derived.current_choice == 16 + + mc_derived = mc // 8.0 + assert mc_derived.source_mutables == {mc} + + mc.current_choice = 128. + assert mc_derived.current_choice == 16 + assert torch.equal(mc_derived.current_mask, + torch.ones(16, dtype=torch.bool)) + mc.current_choice = 120. + assert mc_derived.current_choice == 16 + assert torch.equal(mc_derived.current_mask, + torch.ones(16, dtype=torch.bool)) + + mv = OneShotMutableValue(value_list=[112, 120, 128]) + mv_derived = mv // 8.0 + assert mv_derived.source_mutables == {mv} + + mv.current_choice == 128. + assert mv_derived.current_choice == 16 + mv.current_choice == 120. + assert mv_derived.current_choice == 16 + + def test_source_mutables(self) -> None: + + def useless_fn(x): + return x # noqa: E731 + + with pytest.raises(RuntimeError): + _ = DerivedMutable(choice_fn=useless_fn) + + mc1 = SquentialMutableChannel(num_channels=3) + mc2 = SquentialMutableChannel(num_channels=4) + ms = [mc1, mc2] + + mc_derived1 = DerivedMutable.derive_concat_mutable(ms) + + from mmrazor.models.mutables.derived_mutable import (_concat_choice_fn, + _concat_mask_fn) + mc_derived2 = DerivedMutable( + choice_fn=_concat_choice_fn(ms), + mask_fn=_concat_mask_fn(ms), + source_mutables=ms) + assert mc_derived1.source_mutables == mc_derived2.source_mutables + + dd_mutable = mc_derived1.derive_same_mutable() + assert dd_mutable.source_mutables == mc_derived1.source_mutables + + with pytest.raises(ValueError): + _ = DerivedMutable( + choice_fn=lambda x: x, source_mutables=[mc_derived1]) + + def dict_closure_fn(x, y): + + def fn(): + nonlocal x, y + + return fn + + ddd_mutable = DerivedMutable( + choice_fn=dict_closure_fn({ + mc1: [2, 3], + mc2: 2 + }, None), + mask_fn=dict_closure_fn({2: [mc1, mc2]}, {3: dd_mutable})) + assert ddd_mutable.source_mutables == mc_derived1.source_mutables + + mc3 = SquentialMutableChannel(num_channels=4) + dddd_mutable = DerivedMutable( + choice_fn=dict_closure_fn({ + mc1: [2, 3], + mc2: 2 + }, []), + mask_fn=dict_closure_fn({2: [mc1, mc2, mc3]}, {3: dd_mutable})) + assert dddd_mutable.source_mutables == {mc1, mc2, mc3} + + def test_nested_mutables(self) -> None: + source_a = SquentialMutableChannel(num_channels=2) + source_b = SquentialMutableChannel(num_channels=3) + + # derive from + derived_c = source_a * 1 + concat_mutables = [source_b, derived_c] + derived_d = DerivedMutable.derive_concat_mutable(concat_mutables) + concat_mutables = [derived_c, derived_d] + derived_e = DerivedMutable.derive_concat_mutable(concat_mutables) + + assert derived_c.source_mutables == {source_a} + assert derived_d.source_mutables == {source_a, source_b} + assert derived_e.source_mutables == {source_a, source_b} + + source_a.current_choice = 1 + source_b.current_choice = 3 + + assert derived_c.current_choice == 1 + assert torch.equal(derived_c.current_mask, + torch.tensor([1, 0], dtype=torch.bool)) + + assert derived_d.current_choice == 4 + assert torch.equal(derived_d.current_mask, + torch.tensor([1, 1, 1, 1, 0], dtype=torch.bool)) + + assert derived_e.current_choice == 5 + assert torch.equal( + derived_e.current_mask, + torch.tensor([1, 0, 1, 1, 1, 1, 0], dtype=torch.bool)) + + def test_mutable_channel_value_calculation(self) -> None: + mc = SquentialMutableChannel(num_channels=10) + mv = OneShotMutableValue(value_list=[2.0, 2.5, 3.0, 3.5]) + derived_mutable = mc * mv + assert derived_mutable.source_mutables == {mv, mc} + + mc.current_choice = 6 + mv.current_choice = 3.5 + assert derived_mutable.current_choice == 21 + + mc.current_choice = 9 + mv.current_choice = 3.5 + assert derived_mutable.current_choice == 31 + + mc.current_choice = 7 + mv.current_choice = 2.5 + assert derived_mutable.current_choice == 17 + + assert isinstance(derived_mutable, BaseMutable) + assert isinstance(derived_mutable, DerivedMutable) + assert not derived_mutable.is_fixed + + mc.current_choice = mc.num_channels + mv.current_choice = mv.min_choice + assert derived_mutable.current_choice == \ + mv.current_choice * mc.num_channels + mv.current_choice = mv.max_choice + assert derived_mutable.current_choice == \ + mv.current_choice * mc.current_choice + + with pytest.raises(RuntimeError): + derived_mutable.is_fixed = True + mc.fix_chosen(mc.dump_chosen().chosen) + assert not derived_mutable.is_fixed + mv.fix_chosen(mv.dump_chosen().chosen) + assert derived_mutable.is_fixed + + +@pytest.mark.parametrize('expand_ratio', [1, 2, 3]) +def test_derived_expand_mutable(expand_ratio: int) -> None: + mv = OneShotMutableValue(value_list=[3, 5, 7]) + + mv_derived = mv * expand_ratio + assert mv_derived.source_mutables == {mv} + + assert isinstance(mv_derived, BaseMutable) + assert isinstance(mv_derived, DerivedMutable) + assert not mv_derived.is_fixed + assert mv_derived.num_choices == 1 + + mv.current_choice = mv.max_choice + assert mv_derived.current_choice == mv.current_choice * expand_ratio + mv.current_choice = mv.min_choice + assert mv_derived.current_choice == mv.current_choice * expand_ratio + + with pytest.raises(RuntimeError): + mv_derived.current_choice = 123 + with pytest.raises(RuntimeError): + _ = mv_derived.current_mask + + mv.current_choice = 5 + assert mv_derived.current_choice == 5 * expand_ratio + + +@pytest.mark.parametrize('expand_ratio', [1.5, 2.0, 2.5]) +def test_derived_expand_mutable_float(expand_ratio: float) -> None: + mv = OneShotMutableValue(value_list=[3, 5, 7]) + + mv_derived = mv * expand_ratio + assert mv_derived.source_mutables == {mv} + + assert isinstance(mv_derived, BaseMutable) + assert isinstance(mv_derived, DerivedMutable) + assert not mv_derived.is_fixed + assert mv_derived.num_choices == 1 + + mv.current_choice = mv.max_choice + assert mv_derived.current_choice == int(mv.current_choice * expand_ratio) + mv.current_choice = mv.min_choice + assert mv_derived.current_choice == int(mv.current_choice * expand_ratio) + + with pytest.raises(RuntimeError): + mv_derived.current_choice = 123 + with pytest.raises(RuntimeError): + _ = mv_derived.current_mask + + mv.current_choice = 5 + assert mv_derived.current_choice == int(5 * expand_ratio) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffchoiceroute.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffchoiceroute.py new file mode 100755 index 000000000..a40c9f525 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffchoiceroute.py @@ -0,0 +1,87 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch +import torch.nn as nn + +from mmrazor.models import * # noqa:F403,F401 +from mmrazor.registry import MODELS + +MODELS.register_module(name='torchConv2d', module=nn.Conv2d, force=True) + + +class TestDiffChoiceRoute(TestCase): + + def test_forward_arch_param(self): + edges_dict = nn.ModuleDict() + edges_dict.add_module('first_edge', nn.Conv2d(32, 32, 3, 1, 1)) + edges_dict.add_module('second_edge', nn.Conv2d(32, 32, 5, 1, 2)) + edges_dict.add_module('third_edge', nn.MaxPool2d(3, 1, 1)) + edges_dict.add_module('fourth_edge', nn.MaxPool2d(5, 1, 2)) + edges_dict.add_module('fifth_edge', nn.MaxPool2d(7, 1, 3)) + + diff_choice_route_cfg = dict( + type='DiffChoiceRoute', + edges=edges_dict, + with_arch_param=True, + ) + + # test with_arch_param = True + diffchoiceroute = MODELS.build(diff_choice_route_cfg) + arch_param = nn.Parameter(torch.randn(len(edges_dict))) + + x = [torch.randn(4, 32, 64, 64) for _ in range(5)] + output = diffchoiceroute.forward_arch_param(x=x, arch_param=arch_param) + assert output is not None + + # test with_arch_param = False + new_diff_choice_route_cfg = diff_choice_route_cfg.copy() + new_diff_choice_route_cfg['with_arch_param'] = False + + new_diff_choice_route = MODELS.build(new_diff_choice_route_cfg) + arch_param = nn.Parameter(torch.randn(len(edges_dict))) + output = new_diff_choice_route.forward_arch_param( + x=x, arch_param=arch_param) + assert output is not None + + new_diff_choice_route.fix_chosen(chosen=['first_edge']) + + # test sample choice + arch_param = nn.Parameter(torch.randn(len(edges_dict))) + new_diff_choice_route.sample_choice(arch_param) + + # test dump_chosen + with pytest.raises(AssertionError): + new_diff_choice_route.dump_chosen() + + def test_forward_fixed(self): + edges_dict = nn.ModuleDict({ + 'first_edge': nn.Conv2d(32, 32, 3, 1, 1), + 'second_edge': nn.Conv2d(32, 32, 5, 1, 2), + 'third_edge': nn.Conv2d(32, 32, 7, 1, 3), + 'fourth_edge': nn.MaxPool2d(3, 1, 1), + 'fifth_edge': nn.AvgPool2d(3, 1, 1), + }) + + diff_choice_route_cfg = dict( + type='DiffChoiceRoute', + edges=edges_dict, + with_arch_param=True, + ) + + # test with_arch_param = True + diffchoiceroute = MODELS.build(diff_choice_route_cfg) + + diffchoiceroute.fix_chosen( + chosen=['first_edge', 'second_edge', 'fifth_edge']) + assert diffchoiceroute.is_fixed is True + + x = [torch.randn(4, 32, 64, 64) for _ in range(5)] + output = diffchoiceroute.forward_fixed(x) + assert output is not None + assert diffchoiceroute.num_choices == 3 + + # after is_fixed = True, call fix_chosen + with pytest.raises(AttributeError): + diffchoiceroute.fix_chosen(chosen=['first_edge']) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffop.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffop.py new file mode 100755 index 000000000..eab9fff2b --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_diffop.py @@ -0,0 +1,200 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch +import torch.nn as nn + +from mmrazor.models import * # noqa:F403,F401 +from mmrazor.registry import MODELS + +MODELS.register_module(name='torchConv2d', module=nn.Conv2d, force=True) +MODELS.register_module(name='torchMaxPool2d', module=nn.MaxPool2d, force=True) +MODELS.register_module(name='torchAvgPool2d', module=nn.AvgPool2d, force=True) + + +class TestDiffOP(TestCase): + + def test_forward_arch_param(self): + op_cfg = dict( + type='DiffMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + padding=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + padding=2, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + padding=3, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + input = torch.randn(4, 32, 64, 64) + + arch_param = nn.Parameter(torch.randn(len(op_cfg['candidates']))) + output = op.forward_arch_param(input, arch_param=arch_param) + assert output is not None + + # test when some element of arch_param is 0 + arch_param = nn.Parameter(torch.ones(op.num_choices)) + output = op.forward_arch_param(input, arch_param=arch_param) + assert output is not None + + def test_forward_fixed(self): + op_cfg = dict( + type='DiffMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + input = torch.randn(4, 32, 64, 64) + + op.fix_chosen('torch_conv2d_7x7') + output = op.forward_fixed(input) + + assert output is not None + assert op.is_fixed is True + + def test_forward(self): + op_cfg = dict( + type='DiffMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + padding=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + padding=2, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + padding=3, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + input = torch.randn(4, 32, 64, 64) + + # test set_forward_args + arch_param = nn.Parameter(torch.randn(len(op_cfg['candidates']))) + op.set_forward_args(arch_param=arch_param) + output = op.forward(input) + assert output is not None + + # test dump_chosen + with pytest.raises(AssertionError): + op.dump_chosen() + + # test forward when is_fixed is True + op.fix_chosen('torch_conv2d_7x7') + output = op.forward(input) + + def test_property(self): + op_cfg = dict( + type='DiffMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + padding=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + padding=2, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + padding=3, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + + assert len(op.choices) == 3 + + # test is_fixed propty + assert op.is_fixed is False + + # test is_fixed setting + op.fix_chosen('torch_conv2d_5x5') + + with pytest.raises(AttributeError): + op.is_fixed = True + + # test fix choice when is_fixed is True + with pytest.raises(AttributeError): + op.fix_chosen('torch_conv2d_3x3') + + def test_module_kwargs(self): + op_cfg = dict( + type='DiffMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + in_channels=32, + out_channels=32, + stride=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + in_channels=32, + out_channels=32, + stride=1, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + in_channels=32, + out_channels=32, + stride=1, + ), + torch_maxpool_3x3=dict( + type='torchMaxPool2d', + kernel_size=3, + stride=1, + ), + torch_avgpool_3x3=dict( + type='torchAvgPool2d', + kernel_size=3, + stride=1, + ), + ), + ) + op = MODELS.build(op_cfg) + input = torch.randn(4, 32, 64, 64) + + op.fix_chosen('torch_avgpool_3x3') + output = op.forward(input) + assert output is not None diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_gumbelchoiceroute.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_gumbelchoiceroute.py new file mode 100755 index 000000000..5d1a0fc32 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_gumbelchoiceroute.py @@ -0,0 +1,90 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch +import torch.nn as nn + +from mmrazor.models import * # noqa:F403,F401 +from mmrazor.registry import MODELS + +MODELS.register_module(name='torchConv2d', module=nn.Conv2d, force=True) + + +class TestGumbelChoiceRoute(TestCase): + + def test_forward_arch_param(self): + edges_dict = nn.ModuleDict({ + 'first_edge': nn.Conv2d(32, 32, 3, 1, 1), + 'second_edge': nn.Conv2d(32, 32, 5, 1, 2), + 'third_edge': nn.Conv2d(32, 32, 7, 1, 3), + 'fourth_edge': nn.MaxPool2d(3, 1, 1), + 'fifth_edge': nn.AvgPool2d(3, 1, 1), + }) + + gumbel_choice_route_cfg = dict( + type='GumbelChoiceRoute', + edges=edges_dict, + tau=1.0, + hard=True, + with_arch_param=True, + ) + + # test with_arch_param = True + GumbelChoiceRoute = MODELS.build(gumbel_choice_route_cfg) + + arch_param = nn.Parameter(torch.randn(len(edges_dict))) + assert len(arch_param) == 5 + GumbelChoiceRoute.set_temperature(1.0) + + x = [torch.randn(4, 32, 64, 64) for _ in range(5)] + + output = GumbelChoiceRoute.forward_arch_param( + x=x, arch_param=arch_param) + assert output is not None + + # test with_arch_param = False + new_gumbel_choice_route_cfg = gumbel_choice_route_cfg.copy() + new_gumbel_choice_route_cfg['with_arch_param'] = False + + new_gumbel_choice_route = MODELS.build(new_gumbel_choice_route_cfg) + + arch_param = nn.Parameter(torch.randn(len(edges_dict))) + output = new_gumbel_choice_route.forward_arch_param( + x=x, arch_param=arch_param) + assert output is not None + + new_gumbel_choice_route.fix_chosen(chosen=['first_edge']) + + def test_forward_fixed(self): + edges_dict = nn.ModuleDict({ + 'first_edge': nn.Conv2d(32, 32, 3, 1, 1), + 'second_edge': nn.Conv2d(32, 32, 5, 1, 2), + 'third_edge': nn.Conv2d(32, 32, 7, 1, 3), + 'fourth_edge': nn.MaxPool2d(3, 1, 1), + 'fifth_edge': nn.AvgPool2d(3, 1, 1), + }) + + gumbel_choice_route_cfg = dict( + type='GumbelChoiceRoute', + edges=edges_dict, + tau=1.0, + hard=True, + with_arch_param=True, + ) + + # test with_arch_param = True + GumbelChoiceRoute = MODELS.build(gumbel_choice_route_cfg) + + GumbelChoiceRoute.fix_chosen( + chosen=['first_edge', 'second_edge', 'fifth_edge']) + assert GumbelChoiceRoute.is_fixed is True + + x = [torch.randn(4, 32, 64, 64) for _ in range(3)] + output = GumbelChoiceRoute.forward_fixed(x) + assert output is not None + assert GumbelChoiceRoute.num_choices == 3 + + # after is_fixed = True, call fix_chosen + with pytest.raises(AttributeError): + GumbelChoiceRoute.fix_chosen(chosen=['first_edge']) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_mutable_channels.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_mutable_channels.py new file mode 100755 index 000000000..6330005d1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_mutable_channels.py @@ -0,0 +1,33 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest + +import torch + +from mmrazor.models.mutables import (SimpleMutableChannel, + SquentialMutableChannel) + + +class TestMutableChannels(unittest.TestCase): + + def test_SquentialMutableChannel(self): + mutable_channel = SquentialMutableChannel(4) + mutable_channel.current_choice = 3 + self.assertEqual(mutable_channel.activated_channels, + mutable_channel.current_choice) + self.assertTrue( + (mutable_channel.current_mask == torch.tensor([1, 1, 1, + 0]).bool()).all()) + channel_str = mutable_channel.__repr__() + self.assertEqual( + channel_str, + 'SquentialMutableChannel(num_channels=4, activated_channels=3)') + + mutable_channel.fix_chosen() + mutable_channel.dump_chosen() + + def test_SimpleMutableChannel(self): + channel = SimpleMutableChannel(4) + channel.current_choice = torch.tensor([1, 0, 0, 0]).bool() + self.assertEqual(channel.activated_channels, 1) + channel.fix_chosen() + channel.dump_chosen() diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_sequential_mutable_channel.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_sequential_mutable_channel.py new file mode 100755 index 000000000..c807cabe5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_sequential_mutable_channel.py @@ -0,0 +1,57 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch + +from mmrazor.models.mutables import (OneShotMutableValue, + SquentialMutableChannel) + + +class TestSquentialMutableChannel(TestCase): + + def _test_mutable(self, + mutable: SquentialMutableChannel, + set_choice, + get_choice, + activate_channels, + mask=None): + mutable.current_choice = set_choice + assert mutable.current_choice == get_choice + assert mutable.activated_channels == activate_channels + if mask is not None: + assert (mutable.current_mask == mask).all() + + def _generate_mask(self, num: int, all: int): + mask = torch.zeros([all]) + mask[0:num] = 1 + return mask.bool() + + def test_mul_float(self): + channel = SquentialMutableChannel(10) + new_channel = channel * 0.5 + self.assertEqual(new_channel.current_choice, 5) + channel.current_choice = 5 + self.assertEqual(new_channel.current_choice, 2) + + def test_int_choice(self): + channel = SquentialMutableChannel(10) + self._test_mutable(channel, 5, 5, 5, self._generate_mask(5, 10)) + self._test_mutable(channel, 0.2, 2, 2, self._generate_mask(2, 10)) + + def test_float_choice(self): + channel = SquentialMutableChannel(10, choice_mode='ratio') + self._test_mutable(channel, 0.5, 0.5, 5, self._generate_mask(5, 10)) + self._test_mutable(channel, 2, 0.2, 2, self._generate_mask(2, 10)) + + def test_mutable_channel_mul(self): + channel = SquentialMutableChannel(2) + self.assertEqual(channel.current_choice, 2) + mv = OneShotMutableValue(value_list=[1, 2, 3], default_value=3) + derived1 = channel * mv + derived2 = mv * channel + assert derived1.current_choice == 6 + assert derived2.current_choice == 6 + mv.current_choice = mv.min_choice + assert derived1.current_choice == 2 + assert derived2.current_choice == 2 + assert torch.equal(derived1.current_mask, derived2.current_mask) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_dcff_channel_unit.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_dcff_channel_unit.py new file mode 100755 index 000000000..344d90acb --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_dcff_channel_unit.py @@ -0,0 +1,77 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List +from unittest import TestCase + +import torch + +from mmrazor.models.architectures.dynamic_ops import FuseConv2d +from mmrazor.models.mutables import DCFFChannelUnit +from mmrazor.models.task_modules import ChannelAnalyzer +from .....data.models import SingleLineModel + +DEVICE = torch.device('cpu') + + +class TestDCFFChannelUnit(TestCase): + + def test_num(self): + unit = DCFFChannelUnit(48, choice_mode='number') + unit.current_choice = 24 + self.assertEqual(unit.current_choice, 24) + + unit.current_choice = 0.5 + self.assertEqual(unit.current_choice, 24) + + def test_ratio(self): + unit = DCFFChannelUnit(48, choice_mode='ratio') + unit.current_choice = 0.5 + self.assertEqual(unit.current_choice, 0.5) + unit.current_choice = 24 + self.assertEqual(unit.current_choice, 0.5) + + def test_divisor(self): + unit = DCFFChannelUnit(48, choice_mode='number', divisor=8) + unit.current_choice = 20 + self.assertEqual(unit.current_choice, 24) + self.assertTrue(unit.sample_choice() % 8 == 0) + + unit = DCFFChannelUnit(48, choice_mode='ratio', divisor=8) + unit.current_choice = 0.3 + self.assertEqual(unit.current_choice, 1 / 3) + + def test_config_template(self): + unit = DCFFChannelUnit(48, choice_mode='ratio', divisor=8) + config = unit.config_template(with_init_args=True) + unit2 = DCFFChannelUnit.init_from_cfg(None, config) + self.assertDictEqual( + unit2.config_template(with_init_args=True)['init_args'], + config['init_args']) + + def test_init_from_channel_unit(self): + # init using tracer + model = SingleLineModel() + unit_configs = ChannelAnalyzer().analyze(model) + units = [ + DCFFChannelUnit.init_from_cfg(model, unit_config) + for unit_config in unit_configs.values() + ] + + model = model.to(DEVICE) + self._test_units(units, model) + + def _test_units(self, units: List[DCFFChannelUnit], model): + for unit in units: + unit.prepare_for_pruning(model) + mutable_units = [unit for unit in units if unit.is_mutable] + self.assertGreaterEqual(len(mutable_units), 1) + for unit in mutable_units: + choice = unit.sample_choice() + unit.current_choice = choice + for channel in unit.output_related: + if isinstance(channel.module, FuseConv2d): + layeri_softmaxp = channel.module.get_pooled_channel(1.0) + # update fuseconv op's selected layeri_softmax + channel.module.set_forward_args(choice=layeri_softmaxp) + x = torch.rand([2, 3, 224, 224]).to(DEVICE) + y = model(x) + self.assertSequenceEqual(y.shape, [2, 1000]) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_l1_mutable_channel_unit.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_l1_mutable_channel_unit.py new file mode 100755 index 000000000..94bbfe6b6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_l1_mutable_channel_unit.py @@ -0,0 +1,28 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch.nn as nn + +from mmrazor.models.mutables import L1MutableChannelUnit +from mmrazor.models.mutators import ChannelMutator +from .....data.models import SingleLineModel + + +class TestL1MutableChannelUnit(TestCase): + + def test_init(self): + model = SingleLineModel() + mutator = ChannelMutator( + channel_unit_cfg={ + 'type': 'L1MutableChannelUnit', + 'default_args': { + 'choice_mode': 'ratio' + } + }) + mutator.prepare_from_supernet(model) + + def test_convnd(self): + unit = L1MutableChannelUnit(8) + conv = nn.Conv3d(3, 8, 3) + norm = unit._get_l1_norm(conv, 0, 8) + self.assertSequenceEqual(norm.shape, [8]) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_mutable_channel_units.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_mutable_channel_units.py new file mode 100755 index 000000000..219125ece --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_mutable_channel_units.py @@ -0,0 +1,140 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List +from unittest import TestCase + +import torch +import torch.nn as nn + +from mmrazor.models.architectures.dynamic_ops.mixins import DynamicChannelMixin +from mmrazor.models.mutables.mutable_channel import ( + L1MutableChannelUnit, MutableChannelUnit, SequentialMutableChannelUnit) +from mmrazor.models.mutables.mutable_channel.units.channel_unit import \ + ChannelUnit +from .....data.models import SingleLineModel +from .....data.tracer_passed_models import backward_passed_library + +MUTABLE_CFG = dict(type='SimpleMutablechannel') +PARSE_CFG = dict( + type='ChannelAnalyzer', + demo_input=(1, 3, 224, 224), + tracer_type='BackwardTracer') + +DEVICE = torch.device('cpu') +UNITS: List[MutableChannelUnit] = [ + L1MutableChannelUnit, SequentialMutableChannelUnit +] + +DefaultChannelUnit = SequentialMutableChannelUnit + + +def _test_units(units: List[MutableChannelUnit], model): + for unit in units: + unit.prepare_for_pruning(model) + for unit in units: + _ = unit.current_choice + + mutable_units = [unit for unit in units if unit.is_mutable] + assert len(mutable_units) >= 1, \ + 'len of mutable units should greater or equal than 0.' + for unit in mutable_units: + choice = unit.sample_choice() + unit.current_choice = choice + assert abs(unit.current_choice - choice) < 0.1 + x = torch.rand([2, 3, 224, 224]).to(DEVICE) + y = model(x) + assert list(y.shape) == [2, 1000] + + +class TestMutableChannelUnit(TestCase): + + def test_init_from_cfg(self): + model = SingleLineModel() + # init using tracer + + config = { + 'init_args': { + 'num_channels': 8 + }, + 'channels': { + 'input_related': [{ + 'name': 'net.1', + 'start': 0, + 'end': 8, + 'expand_ratio': 1, + 'is_output_channel': False + }, { + 'name': 'net.3', + 'start': 0, + 'end': 8, + 'expand_ratio': 1, + 'is_output_channel': False + }], + 'output_related': [{ + 'name': 'net.0', + 'start': 0, + 'end': 8, + 'expand_ratio': 1, + 'is_output_channel': True + }, { + 'name': 'net.1', + 'start': 0, + 'end': 8, + 'expand_ratio': 1, + 'is_output_channel': True + }] + } + } + units = [DefaultChannelUnit.init_from_cfg(model, config)] + _test_units(units, model) + + def test_init(self): + for UnitClass in UNITS: + with self.subTest(unit_class=UnitClass): + + def test_units(units, model): + mutable_units = [ + UnitClass.init_from_channel_unit(unit) + for unit in units + ] + _test_units(mutable_units, model) + + # init using tracer + model = SingleLineModel() + units: List[ + ChannelUnit] = ChannelUnit.init_from_channel_analyzer( + model) + test_units(units, model) + + # init using tracer config + model = SingleLineModel() + units: List[ + ChannelUnit] = ChannelUnit.init_from_channel_analyzer( + model, analyzer=dict(type='ChannelAnalyzer')) + test_units(units, model) + + print(units) + + def test_replace_with_dynamic_ops(self): + model_datas = backward_passed_library.include_models() + for model_data in model_datas: + for unit_type in UNITS: + with self.subTest(model=model_data, unit=unit_type): + model: nn.Module = model_data() + units: List[ + MutableChannelUnit] = unit_type.init_from_channel_analyzer( # noqa + model) + for unit in units: + unit.prepare_for_pruning(model) + + for module in model.modules(): + if isinstance(module, nn.Conv2d)\ + and module.groups == module.in_channels\ + and module.groups == 1: + self.assertTrue( + isinstance(module, DynamicChannelMixin)) + if isinstance(module, nn.Linear): + self.assertTrue( + isinstance(module, DynamicChannelMixin)) + if isinstance(module, nn.BatchNorm2d): + self.assertTrue( + isinstance(module, DynamicChannelMixin)) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_one_shot_mutable_channel_unit.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_one_shot_mutable_channel_unit.py new file mode 100755 index 000000000..80d9800c6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_one_shot_mutable_channel_unit.py @@ -0,0 +1,33 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +from mmrazor.models.mutables import OneShotMutableChannelUnit +from mmrazor.models.mutators.channel_mutator import ChannelMutator +from tests.data.models import DynamicAttention + + +class TestSequentialMutableChannelUnit(TestCase): + + def test_init(self): + unit = OneShotMutableChannelUnit( + 48, [20, 30, 40], choice_mode='number', divisor=8) + self.assertSequenceEqual(unit.candidate_choices, [24, 32, 40]) + + unit = OneShotMutableChannelUnit( + 48, [0.3, 0.5, 0.7], choice_mode='ratio', divisor=8) + self.assertSequenceEqual(unit.candidate_choices, [1 / 3, 0.5, 2 / 3]) + + def test_unit_predefined(self): + model = DynamicAttention() + mutator = ChannelMutator( + channel_unit_cfg={ + 'type': 'OneShotMutableChannelUnit', + 'default_args': { + 'unit_predefined': False + } + }, + parse_cfg={'type': 'Predefined'}) + mutator.prepare_from_supernet(model) + self.assertSequenceEqual(mutator.units[0].candidate_choices, + [576, 624]) + self.assertSequenceEqual(mutator.units[1].candidate_choices, [64]) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_sequential_mutable_channel_unit.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_sequential_mutable_channel_unit.py new file mode 100755 index 000000000..8981a8a21 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_channel/test_units/test_sequential_mutable_channel_unit.py @@ -0,0 +1,41 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +from mmrazor.models.mutables import SequentialMutableChannelUnit + + +class TestSequentialMutableChannelUnit(TestCase): + + def test_num(self): + unit = SequentialMutableChannelUnit(48) + unit.current_choice = 24 + self.assertEqual(unit.current_choice, 24) + + unit.current_choice = 0.5 + self.assertEqual(unit.current_choice, 24) + + def test_ratio(self): + unit = SequentialMutableChannelUnit(48, choice_mode='ratio') + unit.current_choice = 0.5 + self.assertEqual(unit.current_choice, 0.5) + unit.current_choice = 24 + self.assertEqual(unit.current_choice, 0.5) + + def test_divisor(self): + unit = SequentialMutableChannelUnit( + 48, choice_mode='number', divisor=8) + unit.current_choice = 20 + self.assertEqual(unit.current_choice, 24) + self.assertTrue(unit.sample_choice() % 8 == 0) + + unit = SequentialMutableChannelUnit(48, choice_mode='ratio', divisor=8) + unit.current_choice = 0.3 + self.assertEqual(unit.current_choice, 1 / 3) + + def test_config_template(self): + unit = SequentialMutableChannelUnit(48, choice_mode='ratio', divisor=8) + config = unit.config_template(with_init_args=True) + unit2 = SequentialMutableChannelUnit.init_from_cfg(None, config) + self.assertDictEqual( + unit2.config_template(with_init_args=True)['init_args'], + config['init_args']) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_value.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_value.py new file mode 100755 index 000000000..11ac7d49c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_mutable_value.py @@ -0,0 +1,119 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch + +from mmrazor.models.mutables import (MutableValue, OneShotMutableValue, + SquentialMutableChannel) + + +class TestMutableValue(TestCase): + + def test_init_mutable_value(self) -> None: + value_list = [2, 4, 6] + mv = MutableValue(value_list=value_list) + assert mv.current_choice == 2 + assert mv.num_choices == 3 + + mv = MutableValue(value_list=value_list, default_value=4) + assert mv.current_choice == 4 + + with pytest.raises(ValueError): + mv = MutableValue(value_list=value_list, default_value=5) + + mv = MutableValue(value_list=[2]) + assert mv.current_choice == 2 + assert mv.choices == [2] + + with pytest.raises(TypeError): + mv = MutableValue(value_list=[2, 3.2]) + + def test_init_one_shot_mutable_value(self) -> None: + value_list = [6, 4, 2] + mv = OneShotMutableValue(value_list=value_list) + assert mv.current_choice == 6 + assert mv.choices == [2, 4, 6] + + mv = OneShotMutableValue(value_list=value_list, default_value=4) + assert mv.current_choice == 4 + + def test_fix_chosen(self) -> None: + mv = MutableValue([2, 3, 4]) + chosen = mv.dump_chosen() + assert chosen.chosen == mv.current_choice + assert chosen.meta['all_choices'] == mv.choices + + with pytest.raises(AssertionError): + mv.fix_chosen(5) + + mv.fix_chosen(3) + assert mv.current_choice == 3 + + with pytest.raises(RuntimeError): + mv.fix_chosen(chosen) + + def test_one_shot_mutable_value_sample(self) -> None: + mv = OneShotMutableValue(value_list=[2, 3, 4]) + assert mv.max_choice == 4 + assert mv.min_choice == 2 + + for _ in range(100): + assert mv.sample_choice() in mv.choices + + def test_mul(self) -> None: + mv = MutableValue(value_list=[1, 2, 3], default_value=3) + mul_derived_mv = mv * 2 + rmul_derived_mv = 2 * mv + + assert mul_derived_mv.current_choice == 6 + assert rmul_derived_mv.current_choice == 6 + + mv.current_choice = 2 + assert mul_derived_mv.current_choice == 4 + assert rmul_derived_mv.current_choice == 4 + + mv = MutableValue(value_list=[1, 2, 3], default_value=3) + mc = SquentialMutableChannel(num_channels=4) + + with pytest.raises(TypeError): + _ = mc * mv + with pytest.raises(TypeError): + _ = mv * mc + + mv = OneShotMutableValue(value_list=[1, 2, 3], default_value=3) + mc.current_choice = 2 + + derived1 = mc * mv + derived2 = mv * mc + + assert derived1.current_choice == 6 + assert derived2.current_choice == 6 + assert torch.equal(derived1.current_mask, derived2.current_mask) + + mv.current_choice = 2 + assert derived1.current_choice == 4 + assert derived2.current_choice == 4 + assert torch.equal(derived1.current_mask, derived2.current_mask) + + def test_floordiv(self) -> None: + mv = MutableValue(value_list=[120, 128, 136]) + derived_mv = mv // 8 + + mv.current_choice = 120 + assert derived_mv.current_choice == 16 + mv.current_choice = 128 + assert derived_mv.current_choice == 16 + + derived_mv = mv // (8, 3) + mv.current_choice = 120 + assert derived_mv.current_choice == 15 + mv.current_choice = 136 + assert derived_mv.current_choice == 18 + + def test_repr(self) -> None: + value_list = [2, 4, 6] + mv = MutableValue(value_list=value_list) + + assert repr(mv) == \ + f'MutableValue(value_list={value_list}, current_choice=2)' diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_onehotop.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_onehotop.py new file mode 100755 index 000000000..a3b86d745 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_onehotop.py @@ -0,0 +1,200 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch +import torch.nn as nn + +from mmrazor.models import * # noqa:F403,F401 +from mmrazor.registry import MODELS + +MODELS.register_module(name='torchConv2d', module=nn.Conv2d, force=True) +MODELS.register_module(name='torchMaxPool2d', module=nn.MaxPool2d, force=True) +MODELS.register_module(name='torchAvgPool2d', module=nn.AvgPool2d, force=True) + + +class TestOneHotOP(TestCase): + + def test_forward_arch_param(self): + op_cfg = dict( + type='mmrazor.OneHotMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + padding=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + padding=2, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + padding=3, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + input = torch.randn(4, 32, 64, 64) + + arch_param = nn.Parameter(torch.randn(len(op_cfg['candidates']))) + output = op.forward_arch_param(input, arch_param=arch_param) + assert output is not None + + # test when some element of arch_param is 0 + arch_param = nn.Parameter(torch.ones(op.num_choices)) + output = op.forward_arch_param(input, arch_param=arch_param) + assert output is not None + + def test_forward_fixed(self): + op_cfg = dict( + type='mmrazor.OneHotMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + input = torch.randn(4, 32, 64, 64) + + op.fix_chosen('torch_conv2d_7x7') + output = op.forward_fixed(input) + + assert output is not None + assert op.is_fixed is True + + def test_forward(self): + op_cfg = dict( + type='mmrazor.OneHotMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + padding=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + padding=2, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + padding=3, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + input = torch.randn(4, 32, 64, 64) + + # test set_forward_args + arch_param = nn.Parameter(torch.randn(len(op_cfg['candidates']))) + op.set_forward_args(arch_param=arch_param) + output = op.forward(input) + assert output is not None + + # test dump_chosen + with pytest.raises(AssertionError): + op.dump_chosen() + + # test forward when is_fixed is True + op.fix_chosen('torch_conv2d_7x7') + output = op.forward(input) + + def test_property(self): + op_cfg = dict( + type='mmrazor.OneHotMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + padding=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + padding=2, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + padding=3, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + + assert len(op.choices) == 3 + + # test is_fixed propty + assert op.is_fixed is False + + # test is_fixed setting + op.fix_chosen('torch_conv2d_5x5') + + with pytest.raises(AttributeError): + op.is_fixed = True + + # test fix choice when is_fixed is True + with pytest.raises(AttributeError): + op.fix_chosen('torch_conv2d_3x3') + + def test_module_kwargs(self): + op_cfg = dict( + type='mmrazor.OneHotMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + in_channels=32, + out_channels=32, + stride=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + in_channels=32, + out_channels=32, + stride=1, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + in_channels=32, + out_channels=32, + stride=1, + ), + torch_maxpool_3x3=dict( + type='torchMaxPool2d', + kernel_size=3, + stride=1, + ), + torch_avgpool_3x3=dict( + type='torchAvgPool2d', + kernel_size=3, + stride=1, + ), + ), + ) + op = MODELS.build(op_cfg) + input = torch.randn(4, 32, 64, 64) + + op.fix_chosen('torch_avgpool_3x3') + output = op.forward(input) + assert output is not None diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_oneshotop.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_oneshotop.py new file mode 100755 index 000000000..3704e67a8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_oneshotop.py @@ -0,0 +1,241 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch +import torch.nn as nn + +import mmrazor.models # noqa:F401 +from mmrazor.registry import MODELS + + +class TestMutables(TestCase): + + def test_oneshotmutableop(self): + norm_cfg = dict(type='BN', requires_grad=True) + op_cfg = dict( + type='OneShotMutableOP', + candidates=dict( + shuffle_3x3=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=3), + shuffle_5x5=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=5), + shuffle_7x7=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=7), + shuffle_xception=dict( + type='ShuffleXception', + norm_cfg=norm_cfg, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + input = torch.randn(4, 32, 64, 64) + + # test forward all + output = op.forward_all(input) + assert output is not None + + # test random choice + assert op.sample_choice() in [ + 'shuffle_3x3', 'shuffle_5x5', 'shuffle_7x7', 'shuffle_xception' + ] + + # test unfixed mode + op.current_choice = 'shuffle_3x3' + output1 = op.forward(input) + + op.current_choice = 'shuffle_7x7' + output2 = op.forward(input) + + assert not output1.equal(output2) + + assert op.is_fixed is False + assert len(op.choices) == 4 + assert op.num_choices == 4 + + # compare set_forward_args with forward with choice + op.current_choice = 'shuffle_5x5' + output1 = op.forward(input) + output2 = op.forward_choice(input, choice='shuffle_5x5') + assert output1.equal(output2) + + # test fixed mode + op.fix_chosen('shuffle_3x3') + assert op.is_fixed is True + assert len(op.choices) == 1 + assert op.num_choices == 1 + + output = op.forward(input) + assert output.shape[1] == 32 + + with pytest.raises(AttributeError): + op.is_fixed = True + + with pytest.raises(AttributeError): + op.fix_chosen('shuffle_3x3') + + def test_oneshotprobop(self): + norm_cfg = dict(type='BN', requires_grad=True) + op_cfg = dict( + type='OneShotProbMutableOP', + choice_probs=[0.1, 0.2, 0.3, 0.4], + candidates=dict( + shuffle_3x3=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=3), + shuffle_5x5=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=5), + shuffle_7x7=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=7), + shuffle_xception=dict( + type='ShuffleXception', + norm_cfg=norm_cfg, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + + input = torch.randn(4, 32, 64, 64) + + # test forward choice with None + with pytest.raises(AssertionError): + output = op.forward_choice(input, choice=None) + + # test forward all + output = op.forward_all(input) + assert output.shape[1] == 32 + + # test random choice + assert op.sample_choice() in [ + 'shuffle_3x3', 'shuffle_5x5', 'shuffle_7x7', 'shuffle_xception' + ] + assert 1 - sum(op.choice_probs) < 0.00001 + + # test unfixed mode + op.current_choice = 'shuffle_3x3' + output = op.forward(input) + + assert output.shape[1] == 32 + + op.current_choice = 'shuffle_7x7' + output = op.forward(input) + assert output.shape[1] == 32 + + assert op.is_fixed is False + assert len(op.choices) == 4 + assert op.num_choices == 4 + + # test fixed mode + op.fix_chosen('shuffle_3x3') + assert op.is_fixed is True + assert len(op.choices) == 1 + assert op.num_choices == 1 + + output = op.forward(input) + assert output.shape[1] == 32 + + with pytest.raises(AttributeError): + op.is_fixed = True + + def test_forward_choice(self): + norm_cfg = dict(type='BN', requires_grad=True) + op_cfg = dict( + type='OneShotMutableOP', + candidates=dict( + shuffle_3x3=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=3), + shuffle_5x5=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=5), + shuffle_7x7=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=7), + shuffle_xception=dict( + type='ShuffleXception', + norm_cfg=norm_cfg, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + input = torch.randn(4, 32, 64, 64) + + assert op.forward_choice(input, choice='shuffle_3x3') is not None + + def test_fix_chosen(self): + norm_cfg = dict(type='BN', requires_grad=True) + op_cfg = dict( + type='OneShotMutableOP', + candidates=dict( + shuffle_3x3=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=3), + shuffle_5x5=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=5), + shuffle_7x7=dict( + type='ShuffleBlock', norm_cfg=norm_cfg, kernel_size=7), + shuffle_xception=dict( + type='ShuffleXception', + norm_cfg=norm_cfg, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + op = MODELS.build(op_cfg) + + with pytest.raises(AttributeError): + op.fix_chosen('shuffle_xception') + op.fix_chosen('ShuffleBlock') + + def test_build_ops(self): + norm_cfg = dict(type='BN', requires_grad=True) + op_cfg = dict( + type='OneShotMutableOP', + candidates=dict( + shuffle_3x3=dict( + type='ShuffleBlock', + norm_cfg=norm_cfg, + kernel_size=3, + in_channels=32, + out_channels=32), + shuffle_5x5=dict( + type='ShuffleBlock', + norm_cfg=norm_cfg, + kernel_size=5, + in_channels=32, + out_channels=32), + shuffle_7x7=dict( + type='ShuffleBlock', + norm_cfg=norm_cfg, + kernel_size=7, + in_channels=32, + out_channels=32), + shuffle_xception=dict( + type='ShuffleXception', + norm_cfg=norm_cfg, + in_channels=32, + out_channels=32), + ), + ) + op = MODELS.build(op_cfg) + input = torch.randn(4, 32, 64, 64) + + output = op.forward_all(input) + assert output is not None + + def test_candidates(self): + + candidates = nn.ModuleDict({ + 'conv3x3': nn.Conv2d(32, 32, 3, 1, 1), + 'conv5x5': nn.Conv2d(32, 32, 5, 1, 2), + 'conv7x7': nn.Conv2d(32, 32, 7, 1, 3), + 'maxpool3x3': nn.MaxPool2d(3, 1, 1), + 'avgpool3x3': nn.AvgPool2d(3, 1, 1), + }) + + op_cfg = dict(type='OneShotMutableOP', candidates=candidates) + + op = MODELS.build(op_cfg) + + input = torch.randn(4, 32, 64, 64) + + output = op.forward_all(input) + assert output is not None diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_sequential_mutable_channel.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_sequential_mutable_channel.py new file mode 100755 index 000000000..f7f4bb91e --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutables/test_sequential_mutable_channel.py @@ -0,0 +1,14 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +from mmrazor.models.mutables import SquentialMutableChannel + + +class TestSquentialMutableChannel(TestCase): + + def test_mul_float(self): + channel = SquentialMutableChannel(10) + new_channel = channel * 0.5 + self.assertEqual(new_channel.current_choice, 5) + channel.current_choice = 5 + self.assertEqual(new_channel.current_choice, 2) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_channel_mutator.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_channel_mutator.py new file mode 100755 index 000000000..1d9d290a2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_channel_mutator.py @@ -0,0 +1,180 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import unittest +from typing import Union + +import torch + +# from mmrazor.models.mutables import MutableChannelUnit +from mmrazor.models.mutables.mutable_channel import ( + L1MutableChannelUnit, SequentialMutableChannelUnit) +from mmrazor.models.mutators.channel_mutator import ChannelMutator +from mmrazor.models.task_modules import ChannelAnalyzer +from mmrazor.registry import MODELS +from ...data.models import DynamicAttention, DynamicLinearModel, DynamicMMBlock +from ...data.tracer_passed_models import backward_passed_library + + +@MODELS.register_module() +class RandomChannelUnit(SequentialMutableChannelUnit): + + def generate_mask(self, choice: Union[int, float]) -> torch.Tensor: + if isinstance(choice, float): + choice = max(1, int(self.num_channels * choice)) + assert 0 < choice <= self.num_channels + rand_imp = torch.rand([self.num_channels]) + ind = rand_imp.topk(choice)[1] + mask = torch.zeros([self.num_channels]) + mask.scatter_(-1, ind, 1) + return mask + + +DATA_UNITS = [ + SequentialMutableChannelUnit, RandomChannelUnit, L1MutableChannelUnit +] + + +class TestChannelMutator(unittest.TestCase): + + def _test_a_mutator(self, mutator: ChannelMutator, model): + self.assertGreater(len(mutator.mutable_units), 0) + x = torch.rand([2, 3, 224, 224]) + y = model(x) + self.assertEqual(list(y.shape), [2, 1000]) + + def test_init(self): + model = backward_passed_library.include_models()[0]() + mutator = ChannelMutator(parse_cfg=ChannelAnalyzer()) + mutator.prepare_from_supernet(model) + self.assertGreaterEqual(len(mutator.mutable_units), 1) + self._test_a_mutator(mutator, model) + + def test_sample_subnet(self): + data_models = backward_passed_library.include_models()[:2] + + for i, data in enumerate(data_models): + with self.subTest(i=i, data=data): + model = data() + + mutator = ChannelMutator() + mutator.prepare_from_supernet(model) + + self.assertGreaterEqual(len(mutator.mutable_units), 1) + + self._test_a_mutator(mutator, model) + + def test_generic_support(self): + data_models = backward_passed_library.include_models() + + for data_model in data_models[:1]: + for unit_type in DATA_UNITS: + with self.subTest(model=data_model, unit=unit_type): + + model = data_model() + + mutator = ChannelMutator(channel_unit_cfg=unit_type) + mutator.prepare_from_supernet(model) + mutator.units + + self._test_a_mutator(mutator, model) + + def test_init_units_from_cfg(self): + ARCHITECTURE_CFG = dict( + type='mmcls.ImageClassifier', + backbone=dict(type='mmcls.MobileNetV2', widen_factor=1.5), + neck=dict(type='mmcls.GlobalAveragePooling'), + head=dict( + type='mmcls.LinearClsHead', + num_classes=1000, + in_channels=1920, + loss=dict(type='mmcls.CrossEntropyLoss', loss_weight=1.0), + topk=(1, 5))) + model = MODELS.build(ARCHITECTURE_CFG) + + # generate config + model1 = copy.deepcopy(model) + mutator = ChannelMutator() + mutator.prepare_from_supernet(model1) + config = mutator.config_template( + with_channels=True, with_unit_init_args=True) + + # test passing config + model2 = copy.deepcopy(model) + config2 = copy.deepcopy(config) + config2['parse_cfg'] = {'type': 'Config'} + mutator2 = MODELS.build(config2) + mutator2.prepare_from_supernet(model2) + self.assertEqual( + len(mutator.mutable_units), len(mutator2.mutable_units)) + self._test_a_mutator(mutator2, model2) + + def test_mix_config_tracer(self): + model = backward_passed_library.include_models()[0]() + + model0 = copy.deepcopy(model) + mutator0 = ChannelMutator() + mutator0.prepare_from_supernet(model0) + config = mutator0.config_template(with_unit_init_args=True) + + model1 = copy.deepcopy(model) + mutator1 = MODELS.build(config) + mutator1.prepare_from_supernet(model1) + config1 = mutator1.config_template(with_unit_init_args=True) + + self.assertDictEqual(config1, config) + self._test_a_mutator(mutator1, model1) + + def test_models_with_predefined_dynamic_op(self): + for Model in [ + DynamicLinearModel, + ]: + with self.subTest(model=Model): + model = Model() + mutator = ChannelMutator( + channel_unit_cfg={ + 'type': 'OneShotMutableChannelUnit', + 'default_args': {} + }, + parse_cfg={'type': 'Predefined'}) + mutator.prepare_from_supernet(model) + self._test_a_mutator(mutator, model) + + def test_models_with_predefined_dynamic_op_without_pruning(self): + for Model in [ + DynamicAttention, + ]: + with self.subTest(model=Model): + model = Model() + mutator = ChannelMutator( + channel_unit_cfg={ + 'type': 'OneShotMutableChannelUnit', + 'default_args': { + 'unit_predefined': True + } + }, + parse_cfg={'type': 'Predefined'}) + mutator.prepare_from_supernet(model) + self.assertGreater(len(mutator.mutable_units), 0) + x = torch.rand([2, 3, 224, 224]) + y = model(x) + self.assertEqual(list(y.shape), [2, 624]) + + def test_related_shortcut_layer(self): + for Model in [ + DynamicMMBlock, + ]: + with self.subTest(model=Model): + model = Model() + mutator = ChannelMutator( + channel_unit_cfg={ + 'type': 'OneShotMutableChannelUnit', + 'default_args': { + 'unit_predefined': True + } + }, + parse_cfg={'type': 'Predefined'}) + mutator.prepare_from_supernet(model) + self.assertGreater(len(mutator.mutable_units), 0) + x = torch.rand([2, 3, 224, 224]) + y = model(x) + self.assertEqual(list(y[-1].shape), [2, 1984, 1, 1]) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dcff_mutator.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dcff_mutator.py new file mode 100755 index 000000000..fc0250248 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dcff_mutator.py @@ -0,0 +1,101 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +from mmcls.models import * # noqa: F401,F403 +from torch import Tensor, nn +from torch.nn import Module + +from mmrazor.models.mutators import DCFFChannelMutator + + +class MultiConcatModel(Module): + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.op2 = nn.Conv2d(3, 8, 1) + self.op3 = nn.Conv2d(16, 8, 1) + self.op4 = nn.Conv2d(3, 8, 1) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.op1(x) + x2 = self.op2(x) + cat1 = torch.cat([x1, x2], dim=1) + x3 = self.op3(cat1) + x4 = self.op4(x) + output = torch.cat([x3, x4], dim=1) + + return output + + +class MultiConcatModel2(Module): + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.op2 = nn.Conv2d(3, 8, 1) + self.op3 = nn.Conv2d(3, 8, 1) + self.op4 = nn.Conv2d(24, 8, 1) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.op1(x) + x2 = self.op2(x) + x3 = self.op3(x) + cat1 = torch.cat([x1, x2], dim=1) + cat2 = torch.cat([cat1, x3], dim=1) + output = self.op4(cat2) + + return output + + +class ConcatModel(Module): + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.bn1 = nn.BatchNorm2d(8) + self.op2 = nn.Conv2d(3, 8, 1) + self.bn2 = nn.BatchNorm2d(8) + self.op3 = nn.Conv2d(16, 8, 1) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.bn1(self.op1(x)) + x2 = self.bn2(self.op2(x)) + cat1 = torch.cat([x1, x2], dim=1) + x3 = self.op3(cat1) + + return x3 + + +class ResBlock(Module): + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.bn1 = nn.BatchNorm2d(8) + self.op2 = nn.Conv2d(8, 8, 1) + self.bn2 = nn.BatchNorm2d(8) + self.op3 = nn.Conv2d(8, 8, 1) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.bn1(self.op1(x)) + x2 = self.bn2(self.op2(x1)) + x3 = self.op3(x2 + x1) + return x3 + + +def test_DCFF_channel_mutator() -> None: + imgs = torch.randn(16, 3, 224, 224) + + # ResBlock + mutator = DCFFChannelMutator(channel_unit_cfg=dict(type='DCFFChannelUnit')) + + model = ResBlock() + mutator.prepare_from_supernet(model) + mutator.calc_information(1.0) + out3 = model(imgs) + + assert out3.shape == (16, 8, 224, 224) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dmcp_mutator.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dmcp_mutator.py new file mode 100755 index 000000000..eea8e2a08 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_dmcp_mutator.py @@ -0,0 +1,40 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch +from mmcls.models import * # noqa: F401,F403 +from torch import Tensor, nn +from torch.nn import Module + +from mmrazor.models.mutators import DMCPChannelMutator + + +class ResBlock(Module): + + def __init__(self) -> None: + super().__init__() + + self.op1 = nn.Conv2d(3, 8, 1) + self.bn1 = nn.BatchNorm2d(8) + self.op2 = nn.Conv2d(8, 8, 1) + self.bn2 = nn.BatchNorm2d(8) + self.op3 = nn.Conv2d(8, 8, 1) + + def forward(self, x: Tensor) -> Tensor: + x1 = self.bn1(self.op1(x)) + x2 = self.bn2(self.op2(x1)) + x3 = self.op3(x2 + x1) + return x3 + + +def test_DMCP_channel_mutator() -> None: + imgs = torch.randn(16, 3, 224, 224) + + # ResBlock + mutator = DMCPChannelMutator(channel_unit_cfg=dict(type='DMCPChannelUnit')) + + model = ResBlock() + mutator.prepare_from_supernet(model) + for mode in ['max', 'min', 'random', 'expected', 'direct']: + mutator.sample_subnet(mode, arch_train=True) + out3 = model(imgs) + + assert out3.shape == (16, 8, 224, 224) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_nas_mutator.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_nas_mutator.py new file mode 100755 index 000000000..dce6b6c38 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_mutators/test_nas_mutator.py @@ -0,0 +1,196 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest + +import pytest +import torch +import torch.nn as nn +from mmcv.cnn import ConvModule + +from mmrazor.models.architectures.utils import mutate_conv_module +from mmrazor.models.mutables import (MutableChannelContainer, MutableValue, + OneShotMutableChannel, + OneShotMutableChannelUnit, + OneShotMutableValue) +from mmrazor.models.mutables.mutable_module import MutableModule +from mmrazor.models.mutators import NasMutator +from mmrazor.registry import MODELS + +MODELS.register_module(name='torchConv2d', module=nn.Conv2d, force=True) +MODELS.register_module(name='torchMaxPool2d', module=nn.MaxPool2d, force=True) +MODELS.register_module(name='torchAvgPool2d', module=nn.AvgPool2d, force=True) + + +class SearchableLayer(nn.Module): + + def __init__(self, mutable_cfg: dict) -> None: + super().__init__() + self.op1 = MODELS.build(mutable_cfg) + self.op2 = MODELS.build(mutable_cfg) + self.op3 = MODELS.build(mutable_cfg) + + def forward(self, x): + x = self.op1(x) + x = self.op2(x) + return self.op3(x) + + +class SearchableModel(nn.Module): + """A searchable model with a mixed search space as follows: + + 1. value search. + 2. module search. + 3. channel search. + """ + + def __init__(self, mutable_cfg: dict) -> None: + super().__init__() + + self.first_conv = ConvModule( + in_channels=3, + out_channels=32, + kernel_size=3, + stride=2, + padding=1, + conv_cfg=dict(type='mmrazor.BigNasConv2d'), + norm_cfg=dict(type='mmrazor.DynamicBatchNorm2d')) + + self.second_conv = ConvModule( + in_channels=32, + out_channels=32, + kernel_size=1, + stride=1, + padding=1, + conv_cfg=dict(type='mmrazor.BigNasConv2d')) + + self.slayer1 = SearchableLayer(mutable_cfg) + self.slayer2 = SearchableLayer(mutable_cfg) + self.slayer3 = SearchableLayer(mutable_cfg) + + self.register_mutables() + + def forward(self, x): + x = self.first_conv(x) + x = self.second_conv(x) + x = self.slayer1(x) + x = self.slayer2(x) + return self.slayer3(x) + + def register_mutables(self): + """Mutate the defined model.""" + OneShotMutableChannelUnit._register_channel_container( + self, MutableChannelContainer) + + mutable_kernel_size = OneShotMutableValue( + value_list=[1, 3], default_value=3) + mutable_out_channels = OneShotMutableChannel( + 32, candidate_choices=[16, 32]) + mutate_conv_module( + self.first_conv, + mutable_kernel_size=mutable_kernel_size, + mutable_out_channels=mutable_out_channels) + + # dont forget the last connection. + MutableChannelContainer.register_mutable_channel_to_module( + self.second_conv.conv, mutable_out_channels, False) + + +class TestNasMutator(unittest.TestCase): + + def setUp(self): + self.MUTABLE_CFG = dict( + type='DiffMutableOP', + candidates=dict( + torch_conv2d_3x3=dict( + type='torchConv2d', + kernel_size=3, + padding=1, + ), + torch_conv2d_5x5=dict( + type='torchConv2d', + kernel_size=5, + padding=2, + ), + torch_conv2d_7x7=dict( + type='torchConv2d', + kernel_size=7, + padding=3, + ), + ), + module_kwargs=dict(in_channels=32, out_channels=32, stride=1)) + + self.MUTATOR_CFG = dict(type='NasMutator') + + def test_models_with_predefined_dynamic_op(self): + for Model in [SearchableModel]: + with self.subTest(model=Model): + model = SearchableModel(self.MUTABLE_CFG) + mutator = MODELS.build(self.MUTATOR_CFG) + assert isinstance(mutator, NasMutator) + + with pytest.raises(RuntimeError): + _ = mutator.search_groups + mutator.prepare_from_supernet(model) + assert hasattr(mutator, 'search_groups') + + with pytest.raises(AttributeError): + _ = mutator.arch_params + mutator.prepare_arch_params() + assert hasattr(mutator, 'arch_params') + + for name in mutator.search_groups.keys(): + assert 'value' or 'channel' or 'module' in name + + self.assertEqual(len(mutator.arch_params.keys()), 9) + for v in mutator.arch_params.values(): + self.assertEqual(v.size()[0], 3) + + mutable_values = [] + mutable_modules = [] + for name, module in model.named_modules(): + if isinstance(module, MutableValue): + mutable_values.append(name) + elif isinstance(module, MutableModule): + mutable_modules.append(name) + elif hasattr(module, 'source_mutables'): + for each_mutables in module.source_mutables: + if isinstance(each_mutables, MutableValue): + mutable_values.append(each_mutables) + elif isinstance(each_mutables, MutableModule): + mutable_modules.append(each_mutables) + + num_mutables = len(mutable_values) + \ + len(mutable_modules) + len(mutator.mutable_units) + self.assertEqual(len(mutator.search_groups), num_mutables) + + choices = mutator.sample_choices() + min_choices = mutator.sample_choices(kind='min') + max_choices = mutator.sample_choices(kind='max') + + self.assertEqual(choices.keys(), min_choices.keys()) + self.assertEqual(choices.keys(), max_choices.keys()) + + with self.assertRaises(NotImplementedError): + _ = mutator.sample_choices(kind='mun') + + assert hasattr(mutator, 'current_choices') + with self.assertWarnsRegex( + UserWarning, 'mutables with `arch param` detected'): + _ = mutator.max_choices + + with self.assertWarnsRegex( + UserWarning, 'mutables with `arch param` detected'): + _ = mutator.min_choices + + with self.assertWarnsRegex( + UserWarning, 'mutables with `arch param` detected'): + mutator.set_max_choices() + + with self.assertWarnsRegex( + UserWarning, 'mutables with `arch param` detected'): + mutator.set_min_choices() + + mutator.set_choices(choices) + + x = torch.rand([1, 3, 224, 224]) + y = model(x) + self.assertEqual(list(y.shape), [1, 32, 114, 114]) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_lsq_observer.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_lsq_observer.py new file mode 100755 index 000000000..a61f95d7f --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_lsq_observer.py @@ -0,0 +1,77 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch + +from mmrazor import digit_version +from mmrazor.models import LSQObserver, LSQPerChannelObserver + + +class TestLSQObserver(TestCase): + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + self.lsq = LSQObserver.with_args( + dtype=torch.quint8, + qscheme=torch.per_tensor_symmetric, + reduce_range=False, + quant_min=0, + quant_max=255) + + def test_forward(self): + lsq_observer = self.lsq() + torch.manual_seed(42) + X = torch.rand(20, 10, dtype=torch.float32) + Y = lsq_observer(X) + # Output of observer is identical to input + self.assertTrue(torch.equal(Y, X)) + + X = torch.rand(0, dtype=torch.float32) + Y = lsq_observer(X) + # Output of observer is identical to input + self.assertTrue(torch.equal(Y, X)) + + def test_calculate_qparams(self): + lsq_observer = self.lsq() + X = torch.ones(10, dtype=torch.float32) + _ = lsq_observer(X) + scale, zero_point = lsq_observer.calculate_qparams() + # tensor_norm = 1, quant_max = 255 + self.assertEqual(scale, 2 * torch.tensor([1.]) / (255**0.5)) + self.assertEqual(zero_point, 127) + + +class TestLSQPerChannelObserver(TestCase): + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + self.lsq = LSQPerChannelObserver.with_args( + dtype=torch.qint8, + qscheme=torch.per_channel_symmetric, + reduce_range=False, + quant_min=-127, + quant_max=127) + + def test_forward(self): + lsq_observer = self.lsq() + torch.manual_seed(42) + X = torch.rand(2, 10, dtype=torch.float32) + Y = lsq_observer(X) + # Output of observer is identical to input + self.assertTrue(torch.equal(Y, X)) + + X = torch.rand(0, dtype=torch.float32) + Y = lsq_observer(X) + # Output of observer is identical to input + self.assertTrue(torch.equal(Y, X)) + + def test_calculate_qparams(self): + lsq_observer = self.lsq() + X = torch.ones(2, 10, dtype=torch.float32) + X[0] -= 1 + _ = lsq_observer(X) + scale, zero_point = lsq_observer.calculate_qparams() + self.assertEqual(scale[0], 2 * torch.tensor([0.]) / (127**0.5)) + self.assertEqual(scale[1], 2 * torch.tensor([1.]) / (127**0.5)) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_torch_observers.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_torch_observers.py new file mode 100755 index 000000000..cc32e69d8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_observers/test_torch_observers.py @@ -0,0 +1,18 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import pytest +import torch + +from mmrazor import digit_version +from mmrazor.models.observers import register_torch_observers +from mmrazor.registry import MODELS + + +@pytest.mark.skipif( + digit_version(torch.__version__) < digit_version('1.13.0'), + reason='version of torch < 1.13.0') +def test_register_torch_observers(): + + TORCH_observers = register_torch_observers() + assert isinstance(TORCH_observers, list) + for observer in TORCH_observers: + assert MODELS.get(observer) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_academic_quantizer.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_academic_quantizer.py new file mode 100755 index 000000000..c95060a00 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_academic_quantizer.py @@ -0,0 +1,167 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from copy import copy +from unittest import TestCase + +import torch +from mmengine.model import BaseModule + +try: + from torch.ao.nn.intrinsic import ConvBnReLU2d + from torch.ao.quantization.backend_config import BackendConfig + from torch.ao.quantization.fx.custom_config import PrepareCustomConfig + from torch.ao.quantization.fx.graph_module import ObservedGraphModule + from torch.ao.quantization.qconfig_mapping import QConfigMapping + from torch.ao.quantization.quant_type import QuantType +except ImportError: + from mmrazor.utils import get_placeholder + ConvBnReLU2d = get_placeholder('torch>=1.13') + BackendConfig = get_placeholder('torch>=1.13') + PrepareCustomConfig = get_placeholder('torch>=1.13') + ConObservedGraphModuleBnReLU2d = get_placeholder('torch>=1.13') + QConfigMapping = get_placeholder('torch>=1.13') + QuantType = get_placeholder('torch>=1.13') + +from mmrazor import digit_version +from mmrazor.models.quantizers import AcademicQuantizer +from mmrazor.models.quantizers.academic_quantizer import ( + FLOAT_TO_OBSERVED_DICT_KEY, GLOBAL_DICT_KEY, MODULE_NAME_DICT_KEY, + OBJECT_TYPE_DICT_KEY, PRESERVED_ATTRIBUTES_DICT_KEY) +from mmrazor.registry import MODELS +from mmrazor.testing import ConvBNReLU + + +@MODELS.register_module() +class ToyFloatModel(BaseModule): + + def __init__(self) -> None: + super().__init__() + + +@MODELS.register_module() +class ToyObservedModel(BaseModule): + + def __init__(self) -> None: + super().__init__() + + +class TestAcademicQuantizer(TestCase): + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + self.global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict(qdtype='qint8', bit=8, is_symmetry=True), + a_qscheme=dict(qdtype='quint8', bit=8, is_symmetry=True), + ) + self.qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict(qdtype='qint8', bit=4, is_symmetry=True), + a_qscheme=dict(qdtype='quint8', bit=4, is_symmetry=True), + ) + self.model = ConvBNReLU(3, 3, norm_cfg=dict(type='BN')) + + def test_gen_qconfig_mapping(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + # test set GLOBAL_DICT_KEY by QConfigMapping + global_qconfig = copy(self.global_qconfig) + qconfig_mapping = {GLOBAL_DICT_KEY: global_qconfig} + quantizer = AcademicQuantizer(qconfig_mapping=qconfig_mapping) + assert hasattr(quantizer, 'qconfig_mapping') + assert isinstance(quantizer.qconfig_mapping, QConfigMapping) + assert quantizer.qconfig_mapping.global_qconfig + + # test set OBJECT_TYPE_DICT_KEY by QConfigMapping + qconfig = copy(self.qconfig) + qconfig_mapping = { + OBJECT_TYPE_DICT_KEY: + [('torch.ao.nn.intrinsic.ConvBnReLU2d', qconfig)] + } + quantizer = AcademicQuantizer(qconfig_mapping=qconfig_mapping) + assert hasattr(quantizer, 'qconfig_mapping') + assert isinstance(quantizer.qconfig_mapping, QConfigMapping) + assert quantizer.qconfig_mapping.object_type_qconfigs.get(ConvBnReLU2d) + + # test set MODULE_NAME_DICT_KEY by QConfigMapping + qconfig = copy(self.qconfig) + qconfig_mapping = { + MODULE_NAME_DICT_KEY: [('conv_module.conv', qconfig)] + } + quantizer = AcademicQuantizer(qconfig_mapping=qconfig_mapping) + assert hasattr(quantizer, 'qconfig_mapping') + assert isinstance(quantizer.qconfig_mapping, QConfigMapping) + assert quantizer.qconfig_mapping.module_name_qconfigs.get( + 'conv_module.conv') + + def test_gen_prepare_custom_config(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + # test prepare_custom_config is None + global_qconfig = copy(self.global_qconfig) + qconfig_mapping = {GLOBAL_DICT_KEY: global_qconfig} + quantizer = AcademicQuantizer(qconfig_mapping=qconfig_mapping) + assert hasattr(quantizer, 'prepare_custom_config') + assert isinstance(quantizer.prepare_custom_config, PrepareCustomConfig) + + # test set FLOAT_TO_OBSERVED_DICT_KEY and PRESERVED_ATTRIBUTES_DICT_KEY + # by PrepareCustomConfig + global_qconfig = copy(self.global_qconfig) + qconfig_mapping = {GLOBAL_DICT_KEY: global_qconfig} + flop_to_observed_list = [('ToyFloatModel', 'ToyObservedModel')] + preserved_attributes_list = ['toy_attr1', 'toy_attr2'] + prepare_custom_config = { + FLOAT_TO_OBSERVED_DICT_KEY: flop_to_observed_list, + PRESERVED_ATTRIBUTES_DICT_KEY: preserved_attributes_list + } + quantizer = AcademicQuantizer( + qconfig_mapping=qconfig_mapping, + prepare_custom_config=prepare_custom_config) + + assert hasattr(quantizer, 'prepare_custom_config') + assert isinstance(quantizer.prepare_custom_config, PrepareCustomConfig) + mapping = quantizer.prepare_custom_config.float_to_observed_mapping[ + QuantType.STATIC] + assert mapping.get(ToyFloatModel) + assert mapping[ToyFloatModel] == ToyObservedModel + + attributes = quantizer.prepare_custom_config.preserved_attributes + assert attributes == preserved_attributes_list + + def test_init(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + global_qconfig = copy(self.global_qconfig) + qconfig_mapping = {GLOBAL_DICT_KEY: global_qconfig} + quantizer = AcademicQuantizer(qconfig_mapping=qconfig_mapping) + assert hasattr(quantizer, 'backend_config') + assert isinstance(quantizer.backend_config, BackendConfig) + + def test_prepare(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + global_qconfig = copy(self.global_qconfig) + qconfig_mapping = {GLOBAL_DICT_KEY: global_qconfig} + preserved_attributes_list = ['toy_attr1', 'toy_attr2'] + prepare_custom_config = { + PRESERVED_ATTRIBUTES_DICT_KEY: preserved_attributes_list + } + quantizer = AcademicQuantizer( + qconfig_mapping=qconfig_mapping, + prepare_custom_config=prepare_custom_config) + model = copy(self.model) + prepared = quantizer.prepare(model) + assert isinstance(prepared, ObservedGraphModule) + assert hasattr(prepared, 'toy_attr1') + assert hasattr(prepared, 'toy_attr2') diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_exporter.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_exporter.py new file mode 100755 index 000000000..04bd8a671 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_exporter.py @@ -0,0 +1,348 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +import shutil +import tempfile +from unittest import TestCase, skipIf + +import torch +import torch.nn as nn + +try: + import onnx + from onnx import helper + from torch.fx import GraphModule +except ImportError: + from mmrazor.utils import get_package_placeholder, get_placeholder + GraphModule = get_placeholder('torch>=1.13') + onnx = get_package_placeholder('No module named onnx') + helper = get_package_placeholder('No module named onnx.helper') + +from mmengine import ConfigDict +from mmengine.model import BaseModel + +try: + import mmdeploy +except ImportError: + from mmrazor.utils import get_package_placeholder + mmdeploy = get_package_placeholder('mmdeploy') + +from mmrazor import digit_version +from mmrazor.models.quantizers.exporters import (OpenVinoQuantizeExportor, + TensorRTExplicitExporter) +from mmrazor.models.quantizers.exporters.optim_utils import ONNXOptimUtils +from mmrazor.registry import MODELS + + +class BasicBlock(nn.Module): + + def __init__(self, in_channels, out_channels): + super(BasicBlock, self).__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.mid_channels = out_channels + + self.norm1 = nn.BatchNorm2d(self.mid_channels) + self.norm2 = nn.BatchNorm2d(out_channels) + self.conv1 = nn.Conv2d(in_channels, self.mid_channels, 1) + self.conv2 = nn.Conv2d(self.mid_channels, out_channels, 1) + + self.relu = nn.ReLU6() + self.drop_path = nn.Identity() + + def forward(self, x): + + def _inner_forward(x): + identity = x + + out = self.conv1(x) + out = self.norm1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.norm2(out) + + out = self.drop_path(out) + + out += identity + + return out + + out = _inner_forward(x) + + out = self.relu(out) + + return out + + +class ToyModel(nn.Module): + + def __init__(self): + super(ToyModel, self).__init__() + self.stem_layer = nn.Sequential( + nn.Conv2d(3, 3, 1), nn.BatchNorm2d(3), nn.ReLU()) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.block = BasicBlock(3, 3) + self.block2 = BasicBlock(3, 3) + self.gap = nn.AdaptiveAvgPool2d((1, 1)) + self.fc = nn.Linear(3, 4) + + def forward(self, x): + x = self.stem_layer(x) + x = self.maxpool(x) + x = self.block(x) + x = self.block2(x) + x = self.gap(x) + x = x.flatten(1) + x = self.fc(x) + return x + + +class ToyQuantModel(BaseModel): + + def __init__(self): + super().__init__() + self.architecture = ToyModel() + + def loss(self, outputs, data_samples): + return dict(loss=outputs.sum() - data_samples.sum()) + + def forward(self, inputs, data_samples, mode: str = 'tensor'): + if isinstance(inputs, list): + inputs = torch.stack(inputs) + outputs = self.architecture(inputs) + + return outputs + + +OpenVINO_GLOBAL_QCONFIG = ConfigDict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict( + qdtype='quint8', bit=8, is_symmetry=True, averaging_constant=0.1), +) + +OpenVINO_ALG_CONFIG = ConfigDict( + type='mmrazor.MMArchitectureQuant', + architecture=dict(type='ToyQuantModel'), + quantizer=dict( + type='mmrazor.OpenVINOQuantizer', + global_qconfig=OpenVINO_GLOBAL_QCONFIG, + tracer=dict(type='mmrazor.CustomTracer'))) + +TensorRT_GLOBAL_QCONFIG = ConfigDict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict(qdtype='qint8', bit=8, is_symmetry=True), + a_qscheme=dict(qdtype='quint8', bit=8, is_symmetry=True), +) + +TensorRT_ALG_CONFIG = ConfigDict( + type='mmrazor.MMArchitectureQuant', + architecture=dict(type='ToyQuantModel'), + quantizer=dict( + type='mmrazor.TensorRTQuantizer', + global_qconfig=OpenVINO_GLOBAL_QCONFIG, + tracer=dict(type='mmrazor.CustomTracer'))) + + +@skipIf( + digit_version(torch.__version__) < digit_version('1.13.0'), + 'PyTorch version lower than 1.13.0 is not supported.') +class TestONNXOptimUtils(TestCase): + + def setUp(self): + MODELS.register_module(module=ToyQuantModel, force=True) + self.temp_dir = tempfile.mkdtemp() + filename = 'symbolic.onnx' + filename = os.path.join(self.temp_dir, filename) + toy_model = MODELS.build(OpenVINO_ALG_CONFIG) + observed_model = toy_model.get_deploy_model() + torch.onnx.export( + observed_model, + torch.rand(2, 3, 16, 16), + filename, + opset_version=11) + self.onnx_model = onnx.load(filename) + self.optimizer = ONNXOptimUtils + + def tearDown(self): + MODELS.module_dict.pop('ToyQuantModel') + shutil.rmtree(self.temp_dir) + + def test_map_name_and_data(self): + params = self.optimizer.map_name_and_data(self.onnx_model) + params_keys = [ + 'activation_post_process_0.scale', + 'activation_post_process_0.zero_point', + 'architecture.stem_layer.0.weight', + 'architecture.stem_layer.0.bias', + 'architecture.stem_layer.0.weight_fake_quant.scale', + 'architecture.stem_layer.0.weight_fake_quant.zero_point', + 'architecture.block.conv1.weight', 'architecture.block.conv1.bias', + 'architecture.block.conv1.weight_fake_quant.scale', + 'architecture.block.conv2.bias', + 'architecture.block2.conv1.weight', + 'architecture.block2.conv1.bias', + 'architecture.block2.conv1.weight_fake_quant.scale', + 'architecture.block2.conv2.weight', + 'architecture.block2.conv2.bias', + 'architecture.block2.conv2.weight_fake_quant.scale', + 'architecture.fc.weight', 'architecture.fc.bias', + 'architecture.fc.weight_fake_quant.scale', + 'architecture.fc.weight_fake_quant.zero_point', + 'activation_post_process_15.zero_point', + 'activation_post_process_15.scale', + 'activation_post_process_14.zero_point', + 'activation_post_process_14.scale', + 'activation_post_process_12.zero_point', + 'activation_post_process_12.scale', + 'activation_post_process_10.zero_point', + 'activation_post_process_10.scale', + 'activation_post_process_8.zero_point', + 'activation_post_process_8.scale', + 'activation_post_process_6.zero_point', + 'activation_post_process_6.scale', + 'activation_post_process_4.zero_point', + 'activation_post_process_4.scale', + 'activation_post_process_1.zero_point', + 'activation_post_process_1.scale', + 'architecture.block2.conv2.weight_fake_quant.zero_point', + 'architecture.block2.conv1.weight_fake_quant.zero_point', + 'architecture.block.conv2.weight_fake_quant.zero_point', + 'architecture.block.conv2.weight_fake_quant.scale', + 'architecture.block.conv2.weight', + 'architecture.block.conv1.weight_fake_quant.zero_point', + '/activation_post_process_0/Constant_output_0', + '/activation_post_process_0/Constant_1_output_0', + '/stem_layer.0/weight_fake_quant/Constant_output_0', + '/stem_layer.0/weight_fake_quant/Constant_1_output_0', + '/relu/Constant_output_0', '/relu/Constant_1_output_0', + '/relu_dup1/Constant_output_0', '/relu_dup1/Constant_1_output_0', + '/relu_1/Constant_output_0', '/relu_1/Constant_1_output_0', + '/relu_dup1_1/Constant_output_0', + '/relu_dup1_1/Constant_1_output_0' + ] + self.assertEqual(set(params.keys()), set(params_keys)) + + def test_map_name_and_initializer(self): + initializers = self.optimizer.map_name_and_initializer(self.onnx_model) + for init in self.onnx_model.graph.initializer: + self.assertIn(init.name, initializers.keys()) + # self.assertEqual(set(initializers.keys()), set(initializers_keys)) + + def test_map_output_and_node(self): + _ = self.optimizer.map_output_and_node(self.onnx_model) + + def test_map_input_and_node(self): + _ = self.optimizer.map_input_and_node(self.onnx_model) + + def test_remove_node_from_onnx(self): + onnx_model = copy.deepcopy(self.onnx_model) + node_to_remove = next(iter(onnx_model.graph.node)) + self.optimizer.remove_node_from_onnx(node_to_remove, onnx_model) + for node in onnx_model.graph.node: + self.assertNotEqual(node, node_to_remove) + + def test_remove_initializer_from_onnx(self): + onnx_model = copy.deepcopy(self.onnx_model) + initializer_to_remove = next(iter(onnx_model.graph.initializer)) + self.optimizer.remove_initializer_from_onnx(initializer_to_remove, + onnx_model) + for initializer in onnx_model.graph.initializer: + self.assertNotEqual(initializer, initializer_to_remove) + + def test_find_standalone_nodes(self): + standalone_nodes = self.optimizer.find_standalone_nodes( + self.onnx_model) + self.assertEqual(standalone_nodes, []) + + def test_find_redundant_initializers(self): + redundant_initializers = self.optimizer.find_redundant_initializers( + self.onnx_model) + self.assertEqual(redundant_initializers, []) + + def test_topo_sort(self): + onnx_model = copy.deepcopy(self.onnx_model) + onnx_model_topo_sort = self.optimizer.topo_sort(onnx_model) + self.assertEqual( + len(onnx_model_topo_sort.graph.node), + len(self.onnx_model.graph.node)) + + def test_optimize(self): + onnx_model = copy.deepcopy(self.onnx_model) + fake_node = helper.make_node('fake_node', [], [], mode='constant') + self.optimizer.insert_node_to_onnx(fake_node, onnx_model) + self.optimizer.optimize(onnx_model) + for node in onnx_model.graph.node: + self.assertNotEqual(node, fake_node) + + +@skipIf( + digit_version(torch.__version__) < digit_version('1.13.0'), + 'PyTorch version lower than 1.13.0 is not supported.') +class TestOpenVinoQuantizeExportor(TestCase): + + def setUp(self): + MODELS.register_module(module=ToyQuantModel, force=True) + self.temp_dir = tempfile.mkdtemp() + filename = 'toy_model_symbolic.onnx' + filename = os.path.join(self.temp_dir, filename) + toy_model = MODELS.build(OpenVINO_ALG_CONFIG) + observed_model = toy_model.get_deploy_model() + torch.onnx.export( + observed_model, + torch.rand(2, 3, 16, 16), + filename, + opset_version=11) + self.onnx_model = onnx.load(filename) + self.export_path = os.path.join(self.temp_dir, 'toy_model.onnx') + + def tearDown(self): + MODELS.module_dict.pop('ToyQuantModel') + shutil.rmtree(self.temp_dir) + + def test_export(self): + exporter = OpenVinoQuantizeExportor(self.onnx_model, self.export_path) + exporter.export() + self.assertTrue(os.path.exists(self.export_path)) + onnx_model = onnx.load(self.export_path) + self.assertIsInstance(onnx_model, onnx.ModelProto) + + +@skipIf( + digit_version(torch.__version__) < digit_version('1.13.0'), + 'PyTorch version lower than 1.13.0 is not supported.') +class TestTensorRTExplicitExporter(TestCase): + + def setUp(self): + MODELS.register_module(module=ToyQuantModel, force=True) + self.temp_dir = tempfile.mkdtemp() + filename = 'toy_model_symbolic.onnx' + filename = os.path.join(self.temp_dir, filename) + toy_model = MODELS.build(TensorRT_ALG_CONFIG) + observed_model = toy_model.get_deploy_model() + torch.onnx.export( + observed_model, + torch.rand(2, 3, 16, 16), + filename, + opset_version=11) + self.onnx_model = onnx.load(filename) + self.export_path = os.path.join(self.temp_dir, 'toy_model.onnx') + + def tearDown(self): + MODELS.module_dict.pop('ToyQuantModel') + shutil.rmtree(self.temp_dir) + + def test_export(self): + exporter = TensorRTExplicitExporter(self.onnx_model, self.export_path) + exporter.export() + self.assertTrue(os.path.exists(self.export_path)) + onnx_model = onnx.load(self.export_path) + self.assertIsInstance(onnx_model, onnx.ModelProto) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_native_quantizer.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_native_quantizer.py new file mode 100755 index 000000000..8f982c139 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_native_quantizer.py @@ -0,0 +1,224 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import torch +import torch.nn as nn + +from mmrazor import digit_version +from mmrazor.models.quantizers import TorchNativeQuantizer +from mmrazor.models.quantizers.native_quantizer import SUPPORT_QAT_MODULES +from mmrazor.models.task_modules.tracer import CustomTracer +from mmrazor.models.task_modules.tracer.fx.custom_tracer import \ + build_graphmodule +from mmrazor.registry import MODELS +from mmrazor.structures.quantization import BackendConfigs, QConfigHandler + +try: + from torch.ao.quantization.fx import prepare + from torch.ao.quantization.fx.graph_module import ObservedGraphModule + from torch.ao.quantization.qconfig_mapping import QConfigMapping + from torch.ao.quantization.quantize_fx import _fuse_fx + from torch.fx import GraphModule +except ImportError: + from mmrazor.utils import get_placeholder + GraphModule = get_placeholder('torch>=1.13') + ObservedGraphModule = get_placeholder('torch>=1.13') + QConfigMapping = get_placeholder('torch>=1.13') + prepare = get_placeholder('torch>=1.13') + _fuse_fx = get_placeholder('torch>=1.13') + + +class BasicBlock(nn.Module): + + def __init__(self, in_channels, out_channels): + super(BasicBlock, self).__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.mid_channels = out_channels + + self.norm1 = nn.BatchNorm2d(self.mid_channels) + self.norm2 = nn.BatchNorm2d(out_channels) + self.conv1 = nn.Conv2d(in_channels, self.mid_channels, 1) + self.conv2 = nn.Conv2d(self.mid_channels, out_channels, 1) + + self.relu = nn.ReLU6() + self.drop_path = nn.Identity() + + def forward(self, x): + + def _inner_forward(x): + identity = x + + out = self.conv1(x) + out = self.norm1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.norm2(out) + + out = self.drop_path(out) + + out += identity + + return out + + out = _inner_forward(x) + + out = self.relu(out) + + return out + + +class ToyQuantModel(nn.Module): + + def __init__(self): + super().__init__() + self.stem_layer = nn.Sequential( + nn.Conv2d(3, 3, 1), nn.BatchNorm2d(3), nn.ReLU()) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.block = BasicBlock(3, 3) + self.block2 = BasicBlock(3, 3) + self.gap = nn.AdaptiveAvgPool2d((1, 1)) + self.fc = nn.Linear(3, 4) + + def forward(self, x): + x = self.stem_layer(x) + x = self.maxpool(x) + x = self.block(x) + x = self.block2(x) + x = self.gap(x) + x = x.flatten(1) + x = self.fc(x) + return x + + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict( + qdtype='quint8', bit=8, is_symmetry=True, averaging_constant=0.1)) + +no_observer_modules = [ + 'torch.nn.Conv2d', +] + +q_kwargs = dict( + type='mmrazor.TorchNativeQuantizer', + global_qconfig=global_qconfig, + no_observer_modules=no_observer_modules, + tracer=dict(type='CustomTracer'), +) + + +class TestTorchNativeQuantizer(TestCase): + """TODO. + + Args: + TestCase (_type_): _description_ + """ + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + self.q_kwargs = q_kwargs + self.tracer = CustomTracer() + self.backend_config = BackendConfigs['native'] + self.qconfig = QConfigHandler(global_qconfig) + self.qconfig_mapping = QConfigMapping().set_global( + self.qconfig.convert()) + self.example_inputs = (torch.randn(1, 3, 224, 224), ) + self.native_quantizer = MODELS.build(self.q_kwargs) + + def tearDown(self): + pass + + def swap_ff_with_fxff(self, model): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + modules_to_swap = [] + for name, module in model.named_children(): + if isinstance(module, torch.ao.nn.quantized.FloatFunctional): + modules_to_swap.append(name) + else: + self.swap_ff_with_fxff(module) + + for name in modules_to_swap: + del model._modules[name] + model._modules[name] = torch.ao.nn.quantized.FXFloatFunctional() + + def test_init(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + native_quantizer = MODELS.build(self.q_kwargs) + self.assertIsInstance(native_quantizer, TorchNativeQuantizer) + + def test_prepare(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + toy_model = ToyQuantModel() + toy_model.eval() + + self.swap_ff_with_fxff(toy_model) + traced_graph = self.tracer.trace(toy_model) + graph_module = build_graphmodule(toy_model, traced_graph) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + backend_config=self.backend_config) + assert isinstance(graph_module, GraphModule) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + backend_config=self.backend_config) + assert isinstance(prepared, ObservedGraphModule) + + prepared = self.native_quantizer.del_redundant_fakequant(prepared) + assert isinstance(prepared, GraphModule) + + def post_process_for_deploy(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + toy_model = ToyQuantModel() + toy_model.eval() + + self.swap_ff_with_fxff(toy_model) + traced_graph = self.tracer.trace(toy_model) + graph_module = build_graphmodule(toy_model, traced_graph) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + backend_config=self.backend_config) + assert isinstance(graph_module, GraphModule) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + backend_config=self.backend_config) + assert isinstance(prepared, ObservedGraphModule) + + prepared = self.native_quantizer.del_redundant_fakequant(prepared) + assert isinstance(prepared, GraphModule) + + prepared_no_fq = prepared + + self.native_quantizer.post_process_weight_fakequant(prepared) + for name, child in prepared.named_children(): + if isinstance(child, SUPPORT_QAT_MODULES): + raise ValueError + self.native_quantizer.post_process_weight_fakequant( + prepared_no_fq, True) + for name, child in prepared_no_fq.named_children(): + if isinstance(child, SUPPORT_QAT_MODULES): + raise ValueError diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_openvino_quantizer.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_openvino_quantizer.py new file mode 100755 index 000000000..7b60dc4a3 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_openvino_quantizer.py @@ -0,0 +1,55 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import shutil +import tempfile +from copy import copy +from unittest import TestCase + +import torch + +try: + from torch.ao.quantization.fx.graph_module import ObservedGraphModule +except ImportError: + from mmrazor.utils import get_placeholder + ObservedGraphModule = get_placeholder('torch>=1.13') + +from mmrazor import digit_version +from mmrazor.models.quantizers import OpenVINOQuantizer +from mmrazor.testing import ConvBNReLU + + +class TestOpenVINOQuantizer(TestCase): + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + self.global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict(qdtype='qint8', bit=8, is_symmetry=True), + a_qscheme=dict(qdtype='quint8', bit=8, is_symmetry=True), + ) + self.temp_dir = tempfile.mkdtemp() + self.model = ConvBNReLU(3, 3, norm_cfg=dict(type='BN')) + + def tearDown(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + shutil.rmtree(self.temp_dir) + + def test_property(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + global_qconfig = copy(self.global_qconfig) + quantizer = OpenVINOQuantizer(global_qconfig=global_qconfig) + assert quantizer.backend == 'openvino' + assert quantizer.support_w_modes == ('per_tensor', 'per_channel') + assert quantizer.support_a_modes == ('per_tensor') + assert quantizer.module_prev_wo_fakequant + assert quantizer.module_next_wo_fakequant + assert quantizer.method_next_wo_fakequant + assert quantizer.op_prev_wo_fakequant diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_tensorrt_quantizer.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_tensorrt_quantizer.py new file mode 100755 index 000000000..f5433a0f9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_quantizers/test_tensorrt_quantizer.py @@ -0,0 +1,51 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import shutil +import tempfile +from copy import copy +from unittest import TestCase + +import torch + +try: + from torch.ao.quantization.fx.graph_module import ObservedGraphModule +except ImportError: + from mmrazor.utils import get_placeholder + ObservedGraphModule = get_placeholder('torch>=1.13') + +from mmrazor import digit_version +from mmrazor.models.quantizers import TensorRTQuantizer +from mmrazor.testing import ConvBNReLU + + +class TestTensorRTQuantizer(TestCase): + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + self.global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict(qdtype='qint8', bit=8, is_symmetry=True), + a_qscheme=dict(qdtype='quint8', bit=8, is_symmetry=True), + ) + self.temp_dir = tempfile.mkdtemp() + self.model = ConvBNReLU(3, 3, norm_cfg=dict(type='BN')) + + def tearDown(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + shutil.rmtree(self.temp_dir) + + def test_property(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + global_qconfig = copy(self.global_qconfig) + quantizer = TensorRTQuantizer(global_qconfig=global_qconfig) + assert quantizer.backend == 'tensorrt' + assert quantizer.support_w_modes == ('per_tensor', 'per_channel') + assert quantizer.support_a_modes == ('per_tensor') diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_candidate.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_candidate.py new file mode 100755 index 000000000..7f8bfe640 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_candidate.py @@ -0,0 +1,152 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +from collections import UserList +from unittest import TestCase + +from mmrazor.structures import Candidates + + +class TestCandidates(TestCase): + + def setUp(self) -> None: + self.fake_subnet = {'1': 'choice1', '2': 'choice2'} + self.fake_subnet_with_resource = { + str(self.fake_subnet): { + 'score': 0., + 'flops': 50., + 'params': 0., + 'latency': 0. + } + } + self.fake_subnet_with_score = { + str(self.fake_subnet): { + 'score': 99., + 'flops': 0., + 'params': 0., + 'latency': 0. + } + } + self.has_flops_network = { + str(self.fake_subnet): { + 'flops': 50., + } + } + + def test_init(self): + # initlist is None + candidates = Candidates() + self.assertEqual(len(candidates.data), 0) + # initlist is list + data = [self.fake_subnet] * 2 + candidates = Candidates(data) + self.assertEqual(len(candidates.data), 2) + # initlist is UserList + data = UserList([self.fake_subnet] * 2) + self.assertEqual(len(candidates.data), 2) + self.assertEqual(candidates.resources('flops'), [-1, -1]) + # initlist is list(Dict[str, Dict]) + candidates = Candidates([self.has_flops_network] * 2) + self.assertEqual(candidates.resources('flops'), [50., 50.]) + + def test_scores(self): + # test property: scores + data = [self.fake_subnet_with_score] * 2 + candidates = Candidates(data) + self.assertEqual(candidates.scores, [99., 99.]) + + def test_resources(self): + data = [self.fake_subnet_with_resource] * 2 + candidates = Candidates(data) + self.assertEqual(candidates.resources('flops'), [50., 50.]) + + def test_subnets(self): + # test property: subnets + data = [self.fake_subnet] * 2 + candidates = Candidates(data) + self.assertEqual(candidates.subnets, [self.fake_subnet] * 2) + + def test_append(self): + # item is dict + candidates = Candidates() + candidates.append(self.fake_subnet) + self.assertEqual(len(candidates), 1) + # item is List + candidates = Candidates() + candidates.append([self.fake_subnet_with_score]) + # item is Candidates + candidates_2 = Candidates([self.fake_subnet_with_resource]) + candidates.append(candidates_2) + self.assertEqual(len(candidates), 2) + + def test_insert(self): + # item is dict + candidates = Candidates(self.fake_subnet_with_score) + candidates.insert(1, self.fake_subnet) + self.assertEqual(len(candidates), 2) + # item is List + candidates = Candidates([self.fake_subnet_with_score]) + candidates.insert(1, self.fake_subnet_with_score) + self.assertEqual(len(candidates), 2) + + def test_extend(self): + # other is list + candidates = Candidates([self.fake_subnet_with_score]) + candidates.extend([self.fake_subnet]) + self.assertEqual(len(candidates), 2) + # other is Candidates + candidates = Candidates([self.fake_subnet_with_score]) + candidates_2 = Candidates([self.fake_subnet_with_resource]) + candidates.extend(candidates_2) + self.assertEqual(len(candidates), 2) + + def test_set_resource(self): + # test set_resource + candidates = Candidates([self.fake_subnet]) + for kk in ['flops', 'params', 'latency']: + self.assertEqual(candidates.resources(kk)[0], -1) + candidates.set_resource(0, 49.9, kk) + self.assertEqual(candidates.resources(kk)[0], 49.9) + candidates.insert(0, self.fake_subnet_with_resource) + self.assertEqual(len(candidates), 2) + self.assertEqual(candidates.resources('flops'), [50., 49.9]) + self.assertEqual(candidates.resources('latency'), [0., 49.9]) + candidates = Candidates([self.fake_subnet_with_score]) + candidates.set_resource(0, 100.0, 'score') + self.assertEqual(candidates.scores[0], 100.) + candidates = Candidates([self.fake_subnet_with_score]) + candidates.set_resource(0, 100.0, 'score') + candidates.extend(UserList([self.fake_subnet_with_resource])) + candidates.set_resource(1, 99.9, 'score') + self.assertEqual(candidates.scores, [100., 99.9]) + + def test_update_resources(self): + # test update_resources + candidates = Candidates([self.fake_subnet]) + candidates.append([self.fake_subnet_with_score]) + candidates_2 = Candidates(self.fake_subnet_with_resource) + candidates.append(candidates_2) + self.assertEqual(len(candidates), 3) + self.assertEqual(candidates.resources('flops'), [-1, 0., 50.]) + self.assertEqual(candidates.resources('latency'), [-1, 0., 0.]) + resources = [{'flops': -2}, {'latency': 4.}] + candidates.update_resources(resources, start=1) + self.assertEqual(candidates.resources('flops'), [-1, -2, 50.]) + self.assertEqual(candidates.resources('latency'), [-1, 0., 4]) + candidates.update_resources(resources, start=0) + self.assertEqual(candidates.resources('flops'), [-2, -2, 50.]) + self.assertEqual(candidates.resources('latency'), [-1, 4., 4.]) + + def test_sort(self): + # test set_sort + candidates = Candidates([self.fake_subnet_with_score]) + candidates.extend(UserList([self.fake_subnet_with_resource])) + candidates.insert(0, self.fake_subnet) + candidates.set_resource(0, 100., 'score') + candidates.set_resource(2, 98., 'score') + self.assertEqual(candidates.scores, [100., 99., 98.]) + candidates.sort_by(key_indicator='score', reverse=False) + self.assertEqual(candidates.scores, [98., 99., 100.]) + candidates.sort_by(key_indicator='latency') + self.assertEqual(candidates.scores, [98., 99., 100.]) + candidates.sort_by(key_indicator='flops', reverse=False) + self.assertEqual(candidates.scores, [100., 99., 98.]) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_fix_subnet.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_fix_subnet.py new file mode 100755 index 000000000..60fb39f8d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_subnet/test_fix_subnet.py @@ -0,0 +1,150 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch.nn as nn + +from mmrazor.models import * # noqa:F403,F401 +from mmrazor.models.architectures.dynamic_ops import BigNasConv2d +from mmrazor.models.mutables import OneShotMutableOP, OneShotMutableValue +from mmrazor.registry import MODELS +from mmrazor.structures import export_fix_subnet, load_fix_subnet +from mmrazor.utils import FixMutable + +MODELS.register_module() + + +class MockModel(nn.Module): + + def __init__(self): + super().__init__() + convs1 = nn.ModuleDict({ + 'conv1': nn.Conv2d(3, 8, 1), + 'conv2': nn.Conv2d(3, 8, 1), + 'conv3': nn.Conv2d(3, 8, 1), + }) + convs2 = nn.ModuleDict({ + 'conv1': nn.Conv2d(8, 16, 1), + 'conv2': nn.Conv2d(8, 16, 1), + 'conv3': nn.Conv2d(8, 16, 1), + }) + + self.mutable1 = OneShotMutableOP(convs1) + self.mutable2 = OneShotMutableOP(convs2) + self.mutable3 = nn.Sequential(BigNasConv2d(16, 16, 5)) + + mutable_kernel_size = OneShotMutableValue( + alias='mutable3.0.kernel_size', value_list=[3, 5]) + self.mutable3[0].register_mutable_attr('kernel_size', + mutable_kernel_size) + + def forward(self, x): + x = self.mutable1(x) + x = self.mutable2(x) + x = self.mutable3(x) + return x + + +class MockModelWithDerivedMutable(nn.Module): + + def __init__(self) -> None: + super().__init__() + + self.source_mutable = OneShotMutableValue([2, 3, 4], default_value=3) + self.derived_mutable = self.source_mutable * 2 + + +class TestFixSubnet(TestCase): + + def test_load_fix_subnet(self): + # fix subnet is str + fix_subnet = 'tests/data/test_models/test_subnet/mockmodel_subnet.yaml' # noqa: E501 + model = MockModel() + + load_fix_subnet(model, fix_subnet) + + # fix subnet is dict + fix_subnet = { + 'mutable1': { + 'chosen': 'conv1' + }, + 'mutable2': { + 'chosen': 'conv2' + }, + 'mutable3.0.kernel_size': { + 'chosen': 3 + } + } + + model = MockModel() + load_fix_subnet(model, fix_subnet) + + model = MockModel() + load_fix_subnet(model, fix_subnet) + + with pytest.raises(TypeError): + # type int is not supported. + model = MockModel() + load_fix_subnet(model, fix_subnet=10) + + model = MockModel() + fix_subnet.pop('mutable1') + with pytest.raises(RuntimeError): + load_fix_subnet(model, fix_subnet) + + def test_export_fix_subnet(self): + # get FixSubnet + fix_subnet = { + 'mutable1': { + 'chosen': 'conv1' + }, + 'mutable2': { + 'chosen': 'conv2' + }, + 'mutable3.0.kernel_size': { + 'chosen': 3 + } + } + + model = MockModel() + load_fix_subnet(model, fix_subnet) + + with pytest.raises(AssertionError): + exported_fix_subnet: FixMutable = export_fix_subnet(model)[0] + + model = MockModel() + model.mutable1.current_choice = 'conv1' + model.mutable2.current_choice = 'conv2' + model.mutable3[0].mutable_attrs.kernel_size.current_choice = 3 + exported_fix_subnet = export_fix_subnet(model)[0] + + mutable1_dump_chosen = exported_fix_subnet['mutable1'] + mutable2_dump_chosen = exported_fix_subnet['mutable2'] + mutable3_0_ks_chosen = exported_fix_subnet['mutable3.0.kernel_size'] + + mutable1_chosen_dict = dict(chosen=mutable1_dump_chosen.chosen) + mutable2_chosen_dict = dict(chosen=mutable2_dump_chosen.chosen) + mutable3_0_ks_chosen_dict = dict(chosen=mutable3_0_ks_chosen.chosen) + + exported_fix_subnet['mutable1'] = mutable1_chosen_dict + exported_fix_subnet['mutable2'] = mutable2_chosen_dict + exported_fix_subnet['mutable3.0.kernel_size'] = \ + mutable3_0_ks_chosen_dict + self.assertDictEqual(fix_subnet, exported_fix_subnet) + + def test_export_fix_subnet_with_derived_mutable(self) -> None: + model = MockModelWithDerivedMutable() + fix_subnet = export_fix_subnet(model)[0] + self.assertDictEqual( + fix_subnet, { + 'source_mutable': model.source_mutable.dump_chosen(), + 'derived_mutable': model.source_mutable.dump_chosen() + }) + + fix_subnet['source_mutable'] = dict( + fix_subnet['source_mutable']._asdict()) + fix_subnet['source_mutable']['chosen'] = 4 + load_fix_subnet(model, fix_subnet) + + assert model.source_mutable.current_choice == 4 + assert model.derived_mutable.current_choice == 8 diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_custom_tracer.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_custom_tracer.py new file mode 100755 index 000000000..2d01ea496 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_custom_tracer.py @@ -0,0 +1,184 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import pytest +import torch +from mmcls.models.backbones.resnet import ResLayer +from mmengine.config import Config +from mmengine.registry import MODELS + +try: + from torch.fx import GraphModule + from torch.fx._symbolic_trace import Graph +except ImportError: + from mmrazor.utils import get_placeholder + GraphModule = get_placeholder('torch>=1.13') + Graph = get_placeholder('torch>=1.13') + +from mmrazor import digit_version +from mmrazor.models.task_modules.tracer import (CustomTracer, + UntracedMethodRegistry, + build_graphmodule, + custom_symbolic_trace) +from mmrazor.models.task_modules.tracer.fx.custom_tracer import \ + _prepare_module_dict + + +class ToyModel(torch.nn.Module): + + def __init__(self): + super().__init__() + + def get_loss(self, x): + return x * 0.1 + + def extrac_feature(self, x): + return x * 2 + + def forward(self, x): + x = self.extrac_feature(x) + x = self.get_loss(x) + return x + + +class testUntracedMethodRgistry(TestCase): + + def test_init(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + method = ToyModel.get_loss + method_registry = UntracedMethodRegistry(method) + assert hasattr(method_registry, 'method') + assert hasattr(method_registry, 'method_dict') + + def test_registry_method(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + model = ToyModel + method = ToyModel.get_loss + method_registry = UntracedMethodRegistry(method) + method_registry.__set_name__(model, 'get_loss') + assert 'get_loss' in method_registry.method_dict.keys() + assert method_registry.method_dict['get_loss']['mod'] == model + + +class testCustomTracer(TestCase): + + def setUp(self): + self.cfg = Config.fromfile( + 'tests/data/test_models/test_task_modules/mmcls_cfg.py') + self.skipped_methods = [ + 'mmcls.models.heads.ClsHead._get_loss', + 'mmcls.models.heads.ClsHead._get_predictions' + ] + self.skipped_module_names = ['backbone.layer4.0'] + self.skipped_module_classes = [ResLayer] + + def test_init(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + # init without skipped_methods + tracer = CustomTracer() + assert hasattr(tracer, 'skipped_methods') + assert len(tracer.skipped_methods) == 0 + # init with skipped_methods(list) + UntracedMethodRegistry.method_dict = dict() + tracer = CustomTracer(skipped_methods=self.skipped_methods) + assert '_get_loss' in UntracedMethodRegistry.method_dict.keys() + assert '_get_predictions' in UntracedMethodRegistry.method_dict.keys() + # init with skipped_methods(str) + UntracedMethodRegistry.method_dict = dict() + tracer = CustomTracer(skipped_methods=self.skipped_methods[0]) + assert '_get_loss' in UntracedMethodRegistry.method_dict.keys() + # init with skipped_methods(int, error) + with self.assertRaises(TypeError): + CustomTracer(skipped_methods=123) + # init with skipped_methods(str, error) + with self.assertRaises(AssertionError): + CustomTracer(skipped_methods='_get_loss') + + def test_trace(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + # test trace with skipped_methods + model = MODELS.build(self.cfg.model) + UntracedMethodRegistry.method_dict = dict() + tracer = CustomTracer(skipped_methods=self.skipped_methods) + graph_tensor = tracer.trace(model, concrete_args={'mode': 'tensor'}) + graph_loss = tracer.trace(model, concrete_args={'mode': 'loss'}) + graph_predict = tracer.trace(model, concrete_args={'mode': 'predict'}) + assert isinstance(graph_tensor, Graph) + assert isinstance(graph_loss, Graph) + skip_flag_loss = False + for node in graph_loss.nodes: + if node.op == 'call_method' and node.target == '_get_loss': + skip_flag_loss = True + assert isinstance(graph_predict, Graph) + skip_flag_predict = False + for node in graph_predict.nodes: + if node.op == 'call_method' and node.target == '_get_predictions': + skip_flag_predict = True + assert skip_flag_loss and skip_flag_predict + + # test trace with skipped_module_names + model = MODELS.build(self.cfg.model) + UntracedMethodRegistry.method_dict = dict() + tracer = CustomTracer(skipped_module_names=self.skipped_module_names) + graph_tensor = tracer.trace(model, concrete_args={'mode': 'tensor'}) + skip_flag = False + for node in graph_tensor.nodes: + skipped_module_name = self.skipped_module_names[0] + if node.op == 'call_module' and node.target == skipped_module_name: + skip_flag = True + assert skip_flag + + # test trace with skipped_module_classes + model = MODELS.build(self.cfg.model) + UntracedMethodRegistry.method_dict = dict() + tracer = CustomTracer( + skipped_module_classes=self.skipped_module_classes) + graph_tensor = tracer.trace(model, concrete_args={'mode': 'tensor'}) + skip_flag = False + for node in graph_tensor.nodes: + if node.op == 'call_module' and node.target == 'backbone.layer1': + skip_flag = True + assert skip_flag + + +@pytest.mark.skipif( + digit_version(torch.__version__) < digit_version('1.13.0'), + reason='version of torch < 1.13.0') +def test_custom_symbolic_trace(): + cfg = Config.fromfile( + 'tests/data/test_models/test_task_modules/mmcls_cfg.py') + model = MODELS.build(cfg.model) + UntracedMethodRegistry.method_dict = dict() + graph_module = custom_symbolic_trace( + model, concrete_args={'mode': 'tensor'}) + assert isinstance(graph_module, GraphModule) + + +@pytest.mark.skipif( + digit_version(torch.__version__) < digit_version('1.13.0'), + reason='version of torch < 1.13.0') +def test_build_graphmodule(): + skipped_methods = ['mmcls.models.heads.ClsHead._get_predictions'] + cfg = Config.fromfile( + 'tests/data/test_models/test_task_modules/mmcls_cfg.py') + model = MODELS.build(cfg.model) + UntracedMethodRegistry.method_dict = dict() + tracer = CustomTracer(skipped_methods=skipped_methods) + graph_predict = tracer.trace(model, concrete_args={'mode': 'predict'}) + graph_module = build_graphmodule(model, graph_predict) + assert isinstance(graph_module, GraphModule) + + # test _prepare_module_dict + modules = dict(model.named_modules()) + module_dict = _prepare_module_dict(model, graph_predict) + for k, v in module_dict.items(): + assert isinstance(v, torch.nn.Module) + assert not isinstance(v, modules[k].__class__) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/test_demo_inputs.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/test_demo_inputs.py new file mode 100755 index 000000000..e88352f08 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_demo_inputs/test_demo_inputs.py @@ -0,0 +1,24 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest + +from mmrazor.models.task_modules.demo_inputs import DefaultDemoInput +from ....data.tracer_passed_models import FxPassedModelManager + + +class TestDemoInputs(unittest.TestCase): + + def test_demo_inputs(self): + for Model in FxPassedModelManager().include_models(): + with self.subTest(model=Model): + demo_input = DefaultDemoInput(input_shape=[1, 3, 224, 224]) + model = Model() + model.eval() + try: + demo_input(model) + input = demo_input.get_data(model) + if isinstance(input, dict): + model(**input) + else: + model(input) + except Exception as e: + self.fail(f'{e}') diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_estimators/test_flops_params.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_estimators/test_flops_params.py new file mode 100755 index 000000000..82fa9d188 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_estimators/test_flops_params.py @@ -0,0 +1,236 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from unittest import TestCase + +import pytest +import torch +from mmcv.cnn.bricks import Conv2dAdaptivePadding +from torch import Tensor +from torch.nn import Conv2d, Module, Parameter + +from mmrazor.models import OneShotMutableModule, ResourceEstimator +from mmrazor.models.task_modules.estimators.counters import BaseCounter +from mmrazor.registry import MODELS, TASK_UTILS +from mmrazor.structures import export_fix_subnet + +_FIRST_STAGE_MUTABLE = dict( + type='OneShotMutableOP', + candidates=dict( + mb_k3e1=dict( + type='MBBlock', + kernel_size=3, + expand_ratio=1, + norm_cfg=dict(type='BN'), + act_cfg=dict(type='ReLU6')))) + +_OTHER_STAGE_MUTABLE = dict( + type='OneShotMutableOP', + candidates=dict( + mb_k3e3=dict( + type='MBBlock', + kernel_size=3, + expand_ratio=3, + norm_cfg=dict(type='BN'), + act_cfg=dict(type='ReLU6')), + mb_k5e3=dict( + type='MBBlock', + kernel_size=5, + expand_ratio=3, + norm_cfg=dict(type='BN'), + act_cfg=dict(type='ReLU6')), + identity=dict(type='Identity'))) + +ARCHSETTING_CFG = [ + # Parameters to build layers. 4 parameters are needed to construct a + # layer, from left to right: channel, num_blocks, stride, mutable cfg. + [16, 1, 1, _FIRST_STAGE_MUTABLE], + [24, 2, 2, _OTHER_STAGE_MUTABLE], + [32, 3, 2, _OTHER_STAGE_MUTABLE], + [64, 4, 2, _OTHER_STAGE_MUTABLE], + [96, 3, 1, _OTHER_STAGE_MUTABLE], + [160, 3, 2, _OTHER_STAGE_MUTABLE], + [320, 1, 1, _OTHER_STAGE_MUTABLE] +] + +NORM_CFG = dict(type='BN') +BACKBONE_CFG = dict( + type='mmrazor.SearchableMobileNetV2', + first_channels=32, + last_channels=1280, + widen_factor=1.0, + norm_cfg=NORM_CFG, + arch_setting=ARCHSETTING_CFG) + +estimator = ResourceEstimator() + + +class FoolAddConstant(Module): + + def __init__(self, p: float = 0.1) -> None: + super().__init__() + + self.register_parameter( + name='p', param=Parameter(torch.tensor(p, dtype=torch.float32))) + + def forward(self, x: Tensor) -> Tensor: + return x + self.p + + +@TASK_UTILS.register_module() +class FoolAddConstantCounter(BaseCounter): + + @staticmethod + def add_count_hook(module, input, output): + module.__flops__ += 1000000 + module.__params__ += 700000 + + +class FoolConv2d(Module): + + def __init__(self) -> None: + super().__init__() + + self.conv2d = Conv2d(3, 32, 3) + + def forward(self, x: Tensor) -> Tensor: + return self.conv2d(x) + + +class FoolConvModule(Module): + + def __init__(self) -> None: + super().__init__() + + self.add_constant = FoolAddConstant(0.1) + self.conv2d = FoolConv2d() + + def forward(self, x: Tensor) -> Tensor: + x = self.add_constant(x) + + return self.conv2d(x) + + +class TestResourceEstimator(TestCase): + + def sample_choice(self, model: Module) -> None: + for module in model.modules(): + if isinstance(module, OneShotMutableModule): + module.current_choice = module.sample_choice() + + def test_estimate(self) -> None: + fool_conv2d = FoolConv2d() + flops_params_cfg = dict(input_shape=(1, 3, 224, 224)) + results = estimator.estimate( + model=fool_conv2d, flops_params_cfg=flops_params_cfg) + flops_count = results['flops'] + params_count = results['params'] + + self.assertEqual(flops_count, 44.158) + self.assertEqual(params_count, 0.001) + + fool_conv2d = Conv2dAdaptivePadding(3, 32, 3) + results = estimator.estimate( + model=fool_conv2d, flops_params_cfg=flops_params_cfg) + flops_count = results['flops'] + params_count = results['params'] + + self.assertEqual(flops_count, 44.958) + self.assertEqual(params_count, 0.001) + + def test_register_module(self) -> None: + fool_add_constant = FoolConvModule() + flops_params_cfg = dict(input_shape=(1, 3, 224, 224)) + results = estimator.estimate( + model=fool_add_constant, flops_params_cfg=flops_params_cfg) + flops_count = results['flops'] + params_count = results['params'] + + self.assertEqual(flops_count, 45.158) + self.assertEqual(params_count, 0.701) + + def test_disable_sepc_counter(self) -> None: + fool_add_constant = FoolConvModule() + flops_params_cfg = dict( + input_shape=(1, 3, 224, 224), + disabled_counters=['FoolAddConstantCounter']) + rest_results = estimator.estimate( + model=fool_add_constant, flops_params_cfg=flops_params_cfg) + rest_flops_count = rest_results['flops'] + rest_params_count = rest_results['params'] + + self.assertLess(rest_flops_count, 45.158) + self.assertLess(rest_params_count, 0.701) + + fool_conv2d = Conv2dAdaptivePadding(3, 32, 3) + flops_params_cfg = dict( + input_shape=(1, 3, 224, 224), disabled_counters=['Conv2dCounter']) + rest_results = estimator.estimate( + model=fool_conv2d, flops_params_cfg=flops_params_cfg) + rest_flops_count = rest_results['flops'] + rest_params_count = rest_results['params'] + + self.assertEqual(rest_flops_count, 0) + self.assertEqual(rest_params_count, 0) + + def test_estimate_spec_module(self) -> None: + fool_add_constant = FoolConvModule() + flops_params_cfg = dict( + input_shape=(1, 3, 224, 224), + spec_modules=['add_constant', 'conv2d']) + results = estimator.estimate( + model=fool_add_constant, flops_params_cfg=flops_params_cfg) + flops_count = results['flops'] + params_count = results['params'] + + self.assertEqual(flops_count, 45.158) + self.assertEqual(params_count, 0.701) + + def test_estimate_separation_modules(self) -> None: + fool_add_constant = FoolConvModule() + flops_params_cfg = dict( + input_shape=(1, 3, 224, 224), spec_modules=['add_constant']) + results = estimator.estimate_separation_modules( + model=fool_add_constant, flops_params_cfg=flops_params_cfg) + self.assertGreater(results['add_constant']['flops'], 0) + + with pytest.raises(AssertionError): + flops_params_cfg = dict( + input_shape=(1, 3, 224, 224), spec_modules=['backbone']) + results = estimator.estimate_separation_modules( + model=fool_add_constant, flops_params_cfg=flops_params_cfg) + + with pytest.raises(AssertionError): + flops_params_cfg = dict( + input_shape=(1, 3, 224, 224), spec_modules=[]) + results = estimator.estimate_separation_modules( + model=fool_add_constant, flops_params_cfg=flops_params_cfg) + + def test_estimate_subnet(self) -> None: + flops_params_cfg = dict(input_shape=(1, 3, 224, 224)) + model = MODELS.build(BACKBONE_CFG) + self.sample_choice(model) + copied_model = copy.deepcopy(model) + + results = estimator.estimate( + model=copied_model, flops_params_cfg=flops_params_cfg) + flops_count = results['flops'] + params_count = results['params'] + + _, sliced_model = export_fix_subnet(model, slice_weight=True) + subnet_results = estimator.estimate( + model=sliced_model, flops_params_cfg=flops_params_cfg) + subnet_flops_count = subnet_results['flops'] + subnet_params_count = subnet_results['params'] + + self.assertEqual(flops_count, subnet_flops_count) + self.assertEqual(params_count, subnet_params_count) + + # test whether subnet estimate will affect original model + copied_model = copy.deepcopy(model) + results_after_estimate = estimator.estimate( + model=copied_model, flops_params_cfg=flops_params_cfg) + flops_count_after_estimate = results_after_estimate['flops'] + params_count_after_estimate = results_after_estimate['params'] + + self.assertEqual(flops_count, flops_count_after_estimate) + self.assertEqual(params_count, params_count_after_estimate) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_graph_utils.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_graph_utils.py new file mode 100755 index 000000000..ea7f90565 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_graph_utils.py @@ -0,0 +1,536 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import operator +from unittest import TestCase + +import torch +import torch.nn as nn + +try: + from torch.ao.quantization import QConfigMapping + from torch.ao.quantization.fake_quantize import FakeQuantizeBase + from torch.ao.quantization.fx import prepare + from torch.ao.quantization.quantize_fx import _fuse_fx +except ImportError: + from mmrazor.utils import get_placeholder + QConfigMapping = get_placeholder('torch>=1.13') + FakeQuantizeBase = get_placeholder('torch>=1.13') + prepare = get_placeholder('torch>=1.13') + _fuse_fx = get_placeholder('torch>=1.13') + +from mmrazor import digit_version +from mmrazor.models.task_modules.tracer import CustomTracer, build_graphmodule +from mmrazor.models.task_modules.tracer.fx import ( + del_fakequant_after_function, del_fakequant_after_method, + del_fakequant_after_module, del_fakequant_after_op, + del_fakequant_before_function, del_fakequant_before_method, + del_fakequant_before_module, del_fakequant_before_op) +from mmrazor.structures.quantization import BackendConfigs, QConfigHandler + + +def _get_attrs(target, attrs): + attrs = attrs.split('.') + + for att in attrs: + target = getattr(target, att, None) + return target + + +class BasicBlock(nn.Module): + + def __init__(self, in_channels, out_channels): + super(BasicBlock, self).__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.mid_channels = out_channels + + self.norm1 = nn.BatchNorm2d(self.mid_channels) + self.norm2 = nn.BatchNorm2d(out_channels) + self.conv1 = nn.Conv2d(in_channels, self.mid_channels, 1) + self.conv2 = nn.Conv2d(self.mid_channels, out_channels, 1) + + self.relu = nn.ReLU6() + self.drop_path = nn.Identity() + + def forward(self, x): + + def _inner_forward(x): + identity = x + + out = self.conv1(x) + out = self.norm1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.norm2(out) + + out = self.drop_path(out) + + out += identity + + return out + + out = _inner_forward(x) + + out = self.relu(out) + + return out + + +class ToyModel(nn.Module): + + def __init__(self): + super().__init__() + self.stem_layer = nn.Sequential( + nn.Conv2d(3, 3, 1), nn.BatchNorm2d(3), nn.ReLU()) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.block = BasicBlock(3, 3) + self.block2 = BasicBlock(3, 3) + self.gap = nn.AdaptiveAvgPool2d((1, 1)) + self.fc = nn.Linear(3, 4) + + def forward(self, x): + x = self.stem_layer(x) + x = self.maxpool(x) + x = self.block(x) + x = self.block2(x) + x = self.gap(x) + x = x.flatten(1) + x = self.fc(x) + return x + + +global_qconfig = dict( + w_observer=dict(type='mmrazor.PerChannelMinMaxObserver'), + a_observer=dict(type='mmrazor.MovingAverageMinMaxObserver'), + w_fake_quant=dict(type='mmrazor.FakeQuantize'), + a_fake_quant=dict(type='mmrazor.FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', bit=8, is_symmetry=True, is_symmetric_range=True), + a_qscheme=dict( + qdtype='quint8', bit=8, is_symmetry=True, averaging_constant=0.1), +) + + +class TestGraphUtils(TestCase): + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + self.tracer = CustomTracer() + self.backend_config = BackendConfigs['native'] + self.qconfig = QConfigHandler(global_qconfig) + self.qconfig_mapping = QConfigMapping().set_global( + self.qconfig.convert()) + self.example_inputs = (torch.randn(1, 3, 224, 224), ) + + def swap_ff_with_fxff(self, model): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + modules_to_swap = [] + for name, module in model.named_children(): + if isinstance(module, torch.ao.nn.quantized.FloatFunctional): + modules_to_swap.append(name) + else: + self.swap_ff_with_fxff(module) + + for name in modules_to_swap: + del model._modules[name] + model._modules[name] = torch.ao.nn.quantized.FXFloatFunctional() + + def test_del_fakequant_before_op(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + model_to_quantize = ToyModel() + model_to_quantize.eval() + + self.swap_ff_with_fxff(model_to_quantize) + traced_graph = self.tracer.trace(model_to_quantize) + graph_module = build_graphmodule(model_to_quantize, traced_graph) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + backend_config=self.backend_config) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + backend_config=self.backend_config) + + op_del_prev_fakequant = ('output', ) + + prepared_after_del = del_fakequant_before_op( + prepared, op_del_prev_fakequant, inplace=False) + for node in prepared.graph.nodes: + if node.op in op_del_prev_fakequant: + args = node.args + self.assertIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + + for node in prepared_after_del.graph.nodes: + if node.op in op_del_prev_fakequant: + args = node.args + self.assertNotIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + + prepared_after_del = del_fakequant_before_op( + prepared, op_del_prev_fakequant, inplace=True) + for node in prepared_after_del.graph.nodes: + if node.op in op_del_prev_fakequant: + args = node.args + self.assertNotIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + + def test_del_fakequant_after_op(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + model_to_quantize = ToyModel() + model_to_quantize.eval() + + self.swap_ff_with_fxff(model_to_quantize) + traced_graph = self.tracer.trace(model_to_quantize) + graph_module = build_graphmodule(model_to_quantize, traced_graph) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + backend_config=self.backend_config) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + backend_config=self.backend_config) + + op_del_next_fakequant = ('placeholder', ) + + prepared_after_del = del_fakequant_after_op( + prepared, op_del_next_fakequant, inplace=False) + for node in prepared.graph.nodes: + if node.op in op_del_next_fakequant: + self.assertIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) + + for node in prepared_after_del.graph.nodes: + if node.op in op_del_next_fakequant: + self.assertNotIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) + + prepared_after_del = del_fakequant_after_op( + prepared, op_del_next_fakequant, inplace=True) + for node in prepared_after_del.graph.nodes: + if node.op in op_del_next_fakequant: + self.assertNotIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) + + def test_del_fakequant_before_method(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + model_to_quantize = ToyModel() + model_to_quantize.eval() + + self.swap_ff_with_fxff(model_to_quantize) + traced_graph = self.tracer.trace(model_to_quantize) + graph_module = build_graphmodule(model_to_quantize, traced_graph) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + backend_config=self.backend_config) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + backend_config=self.backend_config) + + method_del_prev_fakequant = ('flatten', ) + + prepared_after_del = del_fakequant_before_method( + prepared, method_del_prev_fakequant, inplace=False) + for node in prepared.graph.nodes: + if node.op == 'call_method' and \ + node.target in method_del_prev_fakequant: + args = node.args + self.assertIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + + for node in prepared_after_del.graph.nodes: + if node.op == 'call_method' and \ + node.target in method_del_prev_fakequant: + args = node.args + self.assertNotIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + + prepared_after_del = del_fakequant_before_method( + prepared, method_del_prev_fakequant, inplace=True) + for node in prepared_after_del.graph.nodes: + if node.op == 'call_method' and \ + node.target in method_del_prev_fakequant: + args = node.args + self.assertNotIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + + def test_del_fakequant_after_method(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + model_to_quantize = ToyModel() + model_to_quantize.eval() + + self.swap_ff_with_fxff(model_to_quantize) + traced_graph = self.tracer.trace(model_to_quantize) + graph_module = build_graphmodule(model_to_quantize, traced_graph) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + backend_config=self.backend_config) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + backend_config=self.backend_config) + + method_del_next_fakequant = ('flatten', ) + + prepared_after_del = del_fakequant_after_method( + prepared, method_del_next_fakequant, inplace=False) + for node in prepared.graph.nodes: + if node.op == 'call_method' and \ + node.target in method_del_next_fakequant: + self.assertIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) + + for node in prepared_after_del.graph.nodes: + if node.op == 'call_method' and \ + node.target in method_del_next_fakequant: + self.assertNotIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) + + prepared_after_del = del_fakequant_after_method( + prepared, method_del_next_fakequant, inplace=True) + for node in prepared_after_del.graph.nodes: + if node.op == 'call_method' and \ + node.target in method_del_next_fakequant: + self.assertNotIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) + + def test_del_fakequant_before_function(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + model_to_quantize = ToyModel() + model_to_quantize.eval() + + self.swap_ff_with_fxff(model_to_quantize) + traced_graph = self.tracer.trace(model_to_quantize) + graph_module = build_graphmodule(model_to_quantize, traced_graph) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + backend_config=self.backend_config) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + backend_config=self.backend_config) + + function_del_prev_fakequant = (operator.add, ) + + prepared_after_del = del_fakequant_before_function( + prepared, function_del_prev_fakequant, inplace=False) + for node in prepared.graph.nodes: + if node.op == 'call_function' and \ + node.target in function_del_prev_fakequant: + args = node.args + self.assertIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + + for node in prepared_after_del.graph.nodes: + if node.op == 'call_function' and \ + node.target in function_del_prev_fakequant: + args = node.args + self.assertEqual(len(args), 2) + self.assertNotIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + self.assertNotIsInstance( + _get_attrs(prepared, args[1].target), FakeQuantizeBase) + + prepared_after_del = del_fakequant_before_function( + prepared, function_del_prev_fakequant, inplace=True) + for node in prepared_after_del.graph.nodes: + if node.op == 'call_function' and \ + node.target in function_del_prev_fakequant: + args = node.args + self.assertEqual(len(args), 2) + self.assertNotIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + self.assertNotIsInstance( + _get_attrs(prepared, args[1].target), FakeQuantizeBase) + + def test_del_fakequant_after_function(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + model_to_quantize = ToyModel() + model_to_quantize.eval() + + self.swap_ff_with_fxff(model_to_quantize) + traced_graph = self.tracer.trace(model_to_quantize) + graph_module = build_graphmodule(model_to_quantize, traced_graph) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + backend_config=self.backend_config) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + backend_config=self.backend_config) + + function_del_next_fakequant = (operator.add, ) + + prepared_after_del = del_fakequant_after_function( + prepared, function_del_next_fakequant, inplace=False) + for node in prepared.graph.nodes: + if node.op == 'call_function' and \ + node.target in function_del_next_fakequant: + self.assertIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) + + for node in prepared_after_del.graph.nodes: + if node.op == 'call_function' and \ + node.target in function_del_next_fakequant: + self.assertNotIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) + + prepared_after_del = del_fakequant_after_function( + prepared, function_del_next_fakequant, inplace=True) + for node in prepared_after_del.graph.nodes: + if node.op == 'call_function' and \ + node.target in function_del_next_fakequant: + self.assertNotIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) + + def test_del_fakequant_before_module(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + model_to_quantize = ToyModel() + model_to_quantize.eval() + + self.swap_ff_with_fxff(model_to_quantize) + traced_graph = self.tracer.trace(model_to_quantize) + graph_module = build_graphmodule(model_to_quantize, traced_graph) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + backend_config=self.backend_config) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + backend_config=self.backend_config) + + module_del_prev_fakequant = (torch.nn.ReLU6, torch.nn.Identity) + + prepared_after_del = del_fakequant_before_module( + prepared, module_del_prev_fakequant, inplace=False) + for node in prepared.graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared, node.target), + module_del_prev_fakequant): + args = node.args + self.assertIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + + for node in prepared_after_del.graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared, node.target), + module_del_prev_fakequant): + args = node.args + if args[0].op == 'call_module': + self.assertNotIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + + prepared_after_del = del_fakequant_before_module( + prepared, module_del_prev_fakequant, inplace=True) + for node in prepared_after_del.graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared, node.target), + module_del_prev_fakequant): + args = node.args + if args[0].op == 'call_module': + self.assertNotIsInstance( + _get_attrs(prepared, args[0].target), FakeQuantizeBase) + + def test_del_fakequant_after_module(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + model_to_quantize = ToyModel() + model_to_quantize.eval() + + self.swap_ff_with_fxff(model_to_quantize) + traced_graph = self.tracer.trace(model_to_quantize) + graph_module = build_graphmodule(model_to_quantize, traced_graph) + + graph_module = _fuse_fx( + graph_module=graph_module, + is_qat=True, + backend_config=self.backend_config) + prepared = prepare( + model=graph_module, + qconfig_mapping=self.qconfig_mapping, + is_qat=True, + node_name_to_scope=self.tracer.node_name_to_scope, + example_inputs=self.example_inputs, + backend_config=self.backend_config) + + module_del_next_fakequant = (torch.nn.MaxPool2d, ) + + prepared_after_del = del_fakequant_after_module( + prepared, module_del_next_fakequant, inplace=False) + for node in prepared.graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared, node.target), + module_del_next_fakequant): + self.assertIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) + + for node in prepared_after_del.graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared, node.target), + module_del_next_fakequant): + self.assertNotIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) + + prepared_after_del = del_fakequant_after_module( + prepared, module_del_next_fakequant, inplace=True) + for node in prepared_after_del.graph.nodes: + if node.op == 'call_module' and isinstance( + _get_attrs(prepared, node.target), + module_del_next_fakequant): + self.assertNotIsInstance( + _get_attrs(prepared, node.next.target), FakeQuantizeBase) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_predictors/test_metric_predictor.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_predictors/test_metric_predictor.py new file mode 100755 index 000000000..5da4ab4d1 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_task_modules/test_predictors/test_metric_predictor.py @@ -0,0 +1,196 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import tempfile +from unittest import TestCase + +import numpy as np +import torch.nn as nn +from mmengine.model import BaseModel + +from mmrazor.models import OneShotMutableOP +from mmrazor.registry import TASK_UTILS + +convs = nn.ModuleDict({ + 'conv1': nn.Conv2d(3, 8, 1), + 'conv2': nn.Conv2d(3, 8, 1), + 'conv3': nn.Conv2d(3, 8, 1), +}) +MutableOP = OneShotMutableOP(convs) + + +class ToyModel(BaseModel): + + def __init__(self, data_preprocessor=None): + super().__init__(data_preprocessor=data_preprocessor, init_cfg=None) + self.mutable = MutableOP + self.bn = nn.BatchNorm2d(8) + + def forward(self, batch_inputs, data_samples=None, mode='tensor'): + if mode == 'loss': + out = self.bn(self.mutable(batch_inputs)) + return dict(loss=out) + elif mode == 'predict': + out = self.bn(self.mutable(batch_inputs)) + 1 + return out + elif mode == 'tensor': + out = self.bn(self.mutable(batch_inputs)) + 2 + return out + + +class TestMetricPredictorWithGP(TestCase): + + def setUp(self) -> None: + self.temp_dir = tempfile.mkdtemp() + self.search_groups = {0: [MutableOP]} + self.candidates = [{0: 'conv1'}, {0: 'conv2'}, {0: 'conv3'}] + predictor_cfg = dict( + type='MetricPredictor', + handler_cfg=dict(type='GaussProcessHandler'), + search_groups=self.search_groups, + train_samples=4, + ) + self.predictor = TASK_UTILS.build(predictor_cfg) + self.model = ToyModel() + + def generate_data(self): + inputs = [] + for candidate in self.candidates: + inputs.append(self.predictor.model2vector(candidate)) + inputs = np.array(inputs) + labels = np.random.rand(3) + return inputs, labels + + def test_init_predictor(self): + self.model.mutable.current_choice = 'conv1' + inputs, labels = self.generate_data() + self.assertFalse(self.predictor.initialize) + self.predictor.fit(inputs, labels) + self.assertTrue(self.predictor.initialize) + + def test_predictor(self): + self.model.mutable.current_choice = 'conv1' + inputs, labels = self.generate_data() + self.predictor.fit(inputs, labels) + + metrics = self.predictor.predict(self.model) + self.assertIsInstance(metrics, dict) + self.assertGreater(metrics['accuracy_top-1'], 0.0) + + +class TestMetricPredictorWithCart(TestCase): + + def setUp(self) -> None: + self.temp_dir = tempfile.mkdtemp() + self.search_groups = {0: [MutableOP]} + self.candidates = [{0: 'conv1'}, {0: 'conv2'}, {0: 'conv3'}] + predictor_cfg = dict( + type='MetricPredictor', + handler_cfg=dict(type='CartsHandler'), + search_groups=self.search_groups, + train_samples=4, + ) + self.predictor = TASK_UTILS.build(predictor_cfg) + self.model = ToyModel() + + def generate_data(self): + inputs = [] + for candidate in self.candidates: + inputs.append(self.predictor.model2vector(candidate)) + inputs = np.array(inputs) + labels = np.random.rand(3) + return inputs, labels + + def test_init_predictor(self): + self.model.mutable.current_choice = 'conv1' + inputs, labels = self.generate_data() + self.assertFalse(self.predictor.initialize) + self.predictor.fit(inputs, labels) + self.assertTrue(self.predictor.initialize) + + def test_predictor(self): + self.model.mutable.current_choice = 'conv1' + inputs, labels = self.generate_data() + self.predictor.fit(inputs, labels) + + metrics = self.predictor.predict(self.model) + self.assertIsInstance(metrics, dict) + self.assertGreater(metrics['accuracy_top-1'], 0.0) + + +class TestMetricPredictorWithRBF(TestCase): + + def setUp(self) -> None: + self.temp_dir = tempfile.mkdtemp() + self.search_groups = {0: [MutableOP]} + self.candidates = [{0: 'conv1'}, {0: 'conv2'}, {0: 'conv3'}] + predictor_cfg = dict( + type='MetricPredictor', + handler_cfg=dict(type='RBFHandler'), + search_groups=self.search_groups, + train_samples=4, + ) + self.predictor = TASK_UTILS.build(predictor_cfg) + self.model = ToyModel() + + def generate_data(self): + inputs = [] + for candidate in self.candidates: + inputs.append(self.predictor.model2vector(candidate)) + inputs = np.array(inputs) + labels = np.random.rand(3) + return inputs, labels + + def test_init_predictor(self): + self.model.mutable.current_choice = 'conv1' + inputs, labels = self.generate_data() + self.assertFalse(self.predictor.initialize) + self.predictor.fit(inputs, labels) + self.assertTrue(self.predictor.initialize) + + def test_predictor(self): + self.model.mutable.current_choice = 'conv1' + inputs, labels = self.generate_data() + self.predictor.fit(inputs, labels) + + metrics = self.predictor.predict(self.model) + self.assertIsInstance(metrics, dict) + self.assertGreater(metrics['accuracy_top-1'], 0.0) + + +class TestMetricPredictorWithMLP(TestCase): + + def setUp(self) -> None: + self.temp_dir = tempfile.mkdtemp() + self.search_groups = {0: [MutableOP]} + self.candidates = [{0: 'conv1'}, {0: 'conv2'}, {0: 'conv3'}] + predictor_cfg = dict( + type='MetricPredictor', + handler_cfg=dict(type='MLPHandler'), + search_groups=self.search_groups, + train_samples=4, + ) + self.predictor = TASK_UTILS.build(predictor_cfg) + self.model = ToyModel() + + def generate_data(self): + inputs = [] + for candidate in self.candidates: + inputs.append(self.predictor.model2vector(candidate)) + inputs = np.array(inputs) + labels = np.random.rand(3) + return inputs, labels + + def test_init_predictor(self): + self.model.mutable.current_choice = 'conv1' + inputs, labels = self.generate_data() + self.assertFalse(self.predictor.initialize) + self.predictor.fit(inputs, labels) + self.assertTrue(self.predictor.initialize) + + def test_predictor(self): + self.model.mutable.current_choice = 'conv1' + inputs, labels = self.generate_data() + self.predictor.fit(inputs, labels) + + metrics = self.predictor.predict(self.model) + self.assertIsInstance(metrics, dict) + self.assertGreater(metrics['accuracy_top-1'], 0.0) diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/test_expand.py b/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/test_expand.py new file mode 100755 index 000000000..f8f3b82a8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_models/test_utils/test_expandable_utils/test_expand.py @@ -0,0 +1,64 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest + +import torch + +from mmrazor import digit_version +from mmrazor.models.mutables import SimpleMutableChannel +from mmrazor.models.utils.expandable_utils import ( + expand_expandable_dynamic_model, make_channel_divisible, + to_expandable_model) +from mmrazor.models.utils.expandable_utils.ops import ExpandLinear +from ....data.models import DwConvModel, MultiConcatModel, SingleLineModel + + +class TestExpand(unittest.TestCase): + + def check_torch_version(self): + if digit_version(torch.__version__) < digit_version('1.12.0'): + self.skipTest('version of torch < 1.12.0') + + def test_expand(self): + self.check_torch_version() + for Model in [MultiConcatModel, DwConvModel]: + x = torch.rand([1, 3, 224, 224]) + model = Model() + print(model) + mutator = to_expandable_model(model) + print(mutator.choice_template) + print(model) + y1 = model(x) + + for unit in mutator.mutable_units: + unit.expand(10) + print(unit.mutable_channel.mask.shape) + expand_expandable_dynamic_model(model, zero=True) + print(model) + y2 = model(x) + self.assertTrue((y1 - y2).abs().max() < 1e-3) + + def test_expand_static_model(self): + self.check_torch_version() + x = torch.rand([1, 3, 224, 224]) + model = SingleLineModel() + y1 = model(x) + make_channel_divisible(model, divisor=4) + y2 = model(x) + print(y1.reshape([-1])[:5]) + print(y2.reshape([-1])[:5]) + self.assertTrue((y1 - y2).abs().max() < 1e-3) + + def test_ExpandConv2d(self): + self.check_torch_version() + linear = ExpandLinear(3, 3) + mutable_in = SimpleMutableChannel(3) + mutable_out = SimpleMutableChannel(3) + linear.register_mutable_attr('in_channels', mutable_in) + linear.register_mutable_attr('out_channels', mutable_out) + + print(linear.weight) + + mutable_in.mask = torch.tensor([1.0, 1.0, 0.0, 1.0, 0.0]) + mutable_out.mask = torch.tensor([1.0, 1.0, 0.0, 1.0, 0.0]) + linear_ex = linear.expand(zero=True) + print(linear_ex.weight) diff --git a/cv/distiller/CWD/mmrazor/tests/test_registry/test_registry.py b/cv/distiller/CWD/mmrazor/tests/test_registry/test_registry.py new file mode 100755 index 000000000..c8340f352 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_registry/test_registry.py @@ -0,0 +1,144 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest +from typing import Dict, Optional, Union +from unittest import TestCase + +import torch.nn as nn +from mmengine import fileio +from mmengine.config import Config +from mmengine.model import BaseModel + +from mmrazor.models import * # noqa: F403, F401 +from mmrazor.models.algorithms.base import BaseAlgorithm +from mmrazor.models.mutables import OneShotMutableOP +from mmrazor.registry import MODELS +from mmrazor.structures import load_fix_subnet +from mmrazor.utils import ValidFixMutable + + +@MODELS.register_module() +class MockModel(BaseModel): + + def __init__(self): + super().__init__() + convs1 = nn.ModuleDict({ + 'conv1': nn.Conv2d(3, 8, 1), + 'conv2': nn.Conv2d(3, 8, 1), + 'conv3': nn.Conv2d(3, 8, 1), + }) + convs2 = nn.ModuleDict({ + 'conv1': nn.Conv2d(8, 16, 1), + 'conv2': nn.Conv2d(8, 16, 1), + 'conv3': nn.Conv2d(8, 16, 1), + }) + + self.mutable1 = OneShotMutableOP(convs1) + self.mutable2 = OneShotMutableOP(convs2) + + def forward(self, x): + x = self.mutable1(x) + x = self.mutable2(x) + return x + + +@MODELS.register_module() +class MockAlgorithm(BaseAlgorithm): + + def __init__(self, + architecture: Union[BaseModel, Dict], + fix_subnet: Optional[ValidFixMutable] = None): + super().__init__(architecture) + + if fix_subnet is not None: + # According to fix_subnet, delete the unchosen part of supernet + load_fix_subnet(self, fix_subnet, prefix='architecture.') + self.is_supernet = False + else: + self.is_supernet = True + + +class TestRegistry(TestCase): + + def setUp(self) -> None: + self.arch_cfg_path = dict( + cfg_path='mmdet::faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py', + pretrained=False) + + return super().setUp() + + def test_build_razor_from_cfg(self): + # test cfg_path + # TODO relay on mmengine:HAOCHENYE/config_new_feature + # model = MODELS.build(self.arch_cfg_path) + # self.assertIsNotNone(model) + + # test fix subnet + cfg = Config.fromfile( + 'tests/data/test_registry/registry_subnet_config.py') + model = MODELS.build(cfg.model) + + # test return architecture + cfg = Config.fromfile( + 'tests/data/test_registry/registry_architecture_config.py') + model = MODELS.build(cfg.model) + self.assertTrue(isinstance(model, BaseModel)) + + def test_build_subnet_prune_from_cfg(self): + mutator_cfg = fileio.load('tests/data/test_registry/subnet.json') + init_cfg = dict( + type='Pretrained', + checkpoint='tests/data/test_registry/subnet_weight.pth') + # test fix subnet + model_cfg = dict( + # use mmrazor's build_func + type='mmrazor.sub_model', + cfg=dict( + cfg_path='mmcls::resnet/resnet50_8xb32_in1k.py', + pretrained=False), + fix_subnet=mutator_cfg, + mode='mutator', + init_cfg=init_cfg) + model = MODELS.build(model_cfg) + self.assertTrue(isinstance(model, BaseModel)) + + def test_build_subnet_prune_from_cfg_by_mutator(self): + mutator_cfg = fileio.load('tests/data/test_registry/subnet.json') + init_cfg = dict( + type='Pretrained', + checkpoint='tests/data/test_registry/subnet_weight.pth') + # test fix subnet + model_cfg = dict( + # use mmrazor's build_func + type='mmrazor.sub_model', + cfg=dict( + cfg_path='mmcls::resnet/resnet50_8xb32_in1k.py', + pretrained=False), + fix_subnet=mutator_cfg, + mode='mutator', + init_cfg=init_cfg) + model = MODELS.build(model_cfg) + self.assertTrue(isinstance(model, BaseModel)) + # make sure the model is pruned + assert model.backbone.layer1[0].conv1.weight.size()[0] == 41 + + def test_build_subnet_prune_from_cfg_by_mutable(self): + mutator_cfg = fileio.load('tests/data/test_registry/subnet.json') + init_cfg = dict( + type='Pretrained', + checkpoint='tests/data/test_registry/subnet_weight.pth') + # test fix subnet + model_cfg = dict( + # use mmrazor's build_func + type='mmrazor.sub_model', + cfg=dict( + cfg_path='mmcls::resnet/resnet50_8xb32_in1k.py', + pretrained=False), + fix_subnet=mutator_cfg, + mode='mutable', + init_cfg=init_cfg) + model = MODELS.build(model_cfg) + self.assertTrue(isinstance(model, BaseModel)) + + +if __name__ == '__main__': + unittest.main() diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_autoslim_greedy_search_loop.py b/cv/distiller/CWD/mmrazor/tests/test_runners/test_autoslim_greedy_search_loop.py new file mode 100755 index 000000000..87fab9939 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_runners/test_autoslim_greedy_search_loop.py @@ -0,0 +1,187 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import shutil +import tempfile +from typing import Dict, List, Tuple, Union +from unittest import TestCase +from unittest.mock import MagicMock + +import torch +import torch.nn as nn +import torch.nn.functional as F +from mmcls.structures import ClsDataSample +from mmengine.config import Config +from torch.utils.data import DataLoader, Dataset + +from mmrazor.engine import AutoSlimGreedySearchLoop +from mmrazor.models.algorithms import AutoSlim +from mmrazor.registry import LOOPS + +MUTATOR_TYPE = Union[torch.nn.Module, Dict] +DISTILLER_TYPE = Union[torch.nn.Module, Dict] + + +def collate_fn(data_batch): + return data_batch[0] + + +class ToyDataset(Dataset): + METAINFO = dict() # type: ignore + data = [torch.randn(2, 3, 4, 4)] * 4 + label = [[ClsDataSample().set_gt_label(torch.randint(0, 1000, (2, )))] + for _ in range(4)] + + @property + def metainfo(self): + return self.METAINFO + + def __len__(self): + return len(self.data) + + def __getitem__(self, index): + return dict(inputs=self.data[index], data_samples=self.label[index]) + + +ARCHITECTURE_CFG = dict( + _scope_='mmcls', + type='ImageClassifier', + backbone=dict(type='MobileNetV2', widen_factor=1.5), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='mmcls.LinearClsHead', + num_classes=1000, + in_channels=1920, + loss=dict(type='mmcls.CrossEntropyLoss', loss_weight=1.0), + topk=(1, 5))) + +MUTATOR_CFG = dict( + type='OneShotChannelMutator', + channel_unit_cfg=dict( + type='OneShotMutableChannelUnit', + default_args=dict( + candidate_choices=list(i / 12 for i in range(2, 13)), + choice_mode='ratio'))) + +DISTILLER_CFG = dict( + type='ConfigurableDistiller', + teacher_recorders=dict(fc=dict(type='ModuleOutputs', source='head.fc')), + student_recorders=dict(fc=dict(type='ModuleOutputs', source='head.fc')), + distill_losses=dict( + loss_kl=dict(type='KLDivergence', tau=1, loss_weight=1)), + loss_forward_mappings=dict( + loss_kl=dict( + preds_S=dict(recorder='fc', from_student=True), + preds_T=dict(recorder='fc', from_student=False)))) + + +class ToyDataPreprocessor(torch.nn.Module): + + def forward( + self, + data: Dict, + training: bool = True) -> Tuple[torch.Tensor, List[ClsDataSample]]: + return data + + +class Net(nn.Module): + + def __init__(self): + super(Net, self).__init__() + self.conv = nn.Conv2d(3, 100, 3) + + def forward(self, x): + out = F.conv2d( + x, + weight=self.conv.weight, + bias=self.conv.bias, + stride=self.conv.stride, + padding=self.conv.padding, + dilation=self.conv.dilation, + groups=self.conv.groups) + return out + + +class ToyRunner: + + @property + def distributed(self): + pass + + @property + def rank(self): + pass + + @property + def epoch(self): + pass + + @property + def work_dir(self): + pass + + def model(self): + pass + + def logger(self): + pass + + def call_hook(self, fn_name: str): + pass + + def visualizer(self): + pass + + +class TestAutoSlimGreedySearchLoop(TestCase): + device: str = 'cpu' + + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + train_cfg = dict(type='AutoSlimGreedySearchLoop', target_flops=(700, )) + self.train_cfg = Config(train_cfg) + self.runner = MagicMock(spec=ToyRunner) + self.runner.model = self.prepare_model(MUTATOR_CFG, DISTILLER_CFG, + ARCHITECTURE_CFG) + self.runner.distributed = False + self.dataloader = DataLoader(ToyDataset(), collate_fn=collate_fn) + self.evaluator = MagicMock() + + def prepare_model(self, + mutator_cfg: MUTATOR_TYPE = MUTATOR_CFG, + distiller_cfg: DISTILLER_TYPE = DISTILLER_CFG, + architecture_cfg: Dict = ARCHITECTURE_CFG, + num_random_samples: int = 2) -> AutoSlim: + model = AutoSlim( + mutator=mutator_cfg, + distiller=distiller_cfg, + architecture=architecture_cfg, + data_preprocessor=ToyDataPreprocessor(), + num_random_samples=num_random_samples) + model.to(self.device) + + return model + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_init(self) -> None: + loop_cfg = copy.deepcopy(self.train_cfg) + loop_cfg.runner = self.runner + loop_cfg.dataloader = self.dataloader + loop_cfg.evaluator = self.evaluator + loop = LOOPS.build(loop_cfg) + self.assertIsInstance(loop, AutoSlimGreedySearchLoop) + + def test_run(self): + # test_run_epoch: distributed == False + loop_cfg = copy.deepcopy(self.train_cfg) + loop_cfg.runner = self.runner + loop_cfg.dataloader = self.dataloader + loop_cfg.evaluator = self.evaluator + loop = LOOPS.build(loop_cfg) + self.runner.rank = 0 + loop._epoch = 1 + self.runner.distributed = False + self.runner.work_dir = self.temp_dir + loop.run() + self.assertEqual(len(loop.searched_subnet), 1) diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_darts_loop.py b/cv/distiller/CWD/mmrazor/tests/test_runners/test_darts_loop.py new file mode 100755 index 000000000..70255b206 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_runners/test_darts_loop.py @@ -0,0 +1,258 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import shutil +import tempfile +from unittest import TestCase + +import torch +import torch.nn as nn +from mmengine.config import Config +from mmengine.hooks import Hook +from mmengine.model import BaseDataPreprocessor, BaseModel +from mmengine.runner import Runner +from torch.utils.data import DataLoader, Dataset + +from mmrazor.engine import DartsEpochBasedTrainLoop # noqa: F401 +from mmrazor.engine import DartsIterBasedTrainLoop # noqa: F401 +from mmrazor.registry import DATASETS, HOOKS, MODELS + + +class ToyDataPreprocessor(BaseDataPreprocessor): + + def collate_data(self, data): + data = [_data[0] for _data in data] + inputs = [_data['inputs'].to(self._device) for _data in data] + batch_data_samples = [] + # Model can get predictions without any data samples. + for _data in data: + if 'data_samples' in _data: + batch_data_samples.append(_data['data_samples']) + # Move data from CPU to corresponding device. + batch_data_samples = [ + data_sample.to(self._device) for data_sample in batch_data_samples + ] + + if not batch_data_samples: + batch_data_samples = None # type: ignore + + return inputs, batch_data_samples + + +@MODELS.register_module() +class ToyModel_DartsLoop(BaseModel): + + def __init__(self): + super().__init__() + self.linear1 = nn.Linear(2, 2) + self.linear2 = nn.Linear(2, 1) + + def train_step(self, data, optim_wrapper=None): + + data1, data2 = data + _ = self._run_forward(data1, mode='loss') + losses = self._run_forward(data2, mode='loss') + parsed_losses, log_vars = self.parse_losses(losses) + return log_vars + + def forward(self, inputs, data_samples, mode='tensor'): + batch_inputs = torch.stack(inputs).to(self.linear1.weight.device) + labels = torch.stack(data_samples).to(self.linear1.weight.device) + outputs = self.linear1(batch_inputs) + outputs = self.linear2(outputs) + + if mode == 'tensor': + return outputs + elif mode == 'loss': + loss = (labels - outputs).sum() + outputs = dict(loss=loss) + return outputs + elif mode == 'predict': + outputs = dict(log_vars=dict(a=1, b=0.5)) + return outputs + + +@DATASETS.register_module() +class ToyDataset_DartsLoop(Dataset): + METAINFO = dict() # type: ignore + data = torch.randn(12, 2) + label = torch.ones(12) + + @property + def metainfo(self): + return self.METAINFO + + def __len__(self): + return self.data.size(0) + + def __getitem__(self, index): + return dict(inputs=self.data[index], data_samples=self.label[index]) + + +class TestDartsLoop(TestCase): + + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + epoch_based_cfg = dict( + default_scope='mmrazor', + model=dict(type='ToyModel_DartsLoop'), + work_dir=self.temp_dir, + train_dataloader=dict( + dataset=dict(type='ToyDataset_DartsLoop'), + sampler=dict(type='DefaultSampler', shuffle=True), + batch_size=3, + num_workers=0), + optim_wrapper=dict( + type='OptimWrapper', optimizer=dict(type='SGD', lr=0.01)), + param_scheduler=dict(type='MultiStepLR', milestones=[1, 2]), + train_cfg=dict( + type='DartsEpochBasedTrainLoop', + max_epochs=3, + val_interval=1, + val_begin=2), + custom_hooks=[], + default_hooks=dict( + runtime_info=dict(type='RuntimeInfoHook'), + timer=dict(type='IterTimerHook'), + logger=dict(type='LoggerHook'), + param_scheduler=dict(type='ParamSchedulerHook'), + checkpoint=dict( + type='CheckpointHook', interval=1, by_epoch=True), + sampler_seed=dict(type='DistSamplerSeedHook')), + launcher='none', + env_cfg=dict(dist_cfg=dict(backend='nccl')), + ) + self.epoch_based_cfg = Config(epoch_based_cfg) + self.epoch_based_cfg.train_cfg['mutator_dataloader'] = \ + self.epoch_based_cfg.train_dataloader + self.iter_based_cfg = copy.deepcopy(self.epoch_based_cfg) + self.iter_based_cfg.train_dataloader = dict( + dataset=dict(type='ToyDataset_DartsLoop'), + sampler=dict(type='InfiniteSampler', shuffle=True), + batch_size=3, + num_workers=0) + self.iter_based_cfg.train_cfg = dict( + type='DartsIterBasedTrainLoop', + mutator_dataloader=self.iter_based_cfg.train_dataloader, + max_iters=12, + val_interval=4, + val_begin=4) + self.iter_based_cfg.default_hooks = dict( + runtime_info=dict(type='RuntimeInfoHook'), + timer=dict(type='IterTimerHook'), + logger=dict(type='LoggerHook'), + param_scheduler=dict(type='ParamSchedulerHook'), + checkpoint=dict(type='CheckpointHook', interval=1, by_epoch=False), + sampler_seed=dict(type='DistSamplerSeedHook')) + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_init(self): + # 1. DartsEpochBasedTrainLoop + cfg = copy.deepcopy(self.epoch_based_cfg) + cfg.experiment_name = 'test_init1' + runner = Runner.from_cfg(cfg) + loop = runner.build_train_loop(cfg.train_cfg) + + self.assertIsInstance(loop, DartsEpochBasedTrainLoop) + self.assertIsInstance(loop.runner, Runner) + self.assertEqual(loop.max_epochs, 3) + self.assertEqual(loop.max_iters, 12) + self.assertIsInstance(loop.mutator_dataloader, DataLoader) + + # 2. DartsIterBasedTrainLoop + cfg = copy.deepcopy(self.iter_based_cfg) + cfg.experiment_name = 'test_init2' + runner = Runner.from_cfg(cfg) + loop = runner.build_train_loop(cfg.train_cfg) + + self.assertIsInstance(loop, DartsIterBasedTrainLoop) + self.assertIsInstance(loop.runner, Runner) + self.assertEqual(loop.max_iters, 12) + self.assertIsInstance(loop.mutator_dataloader, DataLoader) + + def test_run(self): + # 1. test DartsEpochBasedTrainLoop + epoch_results = [] + epoch_targets = [i for i in range(3)] + iter_results = [] + iter_targets = [i for i in range(4 * 3)] + batch_idx_results = [] + batch_idx_targets = [i for i in range(4)] * 3 # train and val + val_epoch_results = [] + val_epoch_targets = [i for i in range(2, 4)] + + @HOOKS.register_module() + class TestEpochHook(Hook): + + def before_train_epoch(self, runner): + epoch_results.append(runner.epoch) + + def before_train_iter(self, runner, batch_idx, data_batch=None): + iter_results.append(runner.iter) + batch_idx_results.append(batch_idx) + + def before_val_epoch(self, runner): + val_epoch_results.append(runner.epoch) + + cfg = copy.deepcopy(self.epoch_based_cfg) + cfg.experiment_name = 'test_train1' + cfg.custom_hooks = [dict(type='TestEpochHook', priority=50)] + runner = Runner.from_cfg(cfg) + runner.train() + + assert isinstance(runner.train_loop, DartsEpochBasedTrainLoop) + for result, target, in zip(epoch_results, epoch_targets): + self.assertEqual(result, target) + for result, target, in zip(iter_results, iter_targets): + self.assertEqual(result, target) + for result, target, in zip(batch_idx_results, batch_idx_targets): + self.assertEqual(result, target) + for result, target, in zip(val_epoch_results, val_epoch_targets): + self.assertEqual(result, target) + + # 2. test DartsIterBasedTrainLoop + epoch_results = [] + iter_results = [] + batch_idx_results = [] + val_iter_results = [] + val_batch_idx_results = [] + iter_targets = [i for i in range(12)] + batch_idx_targets = [i for i in range(12)] + val_iter_targets = [i for i in range(4, 12)] + val_batch_idx_targets = [i for i in range(4)] * 2 + + @HOOKS.register_module() + class TestIterHook(Hook): + + def before_train_epoch(self, runner): + epoch_results.append(runner.epoch) + + def before_train_iter(self, runner, batch_idx, data_batch=None): + iter_results.append(runner.iter) + batch_idx_results.append(batch_idx) + + def before_val_iter(self, runner, batch_idx, data_batch=None): + val_epoch_results.append(runner.iter) + val_batch_idx_results.append(batch_idx) + + cfg = copy.deepcopy(self.iter_based_cfg) + cfg.experiment_name = 'test_train2' + cfg.custom_hooks = [dict(type='TestIterHook', priority=50)] + runner = Runner.from_cfg(cfg) + runner.train() + + assert isinstance(runner.train_loop, DartsIterBasedTrainLoop) + self.assertEqual(len(epoch_results), 1) + self.assertEqual(epoch_results[0], 0) + self.assertEqual(runner.val_interval, 4) + self.assertEqual(runner.val_begin, 4) + for result, target, in zip(iter_results, iter_targets): + self.assertEqual(result, target) + for result, target, in zip(batch_idx_results, batch_idx_targets): + self.assertEqual(result, target) + for result, target, in zip(val_iter_results, val_iter_targets): + self.assertEqual(result, target) + for result, target, in zip(val_batch_idx_results, + val_batch_idx_targets): + self.assertEqual(result, target) diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_distill_val_loop.py b/cv/distiller/CWD/mmrazor/tests/test_runners/test_distill_val_loop.py new file mode 100755 index 000000000..49fa9ace4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_runners/test_distill_val_loop.py @@ -0,0 +1,180 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import shutil +import tempfile +from unittest import TestCase +from unittest.mock import MagicMock + +import torch +import torch.nn as nn +from mmengine.config import Config +from mmengine.evaluator import BaseMetric +from mmengine.model import BaseModel +from mmengine.runner import Runner +from torch.utils.data import Dataset + +from mmrazor.engine import SelfDistillValLoop # noqa: F401 +from mmrazor.engine import SingleTeacherDistillValLoop +from mmrazor.registry import DATASETS, METRICS, MODELS + + +@MODELS.register_module() +class ToyModel_DistillValLoop(BaseModel): + + def __init__(self): + super().__init__() + self.linear1 = nn.Linear(2, 2) + self.linear2 = nn.Linear(2, 1) + self.teacher = MagicMock() + + def forward(self, inputs, data_samples, mode='tensor'): + inputs = torch.stack(inputs) + labels = torch.stack(data_samples) + outputs = self.linear1(inputs) + outputs = self.linear2(outputs) + + if mode == 'tensor': + return outputs + elif mode == 'loss': + loss = (labels - outputs).sum() + outputs = dict(loss=loss) + return outputs + elif mode == 'predict': + outputs = dict(log_vars=dict(a=1, b=0.5)) + return outputs + + +@DATASETS.register_module() +class ToyDataset_DistillValLoop(Dataset): + METAINFO = dict() # type: ignore + data = torch.randn(12, 2) + label = torch.ones(12) + + @property + def metainfo(self): + return self.METAINFO + + def __len__(self): + return self.data.size(0) + + def __getitem__(self, index): + return dict(inputs=self.data[index], data_samples=self.label[index]) + + +@METRICS.register_module() +class ToyMetric_DistillValLoop(BaseMetric): + + def __init__(self, collect_device='cpu', dummy_metrics=None): + super().__init__(collect_device=collect_device) + self.dummy_metrics = dummy_metrics + + def process(self, data_samples, predictions): + result = {'acc': 1} + self.results.append(result) + + def compute_metrics(self, results): + return dict(acc=1) + + +class TestSingleTeacherDistillValLoop(TestCase): + + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + + val_dataloader = dict( + dataset=dict(type='ToyDataset_DistillValLoop'), + sampler=dict(type='DefaultSampler', shuffle=False), + batch_size=3, + num_workers=0) + val_evaluator = dict(type='ToyMetric_DistillValLoop') + + val_loop_cfg = dict( + default_scope='mmrazor', + model=dict(type='ToyModel_DistillValLoop'), + work_dir=self.temp_dir, + val_dataloader=val_dataloader, + val_evaluator=val_evaluator, + val_cfg=dict(type='SingleTeacherDistillValLoop'), + custom_hooks=[], + default_hooks=dict( + runtime_info=dict(type='RuntimeInfoHook'), + timer=dict(type='IterTimerHook'), + logger=dict(type='LoggerHook'), + param_scheduler=dict(type='ParamSchedulerHook'), + checkpoint=dict( + type='CheckpointHook', interval=1, by_epoch=True), + sampler_seed=dict(type='DistSamplerSeedHook')), + launcher='none', + env_cfg=dict(dist_cfg=dict(backend='nccl')), + ) + self.val_loop_cfg = Config(val_loop_cfg) + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_init(self): + cfg = copy.deepcopy(self.val_loop_cfg) + cfg.experiment_name = 'test_init' + runner = Runner.from_cfg(cfg) + loop = runner.build_val_loop(cfg.val_cfg) + + self.assertIsInstance(loop, SingleTeacherDistillValLoop) + + def test_run(self): + cfg = copy.deepcopy(self.val_loop_cfg) + cfg.experiment_name = 'test_run' + runner = Runner.from_cfg(cfg) + runner.val() + + self.assertIn('val/teacher.acc', runner.message_hub.log_scalars.keys()) + + +class TestSelfDistillValLoop(TestCase): + + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + + val_dataloader = dict( + dataset=dict(type='ToyDataset_DistillValLoop'), + sampler=dict(type='DefaultSampler', shuffle=False), + batch_size=3, + num_workers=0) + val_evaluator = dict(type='ToyMetric_DistillValLoop') + + val_loop_cfg = dict( + default_scope='mmrazor', + model=dict(type='ToyModel_DistillValLoop'), + work_dir=self.temp_dir, + val_dataloader=val_dataloader, + val_evaluator=val_evaluator, + val_cfg=dict(type='SelfDistillValLoop'), + custom_hooks=[], + default_hooks=dict( + runtime_info=dict(type='RuntimeInfoHook'), + timer=dict(type='IterTimerHook'), + logger=dict(type='LoggerHook'), + param_scheduler=dict(type='ParamSchedulerHook'), + checkpoint=dict( + type='CheckpointHook', interval=1, by_epoch=True), + sampler_seed=dict(type='DistSamplerSeedHook')), + launcher='none', + env_cfg=dict(dist_cfg=dict(backend='nccl')), + ) + self.val_loop_cfg = Config(val_loop_cfg) + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_init(self): + cfg = copy.deepcopy(self.val_loop_cfg) + cfg.experiment_name = 'test_init_self' + runner = Runner.from_cfg(cfg) + loop = runner.build_val_loop(cfg.val_cfg) + + self.assertIsInstance(loop, SelfDistillValLoop) + + def test_run(self): + cfg = copy.deepcopy(self.val_loop_cfg) + cfg.experiment_name = 'test_run_self' + runner = Runner.from_cfg(cfg) + runner.val() diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_evolution_search_loop.py b/cv/distiller/CWD/mmrazor/tests/test_runners/test_evolution_search_loop.py new file mode 100755 index 000000000..1dc2cf958 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_runners/test_evolution_search_loop.py @@ -0,0 +1,392 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +import shutil +import tempfile +from unittest import TestCase +from unittest.mock import MagicMock, patch + +import torch +import torch.nn as nn +from mmengine import fileio +from mmengine.config import Config +from torch.utils.data import DataLoader, Dataset + +from mmrazor.engine import EvolutionSearchLoop +from mmrazor.models import OneShotMutableOP +from mmrazor.registry import LOOPS +from mmrazor.structures import Candidates + + +def collate_fn(data_batch): + return data_batch + + +class ToyDataset(Dataset): + METAINFO = dict() # type: ignore + data = torch.randn(12, 2) + label = torch.ones(12) + + @property + def metainfo(self): + return self.METAINFO + + def __len__(self): + return self.data.size(0) + + def __getitem__(self, index): + return dict(inputs=self.data[index], data_sample=self.label[index]) + + +class ToyModel(nn.Module): + + def __init__(self): + super().__init__() + self.architecture = nn.Conv2d(1, 1, 1) + + def forward(self, x): + return self.architecture(x) + + +class ToyRunner: + + @property + def distributed(self): + pass + + @property + def rank(self): + pass + + @property + def epoch(self): + pass + + @property + def work_dir(self): + pass + + def model(self): + return ToyModel() + + def logger(self): + pass + + def call_hook(self, fn_name: str): + pass + + def visualizer(self): + pass + + +class TestEvolutionSearchLoop(TestCase): + + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + train_cfg = dict( + type='EvolutionSearchLoop', + max_epochs=4, + max_keep_ckpts=3, + resume_from=None, + num_candidates=4, + top_k=2, + num_mutation=2, + num_crossover=2, + mutate_prob=0.1, + constraints_range=dict(flops=(0, 330)), + score_key='coco/bbox_mAP') + self.train_cfg = Config(train_cfg) + self.runner = MagicMock(spec=ToyRunner) + self.runner.train_dataloader = MagicMock() + self.dataloader = DataLoader(ToyDataset(), collate_fn=collate_fn) + self.evaluator = MagicMock() + self.calibrate_bn_statistics = MagicMock() + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_init(self): + # test_init: dataloader and evaluator are instances + loop_cfg = copy.deepcopy(self.train_cfg) + loop_cfg.runner = self.runner + loop_cfg.dataloader = self.dataloader + loop_cfg.evaluator = self.evaluator + loop = LOOPS.build(loop_cfg) + self.assertIsInstance(loop, EvolutionSearchLoop) + + # test init_candidates is not None + fake_subnet = {'1': 'choice1', '2': 'choice2'} + fake_candidates = Candidates(fake_subnet) + init_candidates_path = os.path.join(self.temp_dir, 'candidates.yaml') + fileio.dump(fake_candidates, init_candidates_path) + loop_cfg.init_candidates = init_candidates_path + loop = LOOPS.build(loop_cfg) + self.assertIsInstance(loop, EvolutionSearchLoop) + self.assertEqual(loop.candidates, fake_candidates) + + @patch('mmrazor.structures.subnet.fix_subnet.load_fix_subnet') + @patch('mmrazor.structures.subnet.fix_subnet.export_fix_subnet') + @patch('mmrazor.models.task_modules.estimators.resource_estimator.' + 'get_model_flops_params') + def test_run_epoch(self, flops_params, mock_export_fix_subnet, + load_status): + # test_run_epoch: distributed == False + loop_cfg = copy.deepcopy(self.train_cfg) + loop_cfg.runner = self.runner + loop_cfg.dataloader = self.dataloader + loop_cfg.evaluator = self.evaluator + loop = LOOPS.build(loop_cfg) + self.runner.rank = 0 + self.runner.distributed = False + self.runner.work_dir = self.temp_dir + fake_subnet = {'1': 'choice1', '2': 'choice2'} + loop.model.mutator.sample_choices = MagicMock(return_value=fake_subnet) + mock_export_fix_subnet.return_value = (fake_subnet, self.runner.model) + load_status.return_value = True + flops_params.return_value = 0, 0 + loop.run_epoch() + self.assertEqual(len(loop.candidates), 4) + self.assertEqual(len(loop.top_k_candidates), 2) + self.assertEqual(loop._epoch, 1) + + # test_run_epoch: distributed == True + loop = LOOPS.build(loop_cfg) + self.runner.rank = 0 + self.runner.distributed = True + self.runner.work_dir = self.temp_dir + fake_subnet = {'1': 'choice1', '2': 'choice2'} + self.runner.model.mutator.sample_choices = MagicMock( + return_value=fake_subnet) + loop.run_epoch() + self.assertEqual(len(loop.candidates), 4) + self.assertEqual(len(loop.top_k_candidates), 2) + self.assertEqual(loop._epoch, 1) + + # test_check_constraints + loop_cfg.constraints_range = dict(params=(0, 100)) + loop = LOOPS.build(loop_cfg) + self.runner.rank = 0 + self.runner.distributed = True + self.runner.work_dir = self.temp_dir + fake_subnet = {'1': 'choice1', '2': 'choice2'} + loop.model.mutator.sample_choices = MagicMock(return_value=fake_subnet) + flops_params.return_value = (50., 1) + loop.run_epoch() + self.assertEqual(len(loop.candidates), 4) + self.assertEqual(len(loop.top_k_candidates), 2) + self.assertEqual(loop._epoch, 1) + + @patch('mmrazor.structures.subnet.fix_subnet.export_fix_subnet') + @patch('mmrazor.models.task_modules.estimators.resource_estimator.' + 'get_model_flops_params') + def test_run_loop(self, mock_flops, mock_export_fix_subnet): + # test a new search: resume == None + loop_cfg = copy.deepcopy(self.train_cfg) + loop_cfg.runner = self.runner + loop_cfg.dataloader = self.dataloader + loop_cfg.evaluator = self.evaluator + loop = LOOPS.build(loop_cfg) + self.runner.rank = 0 + loop._epoch = 1 + + fake_subnet = {'1': 'choice1', '2': 'choice2'} + mock_export_fix_subnet.return_value = (fake_subnet, self.runner.model) + self.runner.work_dir = self.temp_dir + loop.update_candidate_pool = MagicMock() + loop.val_candidate_pool = MagicMock() + + mutation_candidates = Candidates([fake_subnet] * loop.num_mutation) + for i in range(loop.num_mutation): + mutation_candidates.set_resource(i, 0.1 + 0.1 * i, 'flops') + mutation_candidates.set_resource(i, 99 + i, 'score') + crossover_candidates = Candidates([fake_subnet] * loop.num_crossover) + for i in range(loop.num_crossover): + crossover_candidates.set_resource(i, 0.1 + 0.1 * i, 'flops') + crossover_candidates.set_resource(i, 99 + i, 'score') + loop.gen_mutation_candidates = \ + MagicMock(return_value=mutation_candidates) + loop.gen_crossover_candidates = \ + MagicMock(return_value=crossover_candidates) + loop.candidates = Candidates([fake_subnet] * 4) + mock_flops.return_value = (0.5, 101) + torch.save = MagicMock() + loop.run() + assert os.path.exists( + os.path.join(self.temp_dir, 'best_fix_subnet.yaml')) + self.assertEqual(loop._epoch, loop._max_epochs) + assert os.path.exists( + os.path.join(self.temp_dir, + f'search_epoch_{loop._max_epochs-1}.pkl')) + # test resuming search + loop_cfg.resume_from = os.path.join( + self.temp_dir, f'search_epoch_{loop._max_epochs-1}.pkl') + loop = LOOPS.build(loop_cfg) + self.runner.rank = 0 + loop.run() + self.assertEqual(loop._max_epochs, 1) + + +class TestEvolutionSearchLoopWithPredictor(TestCase): + + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + convs = nn.ModuleDict({ + 'conv1': nn.Conv2d(3, 8, 1), + 'conv2': nn.Conv2d(3, 8, 1), + 'conv3': nn.Conv2d(3, 8, 1), + }) + MutableOP = OneShotMutableOP(convs) + self.search_groups = {0: [MutableOP], 1: [MutableOP]} + train_cfg = dict( + type='EvolutionSearchLoop', + max_epochs=4, + max_keep_ckpts=3, + resume_from=None, + num_candidates=4, + top_k=2, + num_mutation=2, + num_crossover=2, + mutate_prob=0.1, + constraints_range=dict(flops=(0, 330)), + score_key='bbox_mAP', + predictor_cfg=dict( + type='MetricPredictor', + handler_cfg=dict(type='GaussProcessHandler'), + search_groups=self.search_groups, + train_samples=4, + )) + self.train_cfg = Config(train_cfg) + self.runner = MagicMock(spec=ToyRunner) + self.runner.train_dataloader = MagicMock() + self.dataloader = DataLoader(ToyDataset(), collate_fn=collate_fn) + self.evaluator = MagicMock() + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_init(self): + # test_init: dataloader and evaluator are instances + loop_cfg = copy.deepcopy(self.train_cfg) + loop_cfg.runner = self.runner + loop_cfg.dataloader = self.dataloader + loop_cfg.evaluator = self.evaluator + loop = LOOPS.build(loop_cfg) + self.assertIsInstance(loop, EvolutionSearchLoop) + + # test init_candidates is not None + fake_subnet = {'1': 'choice1', '2': 'choice2'} + fake_candidates = Candidates(fake_subnet) + init_candidates_path = os.path.join(self.temp_dir, 'candidates.yaml') + fileio.dump(fake_candidates, init_candidates_path) + loop_cfg.init_candidates = init_candidates_path + loop = LOOPS.build(loop_cfg) + self.assertIsInstance(loop, EvolutionSearchLoop) + self.assertEqual(loop.candidates, fake_candidates) + + @patch('mmrazor.structures.subnet.fix_subnet.load_fix_subnet') + @patch('mmrazor.structures.subnet.fix_subnet.export_fix_subnet') + @patch('mmrazor.models.task_modules.estimators.resource_estimator.' + 'get_model_flops_params') + def test_run_epoch(self, flops_params, mock_export_fix_subnet, + load_status): + loop_cfg = copy.deepcopy(self.train_cfg) + loop_cfg.runner = self.runner + loop_cfg.dataloader = self.dataloader + loop_cfg.evaluator = self.evaluator + loop = LOOPS.build(loop_cfg) + self.runner.rank = 0 + self.runner.distributed = False + self.runner.work_dir = self.temp_dir + fake_subnet = {'1': 'choice1', '2': 'choice2'} + loop.model.mutator.sample_choices = MagicMock(return_value=fake_subnet) + mock_export_fix_subnet.return_value = (fake_subnet, self.runner.model) + load_status.return_value = True + flops_params.return_value = 0, 0 + loop.run_epoch() + self.assertEqual(len(loop.candidates), 4) + self.assertEqual(len(loop.top_k_candidates), 2) + self.assertEqual(loop._epoch, 1) + + # test_run_epoch: distributed == True + loop = LOOPS.build(loop_cfg) + self.runner.rank = 0 + self.runner.distributed = True + self.runner.work_dir = self.temp_dir + fake_subnet = {'1': 'choice1', '2': 'choice2'} + self.runner.model.mutator.sample_choices = MagicMock( + return_value=fake_subnet) + loop.run_epoch() + self.assertEqual(len(loop.candidates), 4) + self.assertEqual(len(loop.top_k_candidates), 2) + self.assertEqual(loop._epoch, 1) + + # test_check_constraints + loop_cfg.constraints_range = dict(params=(0, 100)) + loop = LOOPS.build(loop_cfg) + self.runner.rank = 0 + self.runner.distributed = True + self.runner.work_dir = self.temp_dir + fake_subnet = {'1': 'choice1', '2': 'choice2'} + loop.model.mutator.sample_choices = MagicMock(return_value=fake_subnet) + flops_params.return_value = (50., 1) + loop.run_epoch() + self.assertEqual(len(loop.candidates), 4) + self.assertEqual(len(loop.top_k_candidates), 2) + self.assertEqual(loop._epoch, 1) + + @patch('mmrazor.structures.subnet.fix_subnet.export_fix_subnet') + @patch('mmrazor.models.task_modules.predictor.metric_predictor.' + 'MetricPredictor.model2vector') + @patch('mmrazor.models.task_modules.estimators.resource_estimator.' + 'get_model_flops_params') + def test_run_loop(self, mock_flops, mock_model2vector, + mock_export_fix_subnet): + # test a new search: resume == None + loop_cfg = copy.deepcopy(self.train_cfg) + loop_cfg.runner = self.runner + loop_cfg.dataloader = self.dataloader + loop_cfg.evaluator = self.evaluator + loop = LOOPS.build(loop_cfg) + self.runner.rank = 0 + loop._epoch = 1 + + fake_subnet = {'1': 'choice1', '2': 'choice2'} + loop.model.mutator.sample_choices = MagicMock(return_value=fake_subnet) + mock_export_fix_subnet.return_value = (fake_subnet, self.runner.model) + + self.runner.work_dir = self.temp_dir + loop.update_candidate_pool = MagicMock() + loop.val_candidate_pool = MagicMock() + + mutation_candidates = Candidates([fake_subnet] * loop.num_mutation) + for i in range(loop.num_mutation): + mutation_candidates.set_resource(i, 0.1 + 0.1 * i, 'flops') + mutation_candidates.set_resource(i, 99 + i, 'score') + crossover_candidates = Candidates([fake_subnet] * loop.num_crossover) + for i in range(loop.num_crossover): + crossover_candidates.set_resource(i, 0.1 + 0.1 * i, 'flops') + crossover_candidates.set_resource(i, 99 + i, 'score') + loop.gen_mutation_candidates = \ + MagicMock(return_value=mutation_candidates) + loop.gen_crossover_candidates = \ + MagicMock(return_value=crossover_candidates) + loop.candidates = Candidates([fake_subnet] * 4) + + mock_flops.return_value = (0.5, 101) + mock_model2vector.return_value = dict( + normal_vector=[0, 1], onehot_vector=[0, 1, 0, 1]) + torch.save = MagicMock() + loop.run() + assert os.path.exists( + os.path.join(self.temp_dir, 'best_fix_subnet.yaml')) + self.assertEqual(loop._epoch, loop._max_epochs) + assert os.path.exists( + os.path.join(self.temp_dir, + f'search_epoch_{loop._max_epochs-1}.pkl')) + # test resuming search + loop_cfg.resume_from = os.path.join( + self.temp_dir, f'search_epoch_{loop._max_epochs-1}.pkl') + loop = LOOPS.build(loop_cfg) + self.runner.rank = 0 + loop.run() + self.assertEqual(loop._max_epochs, 1) diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_quantization_loop.py b/cv/distiller/CWD/mmrazor/tests/test_runners/test_quantization_loop.py new file mode 100755 index 000000000..6a300fb91 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_runners/test_quantization_loop.py @@ -0,0 +1,413 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import logging +import shutil +import tempfile +from unittest import TestCase + +import torch +import torch.nn as nn +from mmengine.config import Config, ConfigDict +from mmengine.evaluator import BaseMetric +from mmengine.hooks import Hook +from mmengine.logging import MMLogger +from mmengine.model import BaseModel +from mmengine.optim import OptimWrapper +from mmengine.registry import DATASETS, HOOKS, METRICS, MODELS, OPTIM_WRAPPERS +from mmengine.runner import Runner +from torch.nn.intrinsic.qat import ConvBnReLU2d +from torch.utils.data import Dataset + +from mmrazor import digit_version +from mmrazor.engine import (LSQEpochBasedLoop, PTQLoop, QATEpochBasedLoop, + QATValLoop) + +try: + from torch.ao.nn.quantized import FloatFunctional, FXFloatFunctional + from torch.ao.quantization import QConfigMapping + from torch.ao.quantization.fake_quantize import FakeQuantizeBase + from torch.ao.quantization.fx import prepare + from torch.ao.quantization.qconfig_mapping import \ + get_default_qconfig_mapping + from torch.ao.quantization.quantize_fx import _fuse_fx +except ImportError: + from mmrazor.utils import get_placeholder + QConfigMapping = get_placeholder('torch>=1.13') + FakeQuantizeBase = get_placeholder('torch>=1.13') + prepare = get_placeholder('torch>=1.13') + _fuse_fx = get_placeholder('torch>=1.13') + get_default_qconfig_mapping = get_placeholder('torch>=1.13') + FloatFunctional = get_placeholder('torch>=1.13') + FXFloatFunctional = get_placeholder('torch>=1.13') + + +class ToyDataset(Dataset): + METAINFO = dict() # type: ignore + data = torch.randn(12, 3, 4, 4) + label = torch.ones(12) + + @property + def metainfo(self): + return self.METAINFO + + def __len__(self): + return self.data.size(0) + + def __getitem__(self, index): + return dict(inputs=self.data[index], data_sample=self.label[index]) + + +class MMArchitectureQuant(BaseModel): + + def __init__(self, data_preprocessor=None): + super().__init__(data_preprocessor=data_preprocessor) + self.architecture = ToyModel() + + def calibrate_step(self, data): + data = self.data_preprocessor(data, False) + return self.architecture(**data) + + def sync_qparams(self, src_mode): + pass + + def forward(self, inputs, data_sample, mode='tensor'): + return self.architecture(inputs, data_sample, mode) + + +class ToyModel(BaseModel): + + def __init__(self, data_preprocessor=None): + super().__init__(data_preprocessor=data_preprocessor) + qconfig = get_default_qconfig_mapping().to_dict()[''] + self.architecture = nn.Sequential( + ConvBnReLU2d(3, 3, 1, qconfig=qconfig)) + + def forward(self, inputs, data_sample, mode='tensor'): + if isinstance(inputs, list): + inputs = torch.stack(inputs) + if isinstance(data_sample, list): + data_sample = torch.stack(data_sample) + outputs = self.architecture(inputs) + + if mode == 'tensor': + return outputs + elif mode == 'loss': + loss = data_sample.sum() - outputs.sum() + outputs = dict(loss=loss) + return outputs + elif mode == 'predict': + return outputs + + +class ToyOptimWrapper(OptimWrapper): + ... + + +class ToyMetric1(BaseMetric): + + def __init__(self, collect_device='cpu', dummy_metrics=None): + super().__init__(collect_device=collect_device) + self.dummy_metrics = dummy_metrics + + def process(self, data_batch, predictions): + result = {'acc': 1} + self.results.append(result) + + def compute_metrics(self, results): + return dict(acc=1) + + +DEFAULT_CFG = ConfigDict( + model=dict(type='MMArchitectureQuant'), + train_dataloader=dict( + dataset=dict(type='ToyDataset'), + sampler=dict(type='DefaultSampler', shuffle=True), + batch_size=3, + num_workers=0), + val_dataloader=dict( + dataset=dict(type='ToyDataset'), + sampler=dict(type='DefaultSampler', shuffle=False), + batch_size=3, + num_workers=0), + test_dataloader=dict( + dataset=dict(type='ToyDataset'), + sampler=dict(type='DefaultSampler', shuffle=False), + batch_size=3, + num_workers=0), + optim_wrapper=dict( + type='OptimWrapper', optimizer=dict(type='SGD', lr=0.01)), + val_evaluator=dict(type='ToyMetric1'), + test_evaluator=dict(type='ToyMetric1'), + train_cfg=dict(), + val_cfg=dict(), + test_cfg=dict(), + custom_hooks=[], + data_preprocessor=None, + launcher='none', + env_cfg=dict(dist_cfg=dict(backend='nccl')), +) + + +class TestQATEpochBasedLoop(TestCase): + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + self.temp_dir = tempfile.mkdtemp() + MODELS.register_module(module=MMArchitectureQuant, force=True) + DATASETS.register_module(module=ToyDataset, force=True) + METRICS.register_module(module=ToyMetric1, force=True) + OPTIM_WRAPPERS.register_module(module=ToyOptimWrapper, force=True) + + default_cfg = copy.deepcopy(DEFAULT_CFG) + default_cfg = Config(default_cfg) + default_cfg.work_dir = self.temp_dir + default_cfg.train_cfg = ConfigDict( + type='mmrazor.QATEpochBasedLoop', + max_epochs=4, + val_begin=1, + val_interval=1, + disable_observer_begin=-1, + freeze_bn_begin=-1, + dynamic_intervals=None) + self.default_cfg = default_cfg + + def tearDown(self): + MODELS.module_dict.pop('MMArchitectureQuant') + DATASETS.module_dict.pop('ToyDataset') + METRICS.module_dict.pop('ToyMetric1') + OPTIM_WRAPPERS.module_dict.pop('ToyOptimWrapper') + + logging.shutdown() + MMLogger._instance_dict.clear() + shutil.rmtree(self.temp_dir) + + def test_init(self): + cfg = copy.deepcopy(self.default_cfg) + cfg.experiment_name = 'test_init_qat_train_loop' + runner = Runner(**cfg) + self.assertIsInstance(runner, Runner) + self.assertIsInstance(runner.train_loop, QATEpochBasedLoop) + + def test_run_epoch(self): + cfg = copy.deepcopy(self.default_cfg) + cfg.experiment_name = 'test_train' + runner = Runner.from_cfg(cfg) + runner.train() + + @HOOKS.register_module(force=True) + class TestFreezeBNHook(Hook): + + def __init__(self, freeze_bn_begin): + self.freeze_bn_begin = freeze_bn_begin + + def after_train_epoch(self, runner): + + def check_bn_stats(mod): + if isinstance(mod, ConvBnReLU2d): + assert mod.freeze_bn + assert not mod.bn.training + + if runner.train_loop._epoch + 1 >= self.freeze_bn_begin: + runner.model.apply(check_bn_stats) + + cfg = copy.deepcopy(self.default_cfg) + cfg.experiment_name = 'test_freeze_bn' + cfg.custom_hooks = [ + dict(type='TestFreezeBNHook', priority=50, freeze_bn_begin=1) + ] + cfg.train_cfg.freeze_bn_begin = 1 + runner = Runner.from_cfg(cfg) + runner.train() + + @HOOKS.register_module(force=True) + class TestDisableObserverHook(Hook): + + def __init__(self, disable_observer_begin): + self.disable_observer_begin = disable_observer_begin + + def after_train_epoch(self, runner): + + def check_observer_stats(mod): + if isinstance(mod, FakeQuantizeBase): + assert mod.fake_quant_enabled[0] == 0 + + if runner.train_loop._epoch + 1 >= self.disable_observer_begin: + runner.model.apply(check_observer_stats) + + cfg = copy.deepcopy(self.default_cfg) + cfg.experiment_name = 'test_disable_observer' + cfg.custom_hooks = [ + dict( + type='TestDisableObserverHook', + priority=50, + disable_observer_begin=1) + ] + cfg.train_cfg.disable_observer_begin = 1 + runner = Runner.from_cfg(cfg) + runner.train() + + +class TestLSQEpochBasedLoop(TestCase): + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + self.temp_dir = tempfile.mkdtemp() + MODELS.register_module(module=MMArchitectureQuant, force=True) + DATASETS.register_module(module=ToyDataset, force=True) + METRICS.register_module(module=ToyMetric1, force=True) + OPTIM_WRAPPERS.register_module(module=ToyOptimWrapper, force=True) + + default_cfg = copy.deepcopy(DEFAULT_CFG) + default_cfg = Config(default_cfg) + default_cfg.work_dir = self.temp_dir + default_cfg.train_cfg = ConfigDict( + type='mmrazor.LSQEpochBasedLoop', + max_epochs=4, + val_begin=1, + val_interval=1, + freeze_bn_begin=-1, + dynamic_intervals=None) + self.default_cfg = default_cfg + + def tearDown(self): + MODELS.module_dict.pop('MMArchitectureQuant') + DATASETS.module_dict.pop('ToyDataset') + METRICS.module_dict.pop('ToyMetric1') + OPTIM_WRAPPERS.module_dict.pop('ToyOptimWrapper') + + logging.shutdown() + MMLogger._instance_dict.clear() + shutil.rmtree(self.temp_dir) + + def test_init(self): + cfg = copy.deepcopy(self.default_cfg) + cfg.experiment_name = 'test_init_lsq_train_loop' + runner = Runner(**cfg) + self.assertIsInstance(runner, Runner) + self.assertIsInstance(runner.train_loop, LSQEpochBasedLoop) + + def test_run_epoch(self): + cfg = copy.deepcopy(self.default_cfg) + cfg.experiment_name = 'test_train' + runner = Runner.from_cfg(cfg) + runner.train() + + @HOOKS.register_module(force=True) + class TestFreezeBNHook(Hook): + + def __init__(self, freeze_bn_begin): + self.freeze_bn_begin = freeze_bn_begin + + def after_train_epoch(self, runner): + + def check_bn_stats(mod): + if isinstance(mod, ConvBnReLU2d): + assert mod.freeze_bn + assert not mod.bn.training + + if runner.train_loop._epoch + 1 >= self.freeze_bn_begin: + runner.model.apply(check_bn_stats) + + cfg = copy.deepcopy(self.default_cfg) + cfg.experiment_name = 'test_freeze_bn' + cfg.custom_hooks = [ + dict(type='TestFreezeBNHook', priority=50, freeze_bn_begin=1) + ] + cfg.train_cfg.freeze_bn_begin = 1 + runner = Runner.from_cfg(cfg) + runner.train() + + +class TestQATValLoop(TestCase): + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + self.temp_dir = tempfile.mkdtemp() + MODELS.register_module(module=MMArchitectureQuant, force=True) + DATASETS.register_module(module=ToyDataset, force=True) + METRICS.register_module(module=ToyMetric1, force=True) + OPTIM_WRAPPERS.register_module(module=ToyOptimWrapper, force=True) + + default_cfg = copy.deepcopy(DEFAULT_CFG) + default_cfg = Config(default_cfg) + default_cfg.work_dir = self.temp_dir + default_cfg.val_cfg = ConfigDict(type='mmrazor.QATValLoop') + self.default_cfg = default_cfg + + def tearDown(self): + MODELS.module_dict.pop('MMArchitectureQuant') + DATASETS.module_dict.pop('ToyDataset') + METRICS.module_dict.pop('ToyMetric1') + OPTIM_WRAPPERS.module_dict.pop('ToyOptimWrapper') + + logging.shutdown() + MMLogger._instance_dict.clear() + shutil.rmtree(self.temp_dir) + + def test_init(self): + cfg = copy.deepcopy(self.default_cfg) + cfg.experiment_name = 'test_init_qat_val_loop' + runner = Runner(**cfg) + self.assertIsInstance(runner, Runner) + self.assertIsInstance(runner.val_loop, QATValLoop) + + def test_run(self): + cfg = copy.deepcopy(self.default_cfg) + cfg.experiment_name = 'test_qat_val' + cfg.pop('train_dataloader') + cfg.pop('train_cfg') + cfg.pop('optim_wrapper') + cfg.pop('test_dataloader') + cfg.pop('test_cfg') + cfg.pop('test_evaluator') + runner = Runner.from_cfg(cfg) + runner.val() + + +class TestPTQLoop(TestCase): + + def setUp(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + self.temp_dir = tempfile.mkdtemp() + MODELS.register_module(module=MMArchitectureQuant, force=True) + DATASETS.register_module(module=ToyDataset, force=True) + METRICS.register_module(module=ToyMetric1, force=True) + OPTIM_WRAPPERS.register_module(module=ToyOptimWrapper, force=True) + + default_cfg = copy.deepcopy(DEFAULT_CFG) + default_cfg = Config(default_cfg) + default_cfg.work_dir = self.temp_dir + # save_checkpoint in PTQLoop need train_dataloader + default_cfg.train_cfg = ConfigDict(by_epoch=True, max_epochs=3) + default_cfg.test_cfg = ConfigDict( + type='mmrazor.PTQLoop', + calibrate_dataloader=default_cfg.train_dataloader, + calibrate_steps=32) + self.default_cfg = default_cfg + + def tearDown(self): + MODELS.module_dict.pop('MMArchitectureQuant') + DATASETS.module_dict.pop('ToyDataset') + METRICS.module_dict.pop('ToyMetric1') + OPTIM_WRAPPERS.module_dict.pop('ToyOptimWrapper') + + logging.shutdown() + MMLogger._instance_dict.clear() + shutil.rmtree(self.temp_dir) + + def test_init(self): + cfg = copy.deepcopy(self.default_cfg) + cfg.experiment_name = 'test_init_ptq_loop' + runner = Runner(**cfg) + self.assertIsInstance(runner, Runner) + self.assertIsInstance(runner.test_loop, PTQLoop) + + def test_run(self): + cfg = copy.deepcopy(self.default_cfg) + cfg.experiment_name = 'test_ptq_run' + runner = Runner.from_cfg(cfg) + runner.test() diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_subnet_sampler_loop.py b/cv/distiller/CWD/mmrazor/tests/test_runners/test_subnet_sampler_loop.py new file mode 100755 index 000000000..02c3a90d5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_runners/test_subnet_sampler_loop.py @@ -0,0 +1,207 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +import os +import shutil +import tempfile +from unittest import TestCase +from unittest.mock import MagicMock, patch + +import torch +import torch.nn as nn +from mmengine.config import Config +from mmengine.evaluator import BaseMetric +from mmengine.model import BaseModel +from mmengine.runner import Runner +from torch.utils.data import Dataset + +from mmrazor.engine import GreedySamplerTrainLoop # noqa: F401 +from mmrazor.registry import DATASETS, METRICS, MODELS + + +@MODELS.register_module() +class ToyModel_GreedySamplerTrainLoop(BaseModel): + + @patch('mmrazor.models.mutators.NasMutator') + def __init__(self, mock_mutator): + super().__init__() + self.linear1 = nn.Linear(2, 2) + self.linear2 = nn.Linear(2, 1) + self.mutator = mock_mutator + + def forward(self, inputs, data_samples, mode='tensor'): + batch_inputs = torch.stack(inputs) + labels = torch.stack(data_samples) + outputs = self.linear1(batch_inputs) + outputs = self.linear2(outputs) + + if mode == 'tensor': + return outputs + elif mode == 'loss': + loss = (labels - outputs).sum() + outputs = dict(loss=loss) + return outputs + elif mode == 'predict': + outputs = dict(log_vars=dict(a=1, b=0.5)) + return outputs + + def sample_subnet(self): + return self.mutator.sample_choices() + + def set_subnet(self, subnet): + self.mutator.set_choices(subnet) + + def export_fix_subnet(self): + pass + + +@DATASETS.register_module() +class ToyDataset_GreedySamplerTrainLoop(Dataset): + METAINFO = dict() # type: ignore + data = torch.randn(12, 2) + label = torch.ones(12) + + @property + def metainfo(self): + return self.METAINFO + + def __len__(self): + return self.data.size(0) + + def __getitem__(self, index): + return dict(inputs=self.data[index], data_samples=self.label[index]) + + +@METRICS.register_module() +class ToyMetric_GreedySamplerTrainLoop(BaseMetric): + + def __init__(self, collect_device='cpu', dummy_metrics=None): + super().__init__(collect_device=collect_device) + self.dummy_metrics = dummy_metrics + + def process(self, data_samples, predictions): + result = {'acc': 1} + self.results.append(result) + + def compute_metrics(self, results): + return dict(acc=1) + + +class TestGreedySamplerTrainLoop(TestCase): + + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + + val_dataloader = dict( + dataset=dict(type='ToyDataset_GreedySamplerTrainLoop'), + sampler=dict(type='DefaultSampler', shuffle=False), + batch_size=3, + num_workers=0) + val_evaluator = dict(type='ToyMetric_GreedySamplerTrainLoop') + + iter_based_cfg = dict( + default_scope='mmrazor', + model=dict(type='ToyModel_GreedySamplerTrainLoop'), + work_dir=self.temp_dir, + train_dataloader=dict( + dataset=dict(type='ToyDataset_GreedySamplerTrainLoop'), + sampler=dict(type='InfiniteSampler', shuffle=True), + batch_size=3, + num_workers=0), + val_dataloader=val_dataloader, + optim_wrapper=dict( + type='OptimWrapper', optimizer=dict(type='SGD', lr=0.01)), + param_scheduler=dict(type='MultiStepLR', milestones=[1, 2]), + val_evaluator=val_evaluator, + train_cfg=dict( + type='GreedySamplerTrainLoop', + dataloader_val=val_dataloader, + evaluator=val_evaluator, + max_iters=12, + val_interval=2, + score_key='acc', + constraints_range=None, + num_candidates=4, + num_samples=2, + top_k=2, + prob_schedule='linear', + schedule_start_iter=4, + schedule_end_iter=10, + init_prob=0., + max_prob=0.8), + val_cfg=dict(), + custom_hooks=[], + default_hooks=dict( + runtime_info=dict(type='RuntimeInfoHook'), + timer=dict(type='IterTimerHook'), + logger=dict(type='LoggerHook'), + param_scheduler=dict(type='ParamSchedulerHook'), + checkpoint=dict( + type='CheckpointHook', interval=1, by_epoch=False), + sampler_seed=dict(type='DistSamplerSeedHook')), + launcher='none', + env_cfg=dict(dist_cfg=dict(backend='nccl')), + ) + self.iter_based_cfg = Config(iter_based_cfg) + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def test_init(self): + cfg = copy.deepcopy(self.iter_based_cfg) + cfg.experiment_name = 'test_init_GreedySamplerTrainLoop' + runner = Runner.from_cfg(cfg) + loop = runner.build_train_loop(cfg.train_cfg) + self.assertIsInstance(loop, GreedySamplerTrainLoop) + + def test_update_cur_prob(self): + # prob_schedule = linear + cfg = copy.deepcopy(self.iter_based_cfg) + cfg.experiment_name = 'test_update_cur_prob1' + runner = Runner.from_cfg(cfg) + loop = runner.build_train_loop(cfg.train_cfg) + + loop.update_cur_prob(loop.schedule_end_iter - 1) + self.assertGreater(loop.max_prob, loop.cur_prob) + loop.update_cur_prob(loop.schedule_end_iter + 1) + self.assertEqual(loop.max_prob, loop.cur_prob) + + # prob_schedule = consine + cfg = copy.deepcopy(self.iter_based_cfg) + cfg.experiment_name = 'test_update_cur_prob2' + cfg.train_cfg.prob_schedule = 'consine' + runner = Runner.from_cfg(cfg) + loop = runner.build_train_loop(cfg.train_cfg) + + loop.update_cur_prob(loop.schedule_end_iter - 1) + self.assertGreater(loop.max_prob, loop.cur_prob) + loop.update_cur_prob(loop.schedule_end_iter + 1) + self.assertEqual(loop.max_prob, loop.cur_prob) + + def test_sample_subnet(self): + cfg = copy.deepcopy(self.iter_based_cfg) + cfg.experiment_name = 'test_sample_subnet' + runner = Runner.from_cfg(cfg) + fake_subnet = {'1': 'choice1', '2': 'choice2'} + runner.model.sample_subnet = MagicMock(return_value=fake_subnet) + loop = runner.build_train_loop(cfg.train_cfg) + loop.cur_prob = loop.max_prob + self.assertEqual(len(loop.top_k_candidates), 0) + + loop._iter = loop.val_interval + subnet = loop.sample_subnet() + self.assertEqual(subnet, fake_subnet) + self.assertEqual(len(loop.top_k_candidates), loop.top_k) + + def test_run(self): + # test run with _check_constraints + cfg = copy.deepcopy(self.iter_based_cfg) + cfg.experiment_name = 'test_run1' + runner = Runner.from_cfg(cfg) + fake_subnet = {'1': 'choice1', '2': 'choice2'} + runner.model.sample_subnet = MagicMock(return_value=fake_subnet) + loop = runner.build_train_loop(cfg.train_cfg) + loop._check_constraints = MagicMock(return_value=(True, dict())) + runner.train() + + self.assertEqual(runner.iter, runner.max_iters) + assert os.path.exists(os.path.join(self.temp_dir, 'candidates.pkl')) diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_calibrate_bn_mixin.py b/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_calibrate_bn_mixin.py new file mode 100755 index 000000000..ce482c268 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_calibrate_bn_mixin.py @@ -0,0 +1,83 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from logging import Logger +from typing import Sequence +from unittest import TestCase + +import torch +from torch import Tensor, nn +from torch.utils.data import DataLoader, Dataset + +from mmrazor.engine.runner.utils import CalibrateBNMixin + + +class ToyModel(nn.Module): + + def __init__(self) -> None: + super().__init__() + + self.bn = nn.BatchNorm2d(3) + + def forward(self, x: Tensor) -> Tensor: + return self.bn(x) + + def test_step(self, x: Tensor) -> None: + self(x) + + +class ToyRunner: + + def __init__(self) -> None: + self.model = ToyModel() + self.logger = Logger('calibrate test logger') + + +class ToyValLoop(CalibrateBNMixin): + + def __init__(self) -> None: + self.fp16 = False + self.runner = ToyRunner() + + +class FakeDataset(Dataset): + + def __init__(self, + random_nums: int = 64, + x_shape: Sequence[int] = (3, 224, 224)) -> None: + self.random_x = torch.normal(1, 100, size=(random_nums, *x_shape)) + self.random_nums = random_nums + self.x_shape = list(x_shape) + + def __getitem__(self, index: int) -> Tensor: + return self.random_x[index] + + def __len__(self) -> int: + return self.random_nums + + @property + def data(self) -> Tensor: + return self.random_x + + +class TestCalibrateBNMixin(TestCase): + + def test_calibrate_bn_statistics(self) -> None: + dataloader = self.prepare_dataloader(random_nums=2000) + loop = ToyValLoop() + loop.calibrate_bn_statistics(dataloader, 2000) + + calibrated_data = dataloader.dataset.data + calibrated_mean = calibrated_data.mean((0, 2, 3)) + calibrated_var = calibrated_data.var((0, 2, 3), unbiased=True) + + assert torch.allclose(calibrated_mean, + loop.runner.model.bn.running_mean) + assert torch.allclose(calibrated_var, loop.runner.model.bn.running_var) + + def prepare_dataloader( + self, + random_nums: int = 2000, + x_shape: Sequence[int] = (3, 224, 224) + ) -> DataLoader: + dataset = FakeDataset(random_nums=random_nums, x_shape=x_shape) + + return DataLoader(dataset, batch_size=64) diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_check.py b/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_check.py new file mode 100755 index 000000000..2f3a80eaa --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_check.py @@ -0,0 +1,44 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest.mock import patch + +from mmrazor.engine.runner.utils import check_subnet_resources + +try: + from mmdet.models.detectors import BaseDetector +except ImportError: + from mmrazor.utils import get_placeholder + BaseDetector = get_placeholder('mmdet') + + +@patch('mmrazor.models.ResourceEstimator') +@patch('mmrazor.models.SPOS') +def test_check_subnet_resources(mock_model, mock_estimator): + # constraints_range = dict() + constraints_range = dict() + fake_subnet = {'1': 'choice1', '2': 'choice2'} + is_pass, _ = check_subnet_resources(mock_model, fake_subnet, + mock_estimator, constraints_range) + assert is_pass is True + + # constraints_range is not None + # architecturte is BaseDetector + constraints_range = dict(flops=(0, 330)) + mock_model.architecture = BaseDetector + fake_results = {'flops': 50.} + mock_estimator.estimate.return_value = fake_results + is_pass, _ = check_subnet_resources( + mock_model, + fake_subnet, + mock_estimator, + constraints_range, + ) + assert is_pass is True + + # constraints_range is not None + # architecturte is BaseDetector + constraints_range = dict(flops=(0, 330)) + fake_results = {'flops': -50.} + mock_estimator.estimate.return_value = fake_results + is_pass, _ = check_subnet_resources(mock_model, fake_subnet, + mock_estimator, constraints_range) + assert is_pass is False diff --git a/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_genetic.py b/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_genetic.py new file mode 100755 index 000000000..04f46e24a --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_runners/test_utils/test_genetic.py @@ -0,0 +1,15 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmrazor.engine.runner.utils import crossover + + +def test_crossover(): + fake_random_subnet1 = {} + fake_random_subnet2 = {} + for i in range(50): + fake_random_subnet1[i] = f'{i}_choice1' + fake_random_subnet2[i] = f'{i}_choice2' + + result = crossover(fake_random_subnet1, fake_random_subnet2) + + assert type(result) == type(fake_random_subnet1) + assert len(result) == len(fake_random_subnet1) diff --git a/cv/distiller/CWD/mmrazor/tests/test_structures/test_backendconfig.py b/cv/distiller/CWD/mmrazor/tests/test_structures/test_backendconfig.py new file mode 100755 index 000000000..24295e391 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_structures/test_backendconfig.py @@ -0,0 +1,62 @@ +# Copyright (c) OpenMMLab. All rights reserved. +try: + from torch.ao.quantization.backend_config import BackendConfig +except ImportError: + from mmrazor.utils import get_placeholder + BackendConfig = get_placeholder('torch>=1.13') + +import pytest +import torch + +from mmrazor import digit_version +from mmrazor.structures.quantization.backend_config import ( + BackendConfigs, get_academic_backend_config, + get_academic_backend_config_dict, get_native_backend_config, + get_native_backend_config_dict, get_openvino_backend_config, + get_openvino_backend_config_dict, get_tensorrt_backend_config, + get_tensorrt_backend_config_dict) + + +@pytest.mark.skipif( + digit_version(torch.__version__) < digit_version('1.13.0'), + reason='version of torch < 1.13.0') +def test_get_backend_config(): + + # test get_native_backend_config + native_backend_config = get_native_backend_config() + assert isinstance(native_backend_config, BackendConfig) + assert native_backend_config.name == 'native' + native_backend_config_dict = get_native_backend_config_dict() + assert isinstance(native_backend_config_dict, dict) + + # test get_academic_backend_config + academic_backend_config = get_academic_backend_config() + assert isinstance(academic_backend_config, BackendConfig) + assert academic_backend_config.name == 'academic' + academic_backend_config_dict = get_academic_backend_config_dict() + assert isinstance(academic_backend_config_dict, dict) + + # test get_openvino_backend_config + openvino_backend_config = get_openvino_backend_config() + assert isinstance(openvino_backend_config, BackendConfig) + assert openvino_backend_config.name == 'openvino' + openvino_backend_config_dict = get_openvino_backend_config_dict() + assert isinstance(openvino_backend_config_dict, dict) + + # test get_tensorrt_backend_config + tensorrt_backend_config = get_tensorrt_backend_config() + assert isinstance(tensorrt_backend_config, BackendConfig) + assert tensorrt_backend_config.name == 'tensorrt' + tensorrt_backend_config_dict = get_tensorrt_backend_config_dict() + assert isinstance(tensorrt_backend_config_dict, dict) + + +@pytest.mark.skipif( + digit_version(torch.__version__) < digit_version('1.13.0'), + reason='version of torch < 1.13.0') +def test_backendconfigs_mapping(): + + mapping = BackendConfigs + assert isinstance(mapping, dict) + assert 'academic' in mapping.keys() + assert isinstance(mapping['academic'], BackendConfig) diff --git a/cv/distiller/CWD/mmrazor/tests/test_structures/test_qconfig.py b/cv/distiller/CWD/mmrazor/tests/test_structures/test_qconfig.py new file mode 100755 index 000000000..7ab78243d --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_structures/test_qconfig.py @@ -0,0 +1,172 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import copy +from unittest import TestCase + +import torch +from mmengine.config import Config + +try: + from torch.ao.quantization import FakeQuantize, QConfig +except ImportError: + from mmrazor.utils import get_placeholder + QConfig = get_placeholder('torch>=1.13') + FakeQuantize = get_placeholder('torch>=1.13') + +from mmrazor import digit_version +from mmrazor.models.fake_quants import register_torch_fake_quants +from mmrazor.models.observers import register_torch_observers +from mmrazor.registry import MODELS +from mmrazor.structures import QConfigHandler, QSchemeHandler + +register_torch_observers() +register_torch_fake_quants() + + +class TestQSchemeHandler(TestCase): + + def test_init(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + # per_channel + qscheme = QSchemeHandler(is_symmetry=True, is_per_channel=True) + assert qscheme.torch_qscheme is torch.per_channel_symmetric + + # per_tensor + qscheme = QSchemeHandler(is_symmetry=True, is_per_channel=False) + assert qscheme.torch_qscheme is torch.per_tensor_symmetric + + # qdtype is incorrect + self.assertRaises(AssertionError, QSchemeHandler, 'float') + + # is_symmetric_range + kwargs = {'is_symmetric_range': True} + qscheme = QSchemeHandler(**kwargs) + assert qscheme.is_symmetric_range is True + + def test_to_observer_params(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + # qdtype = quint8 + ret_params = QSchemeHandler(qdtype='quint8').to_observer_params() + assert ret_params['dtype'] == torch.quint8 + assert ret_params['quant_min'] == 0 and ret_params['quant_max'] == 255 + + # qdtype = qint8, is_symmetric_range=False + ret_params = QSchemeHandler(qdtype='qint8').to_observer_params() + assert ret_params['dtype'] == torch.qint8 + assert ret_params['quant_min'] == -128 and ret_params[ + 'quant_max'] == 127 + + # qdtype = qint8, is_symmetric_range=True + ret_params = QSchemeHandler( + qdtype='qint8', is_symmetric_range=True).to_observer_params() + assert ret_params['quant_min'] == -127 and ret_params[ + 'quant_max'] == 127 + + # per_channel + ret_params = QSchemeHandler(is_per_channel=True).to_observer_params() + assert ret_params['ch_axis'] == 0 + + # per_tensor + ret_params = QSchemeHandler(is_per_channel=False).to_observer_params() + assert 'ch_axis' not in ret_params.keys() + + +class TestQConfigHandler(TestCase): + + def setUp(self): + self.qconfig_dict = dict( + w_observer=dict(type='MovingAveragePerChannelMinMaxObserver'), + a_observer=dict(type='MovingAveragePerChannelMinMaxObserver'), + w_fake_quant=dict(type='FakeQuantize'), + a_fake_quant=dict(type='FakeQuantize'), + w_qscheme=dict( + qdtype='qint8', + bit=8, + is_symmetry=True, + is_symmetric_range=True), + a_qscheme=dict(qdtype='quint8', bit=8, is_symmetry=True), + ) + self.qconfig = Config(self.qconfig_dict) + + def test_check_qconfig(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + assert QConfigHandler.check_qconfig(self.qconfig_dict) is True + assert QConfigHandler.check_qconfig(self.qconfig) is True + qconfig_dict = copy.copy(self.qconfig_dict) + print(qconfig_dict) + qconfig_dict.pop('w_observer') + assert QConfigHandler.check_qconfig(qconfig_dict) is False + + def test_init(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + # test dict init + qconfig = QConfigHandler(self.qconfig_dict) + assert hasattr(qconfig, 'w_qscheme') + assert hasattr(qconfig, 'a_qscheme') + assert hasattr(qconfig, 'w_fake_quant') + assert hasattr(qconfig, 'a_fake_quant') + + # test mmengine's Config init + qconfig = QConfigHandler(self.qconfig) + assert hasattr(qconfig, 'w_qscheme') + assert hasattr(qconfig, 'a_qscheme') + assert hasattr(qconfig, 'w_fake_quant') + assert hasattr(qconfig, 'a_fake_quant') + + # per_channel + assert qconfig.w_qscheme.is_per_channel is True + assert qconfig.a_qscheme.is_per_channel is True + + def test_convert(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + qconfig = QConfigHandler(self.qconfig) + torch_qconfig = qconfig.convert() + assert isinstance(torch_qconfig, QConfig) + + def test_replace_fakequant(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + # update_qparams is False + qconfig = QConfigHandler(self.qconfig) + org_fakequant_ins = qconfig.w_fake_quant() + new_fakequant = qconfig.replace_fakequant( + org_fakequant_ins, qconfig.w_qscheme, update_qparams=False) + new_fakequant_ins = new_fakequant() + assert isinstance(new_fakequant_ins, FakeQuantize) + assert isinstance(new_fakequant_ins.activation_post_process, + MODELS.get('PerChannelMinMaxObserver')) + + # update_qparams is True + qconfig = QConfigHandler(self.qconfig) + org_fakequant_ins = qconfig.w_fake_quant() + org_fakequant_ins.scale = torch.Tensor([2]) + org_fakequant_ins.activation_post_process.min_val = torch.Tensor([1]) + new_fakequant_ins = qconfig.replace_fakequant( + org_fakequant_ins, qconfig.w_qscheme, update_qparams=True) + assert isinstance(new_fakequant_ins, FakeQuantize) + assert isinstance(new_fakequant_ins.activation_post_process, + MODELS.get('PerChannelMinMaxObserver')) + assert new_fakequant_ins.scale == org_fakequant_ins.scale + assert new_fakequant_ins.activation_post_process.min_val == \ + org_fakequant_ins.activation_post_process.min_val + + def test_fixed_w_fakequant(self): + if digit_version(torch.__version__) < digit_version('1.13.0'): + self.skipTest('version of torch < 1.13.0') + + qconfig = QConfigHandler(self.qconfig) + qconfig.fixed_w_fakequant() + new_fakequant_ins = qconfig.w_fake_quant() + assert isinstance(new_fakequant_ins, FakeQuantize) + assert isinstance(new_fakequant_ins.activation_post_process, + MODELS.get('PerChannelMinMaxObserver')) diff --git a/cv/distiller/CWD/mmrazor/tests/test_tools/__init__.py b/cv/distiller/CWD/mmrazor/tests/test_tools/__init__.py new file mode 100755 index 000000000..ef101fec6 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_tools/__init__.py @@ -0,0 +1 @@ +# Copyright (c) OpenMMLab. All rights reserved. diff --git a/cv/distiller/CWD/mmrazor/tests/test_tools/test_tools.py b/cv/distiller/CWD/mmrazor/tests/test_tools/test_tools.py new file mode 100755 index 000000000..8af4a0d20 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_tools/test_tools.py @@ -0,0 +1,101 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import shutil +import subprocess +from unittest import TestCase + +import torch + +from mmrazor import digit_version + +TEST_TOOLS = os.getenv('TEST_TOOLS') == 'true' + + +class TestTools(TestCase): + _config_path = None + + def setUp(self) -> None: + if not TEST_TOOLS: + self.skipTest('disabled') + + @property + def config_path(self): + if self._config_path is None: + self._config_path = self._get_config_path() + return self._config_path + + def _setUp(self) -> None: + self.workdir = os.path.dirname(__file__) + '/tmp/' + if not os.path.exists(self.workdir): + os.mkdir(self.workdir) + + def save_to_config(self, name, content): + with open(self.workdir + f'/{name}', 'w') as f: + f.write(content) + + def test_get_channel_unit(self): + if digit_version(torch.__version__) < digit_version('1.12.0'): + self.skipTest('version of torch < 1.12.0') + + for path in self.config_path: + with self.subTest(path=path): + self._setUp() + self.save_to_config('pretrain.py', f"""_base_=['{path}']""") + try: + subprocess.run([ + 'python', './tools/pruning/get_channel_units.py', + f'{self.workdir}/pretrain.py', '-o', + f'{self.workdir}/unit.json' + ]) + except Exception as e: + self.fail(f'{e}') + self.assertTrue(os.path.exists(f'{self.workdir}/unit.json')) + + self._tearDown() + + def test_get_prune_config(self): + if digit_version(torch.__version__) < digit_version('1.12.0'): + self.skipTest('version of torch < 1.12.0') + for path in self.config_path: + with self.subTest(path=path): + self._setUp() + self.save_to_config('pretrain.py', f"""_base_=['{path}']""") + try: + subprocess.run([ + 'python', + './tools/pruning/get_l1_prune_config.py', + f'{self.workdir}/pretrain.py', + '-o', + f'{self.workdir}/prune.py', + ]) + pass + except Exception as e: + self.fail(f'{e}') + self.assertTrue(os.path.exists(f'{self.workdir}/prune.py')) + + self._tearDown() + + def _tearDown(self) -> None: + print('delete') + shutil.rmtree(self.workdir) + pass + + def _get_config_path(self): + config_paths = [] + paths = [ + ('mmcls', 'mmcls::resnet/resnet34_8xb32_in1k.py'), + ('mmdet', 'mmdet::retinanet/retinanet_r18_fpn_1x_coco.py'), + ( + 'mmseg', + 'mmseg::deeplabv3plus/deeplabv3plus_r50-d8_4xb4-20k_voc12aug-512x512.py' # noqa + ), + ('mmyolo', + 'mmyolo::yolov5/yolov5_m-p6-v62_syncbn_fast_8xb16-300e_coco.py') + ] + for repo_name, path in paths: + try: + __import__(repo_name) + config_paths.append(path) + except Exception: + pass + return config_paths diff --git a/cv/distiller/CWD/mmrazor/tests/test_utils/test_index_dict.py b/cv/distiller/CWD/mmrazor/tests/test_utils/test_index_dict.py new file mode 100755 index 000000000..767dd806c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_utils/test_index_dict.py @@ -0,0 +1,16 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest + +from mmrazor.utils.index_dict import IndexDict + + +class TestIndexDict(unittest.TestCase): + + def test_dict(self): + dict = IndexDict() + dict[(4, 5)] = 2 + dict[(1, 3)] = 1 + + self.assertSequenceEqual(list(dict.keys()), [(1, 3), (4, 5)]) + with self.assertRaisesRegex(AssertionError, 'overlap'): + dict[2, 3] = 3 diff --git a/cv/distiller/CWD/mmrazor/tests/test_utils/test_placeholder.py b/cv/distiller/CWD/mmrazor/tests/test_utils/test_placeholder.py new file mode 100755 index 000000000..600cd0914 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_utils/test_placeholder.py @@ -0,0 +1,18 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest + +import pytest + +from mmrazor.utils import get_placeholder + + +class TestPlaceholder(unittest.TestCase): + + def test_placeholder(self): + holder = get_placeholder('test') + with pytest.raises(ImportError): + holder() + from mmrazor.models.architectures.dynamic_ops import DynamicMixin + + class tmp(holder, DynamicMixin): + pass diff --git a/cv/distiller/CWD/mmrazor/tests/test_visualizer/test_visualizer.py b/cv/distiller/CWD/mmrazor/tests/test_visualizer/test_visualizer.py new file mode 100755 index 000000000..b1beaedce --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/test_visualizer/test_visualizer.py @@ -0,0 +1,128 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import numpy as np +import pytest +import torch +from mmengine.visualization import Visualizer + +from mmrazor.visualization.local_visualizer import modify + + +class TestVisualizer(TestCase): + + def setUp(self): + """Setup the demo image in every test method. + + TestCase calls functions in this order: setUp() -> testMethod() -> + tearDown() -> cleanUp() + """ + self.image = np.random.randint( + 0, 256, size=(10, 10, 3)).astype('uint8') + + def test_draw_featmap(self): + visualizer = Visualizer() + visualizer.draw_featmap = modify + image = np.random.randint(0, 256, size=(3, 3, 3), dtype='uint8') + + # must be Tensor + with pytest.raises( + AssertionError, + match='`featmap` should be torch.Tensor, but got ' + ""): + visualizer.draw_featmap(np.ones((3, 3, 3))) + + # test tensor format + with pytest.raises( + AssertionError, match='Input dimension must be 3, but got 4'): + visualizer.draw_featmap(torch.randn(1, 1, 3, 3)) + + # test overlaid_image shape + with pytest.warns(Warning): + visualizer.draw_featmap(torch.randn(1, 4, 3), overlaid_image=image) + + # test resize_shape + featmap = visualizer.draw_featmap( + torch.randn(1, 4, 3), resize_shape=(6, 7)) + assert featmap.shape[:2] == (6, 7) + featmap = visualizer.draw_featmap( + torch.randn(1, 4, 3), overlaid_image=image, resize_shape=(6, 7)) + assert featmap.shape[:2] == (6, 7) + + # test channel_reduction parameter + # mode only supports 'squeeze_mean' and 'select_max' + with pytest.raises(AssertionError): + visualizer.draw_featmap( + torch.randn(2, 3, 3), channel_reduction='xx') + + featmap = visualizer.draw_featmap( + torch.randn(2, 3, 3), channel_reduction='squeeze_mean') + assert featmap.shape[:2] == (3, 3) + featmap = visualizer.draw_featmap( + torch.randn(2, 3, 3), channel_reduction='select_max') + assert featmap.shape[:2] == (3, 3) + featmap = visualizer.draw_featmap( + torch.randn(2, 3, 3), channel_reduction='pixel_wise_max') + assert featmap.shape[:2] == (3, 3) + featmap = visualizer.draw_featmap( + torch.randn(2, 4, 3), + overlaid_image=image, + channel_reduction='pixel_wise_max') + assert featmap.shape[:2] == (3, 3) + + # test topk parameter + with pytest.raises( + AssertionError, + match='The input tensor channel dimension must be 1 or 3 ' + 'when topk is less than 1, but the channel ' + 'dimension you input is 6, you can use the ' + 'channel_reduction parameter or set topk ' + 'greater than 0 to solve the error'): + visualizer.draw_featmap( + torch.randn(6, 3, 3), channel_reduction=None, topk=0) + + featmap = visualizer.draw_featmap( + torch.randn(6, 3, 3), channel_reduction='select_max', topk=10) + assert featmap.shape[:2] == (3, 3) + featmap = visualizer.draw_featmap( + torch.randn(1, 4, 3), channel_reduction=None, topk=-1) + assert featmap.shape[:2] == (4, 3) + + featmap = visualizer.draw_featmap( + torch.randn(3, 4, 3), + overlaid_image=image, + channel_reduction=None, + topk=-1) + assert featmap.shape[:2] == (3, 3) + featmap = visualizer.draw_featmap( + torch.randn(6, 3, 3), + channel_reduction=None, + topk=4, + arrangement=(2, 2)) + assert featmap.shape[:2] == (6, 6) + featmap = visualizer.draw_featmap( + torch.randn(6, 3, 3), + channel_reduction=None, + topk=4, + arrangement=(1, 4)) + assert featmap.shape[:2] == (3, 12) + with pytest.raises( + AssertionError, + match='The product of row and col in the `arrangement` ' + 'is less than topk, please set ' + 'the `arrangement` correctly'): + visualizer.draw_featmap( + torch.randn(6, 3, 3), + channel_reduction=None, + topk=4, + arrangement=(1, 2)) + + # test gray + featmap = visualizer.draw_featmap( + torch.randn(6, 3, 3), + overlaid_image=np.random.randint( + 0, 256, size=(3, 3), dtype='uint8'), + channel_reduction=None, + topk=4, + arrangement=(2, 2)) + assert featmap.shape[:2] == (6, 6) diff --git a/cv/distiller/CWD/mmrazor/tests/utils/__init__.py b/cv/distiller/CWD/mmrazor/tests/utils/__init__.py new file mode 100755 index 000000000..f4f0562e4 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/utils/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .set_torch_thread import SetTorchThread + +__all__ = ['SetTorchThread'] diff --git a/cv/distiller/CWD/mmrazor/tests/utils/set_dist_env.py b/cv/distiller/CWD/mmrazor/tests/utils/set_dist_env.py new file mode 100755 index 000000000..66d41a170 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/utils/set_dist_env.py @@ -0,0 +1,31 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import random + +import torch +import torch.distributed as dist + + +class SetDistEnv: + + def __init__(self, using_cuda=False, port=None) -> None: + self.using_cuda = using_cuda + if self.using_cuda: + assert torch.cuda.is_available() + if port is None: + port = random.randint(10000, 20000) + self.port = port + + def __enter__(self): + os.environ['MASTER_ADDR'] = 'localhost' + os.environ['MASTER_PORT'] = str(self.port) + + # initialize the process group + if self.using_cuda: + backend = 'nccl' + else: + backend = 'gloo' + dist.init_process_group(backend, rank=0, world_size=1) + + def __exit__(self, exc_type, exc_value, tb): + dist.destroy_process_group() diff --git a/cv/distiller/CWD/mmrazor/tests/utils/set_torch_thread.py b/cv/distiller/CWD/mmrazor/tests/utils/set_torch_thread.py new file mode 100755 index 000000000..a3cc482e8 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tests/utils/set_torch_thread.py @@ -0,0 +1,17 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import torch + + +class SetTorchThread: + + def __init__(self, num_thread: int = -1) -> None: + self.prev_num_threads = torch.get_num_threads() + self.num_threads = num_thread + + def __enter__(self): + if self.num_threads != -1: + torch.set_num_threads(self.num_threads) + + def __exit__(self, exc_type, exc_value, tb): + if self.num_threads != -1: + torch.set_num_threads(self.prev_num_threads) diff --git a/cv/distiller/CWD/mmrazor/tools/dataset_converters/cityscapes.py b/cv/distiller/CWD/mmrazor/tools/dataset_converters/cityscapes.py new file mode 100755 index 000000000..3f22c27ad --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/dataset_converters/cityscapes.py @@ -0,0 +1,56 @@ +#copyright (c) OpenMMLab. All rights reserved. +import argparse +import os.path as osp + +from cityscapesscripts.preparation.json2labelImg import json2labelImg +from mmengine.utils import (mkdir_or_exist, scandir, track_parallel_progress, + track_progress) + + +def convert_json_to_label(json_file): + label_file = json_file.replace('_polygons.json', '_labelTrainIds.png') + json2labelImg(json_file, label_file, 'trainIds') + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Convert Cityscapes annotations to TrainIds') + parser.add_argument('cityscapes_path', help='cityscapes data path') + parser.add_argument('--gt-dir', default='gtFine', type=str) + parser.add_argument('-o', '--out-dir', help='output path') + parser.add_argument( + '--nproc', default=1, type=int, help='number of process') + args = parser.parse_args() + return args + + +def main(): + args = parse_args() + cityscapes_path = args.cityscapes_path + out_dir = args.out_dir if args.out_dir else cityscapes_path + mkdir_or_exist(out_dir) + + gt_dir = osp.join(cityscapes_path, args.gt_dir) + + poly_files = [] + for poly in scandir(gt_dir, '_polygons.json', recursive=True): + poly_file = osp.join(gt_dir, poly) + poly_files.append(poly_file) + if args.nproc > 1: + track_parallel_progress(convert_json_to_label, poly_files, args.nproc) + else: + track_progress(convert_json_to_label, poly_files) + + split_names = ['train', 'val', 'test'] + + for split in split_names: + filenames = [] + for poly in scandir( + osp.join(gt_dir, split), '_polygons.json', recursive=True): + filenames.append(poly.replace('_gtFine_polygons.json', '')) + with open(osp.join(out_dir, f'{split}.txt'), 'w') as f: + f.writelines(f + '\n' for f in filenames) + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/dist_test.sh b/cv/distiller/CWD/mmrazor/tools/dist_test.sh new file mode 100755 index 000000000..dea131b43 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/dist_test.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +CONFIG=$1 +CHECKPOINT=$2 +GPUS=$3 +NNODES=${NNODES:-1} +NODE_RANK=${NODE_RANK:-0} +PORT=${PORT:-29500} +MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} + +PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ +python -m torch.distributed.launch \ + --nnodes=$NNODES \ + --node_rank=$NODE_RANK \ + --master_addr=$MASTER_ADDR \ + --nproc_per_node=$GPUS \ + --master_port=$PORT \ + $(dirname "$0")/test.py \ + $CONFIG \ + $CHECKPOINT \ + --launcher pytorch \ + ${@:4} diff --git a/cv/distiller/CWD/mmrazor/tools/dist_train.sh b/cv/distiller/CWD/mmrazor/tools/dist_train.sh new file mode 100755 index 000000000..4ef0ea669 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/dist_train.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +CONFIG=$1 +GPUS=$2 +NNODES=${NNODES:-1} +NODE_RANK=${NODE_RANK:-0} +PORT=${PORT:-29500} +MASTER_ADDR=${MASTER_ADDR:-"127.0.0.1"} + +PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ +python3 -m torch.distributed.launch \ + --nnodes=$NNODES \ + --node_rank=$NODE_RANK \ + --master_addr=$MASTER_ADDR \ + --nproc_per_node=$GPUS \ + --master_port=$PORT \ + $(dirname "$0")/train.py \ + $CONFIG \ + --launcher pytorch ${@:3} diff --git a/cv/distiller/CWD/mmrazor/tools/misc/print_config.py b/cv/distiller/CWD/mmrazor/tools/misc/print_config.py new file mode 100755 index 000000000..6829b2934 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/misc/print_config.py @@ -0,0 +1,51 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import warnings + +from mmengine import Config, DictAction + + +def parse_args(): + parser = argparse.ArgumentParser(description='Print the whole config') + parser.add_argument('config', help='config file path') + parser.add_argument( + '--options', + nargs='+', + action=DictAction, + help='override some settings in the used config, the key-value pair ' + 'in xxx=yyy format will be merged into config file (deprecate), ' + 'change to --cfg-options instead.') + parser.add_argument( + '--cfg-options', + nargs='+', + action=DictAction, + help='override some settings in the used config, the key-value pair ' + 'in xxx=yyy format will be merged into config file. If the value to ' + 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' + 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' + 'Note that the quotation marks are necessary and that no white space ' + 'is allowed.') + args = parser.parse_args() + + if args.options and args.cfg_options: + raise ValueError( + '--options and --cfg-options cannot be both ' + 'specified, --options is deprecated in favor of --cfg-options') + if args.options: + warnings.warn('--options is deprecated in favor of --cfg-options') + args.cfg_options = args.options + + return args + + +def main(): + args = parse_args() + + cfg = Config.fromfile(args.config) + if args.cfg_options is not None: + cfg.merge_from_dict(args.cfg_options) + print(f'Config:\n{cfg.pretty_text}') + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_attentivenas_nas_ckpt.py b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_attentivenas_nas_ckpt.py new file mode 100755 index 000000000..e320fdf94 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_attentivenas_nas_ckpt.py @@ -0,0 +1,170 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +from pathlib import Path + +import torch + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Process a checkpoint to be published') + parser.add_argument('checkpoint', help='input checkpoint filename') + parser.add_argument( + '--inplace', action='store_true', help='replace origin ckpt') + args = parser.parse_args() + return args + + +def main(): + args = parse_args() + checkpoint = torch.load(args.checkpoint, map_location='cpu') + new_state_dict = dict() + + for key, value in checkpoint['state_dict'].items(): + key = key.replace('module.', 'architecture.backbone.') + if 'blocks.10' in key: + new_key = key.replace('blocks.10', 'layer3.3') + elif 'blocks.11' in key: + new_key = key.replace('blocks.11', 'layer3.4') + elif 'blocks.12' in key: + new_key = key.replace('blocks.12', 'layer3.5') + elif 'blocks.13' in key: + new_key = key.replace('blocks.13', 'layer4.0') + elif 'blocks.14' in key: + new_key = key.replace('blocks.14', 'layer4.1') + elif 'blocks.15' in key: + new_key = key.replace('blocks.15', 'layer4.2') + elif 'blocks.16' in key: + new_key = key.replace('blocks.16', 'layer4.3') + elif 'blocks.17' in key: + new_key = key.replace('blocks.17', 'layer4.4') + elif 'blocks.18' in key: + new_key = key.replace('blocks.18', 'layer4.5') + elif 'blocks.19' in key: + new_key = key.replace('blocks.19', 'layer5.0') + elif 'blocks.20' in key: + new_key = key.replace('blocks.20', 'layer5.1') + elif 'blocks.21' in key: + new_key = key.replace('blocks.21', 'layer5.2') + elif 'blocks.22' in key: + new_key = key.replace('blocks.22', 'layer5.3') + elif 'blocks.23' in key: + new_key = key.replace('blocks.23', 'layer5.4') + elif 'blocks.24' in key: + new_key = key.replace('blocks.24', 'layer5.5') + elif 'blocks.25' in key: + new_key = key.replace('blocks.25', 'layer5.6') + elif 'blocks.26' in key: + new_key = key.replace('blocks.26', 'layer5.7') + elif 'blocks.27' in key: + new_key = key.replace('blocks.27', 'layer6.0') + elif 'blocks.28' in key: + new_key = key.replace('blocks.28', 'layer6.1') + elif 'blocks.29' in key: + new_key = key.replace('blocks.29', 'layer6.2') + elif 'blocks.30' in key: + new_key = key.replace('blocks.30', 'layer6.3') + elif 'blocks.31' in key: + new_key = key.replace('blocks.31', 'layer6.4') + elif 'blocks.32' in key: + new_key = key.replace('blocks.32', 'layer6.5') + elif 'blocks.33' in key: + new_key = key.replace('blocks.33', 'layer6.6') + elif 'blocks.34' in key: + new_key = key.replace('blocks.34', 'layer6.7') + elif 'blocks.35' in key: + new_key = key.replace('blocks.35', 'layer7.0') + elif 'blocks.36' in key: + new_key = key.replace('blocks.36', 'layer7.1') + elif 'blocks.0' in key: + new_key = key.replace('blocks.0', 'layer1.0') + elif 'blocks.1' in key: + new_key = key.replace('blocks.1', 'layer1.1') + elif 'blocks.2' in key: + new_key = key.replace('blocks.2', 'layer2.0') + elif 'blocks.3' in key: + new_key = key.replace('blocks.3', 'layer2.1') + elif 'blocks.4' in key: + new_key = key.replace('blocks.4', 'layer2.2') + elif 'blocks.5' in key: + new_key = key.replace('blocks.5', 'layer2.3') + elif 'blocks.6' in key: + new_key = key.replace('blocks.6', 'layer2.4') + elif 'blocks.7' in key: + new_key = key.replace('blocks.7', 'layer3.0') + elif 'blocks.8' in key: + new_key = key.replace('blocks.8', 'layer3.1') + elif 'blocks.9' in key: + new_key = key.replace('blocks.9', 'layer3.2') + else: + new_key = key + + if 'mobile_inverted_conv.depth_conv.conv.conv' in new_key: + final_new_key = new_key.replace( + 'mobile_inverted_conv.depth_conv.conv.conv', + 'depthwise_conv.conv') + elif 'mobile_inverted_conv.depth_conv.bn.bn' in new_key: + final_new_key = new_key.replace( + 'mobile_inverted_conv.depth_conv.bn.bn', 'depthwise_conv.bn') + elif 'mobile_inverted_conv.point_linear.conv.conv' in new_key: + final_new_key = new_key.replace( + 'mobile_inverted_conv.point_linear.conv.conv', + 'linear_conv.conv') + elif 'mobile_inverted_conv.point_linear.bn.bn' in new_key: + final_new_key = new_key.replace( + 'mobile_inverted_conv.point_linear.bn.bn', 'linear_conv.bn') + elif 'shortcut.conv.conv' in new_key: + final_new_key = new_key.replace('shortcut.conv.conv', + 'shortcut.conv') + elif 'mobile_inverted_conv.inverted_bottleneck.conv.conv' in new_key: + final_new_key = new_key.replace( + 'mobile_inverted_conv.inverted_bottleneck.conv.conv', + 'expand_conv.conv') + elif 'mobile_inverted_conv.inverted_bottleneck.bn.bn' in new_key: + final_new_key = new_key.replace( + 'mobile_inverted_conv.inverted_bottleneck.bn.bn', + 'expand_conv.bn') + elif 'mobile_inverted_conv.depth_conv.se.fc.reduce' in new_key: + final_new_key = new_key.replace( + 'mobile_inverted_conv.depth_conv.se.fc.reduce', + 'se.conv1.conv') + elif 'mobile_inverted_conv.depth_conv.se.fc.expand' in new_key: + final_new_key = new_key.replace( + 'mobile_inverted_conv.depth_conv.se.fc.expand', + 'se.conv2.conv') + elif 'first_conv.conv.conv' in new_key: + final_new_key = new_key.replace('first_conv.conv.conv', + 'first_conv.conv') + elif 'first_conv.bn.bn' in new_key: + final_new_key = new_key.replace('first_conv.bn.bn', + 'first_conv.bn') + elif 'final_expand_layer.conv.conv' in new_key: + final_new_key = new_key.replace('final_expand_layer.conv.conv', + 'final_expand_layer.conv') + elif 'final_expand_layer.bn.bn' in new_key: + final_new_key = new_key.replace('final_expand_layer.bn.bn', + 'final_expand_layer.bn') + elif 'feature_mix_layer.conv.conv' in new_key: + final_new_key = new_key.replace('feature_mix_layer.conv.conv', + 'feature_mix_layer.conv') + elif 'classifier.linear.linear' in new_key: + final_new_key = new_key.replace( + 'backbone.classifier.linear.linear', 'head.fc') + else: + final_new_key = new_key + + new_state_dict[final_new_key] = value + + checkpoint['state_dict'] = new_state_dict + if args.inplace: + torch.save(checkpoint, args.checkpoint) + else: + ckpt_path = Path(args.checkpoint) + ckpt_name = ckpt_path.stem + ckpt_dir = ckpt_path.parent + new_ckpt_path = ckpt_dir / f'{ckpt_name}_latest.pth' + torch.save(checkpoint, new_ckpt_path) + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_bignas_gml_ckpt.py b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_bignas_gml_ckpt.py new file mode 100755 index 000000000..bba0b3dc9 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_bignas_gml_ckpt.py @@ -0,0 +1,56 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +from pathlib import Path + +import torch + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Process a checkpoint to be published') + parser.add_argument('checkpoint', help='input checkpoint filename') + parser.add_argument( + '--inplace', action='store_true', help='replace origin ckpt') + args = parser.parse_args() + return args + + +def main(): + args = parse_args() + checkpoint = torch.load(args.checkpoint, map_location='cpu') + new_state_dict = dict() + + for key, value in checkpoint['state_dict'].items(): + key = key.replace('model.', 'architecture.') + if 'blocks.0' in key: + new_key = key.replace('blocks.0', 'layer1') + elif 'blocks.1' in key: + new_key = key.replace('blocks.1', 'layer2') + elif 'blocks.2' in key: + new_key = key.replace('blocks.2', 'layer3') + elif 'blocks.3' in key: + new_key = key.replace('blocks.3', 'layer4') + elif 'blocks.4' in key: + new_key = key.replace('blocks.4', 'layer5') + elif 'blocks.5' in key: + new_key = key.replace('blocks.5', 'layer6') + elif 'blocks.6' in key: + new_key = key.replace('blocks.6', 'layer7') + else: + new_key = key + + new_state_dict[new_key] = value + + checkpoint['state_dict'] = new_state_dict + if args.inplace: + torch.save(checkpoint, args.checkpoint) + else: + ckpt_path = Path(args.checkpoint) + ckpt_name = ckpt_path.stem + ckpt_dir = ckpt_path.parent + new_ckpt_path = ckpt_dir / f'{ckpt_name}_latest.pth' + torch.save(checkpoint, new_ckpt_path) + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt.py b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt.py new file mode 100755 index 000000000..c6e966589 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt.py @@ -0,0 +1,47 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +from pathlib import Path + +import torch + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Process a checkpoint to be published') + parser.add_argument('checkpoint', help='input checkpoint filename') + parser.add_argument( + '--inplace', action='store_true', help='replace origin ckpt') + args = parser.parse_args() + return args + + +def main(): + args = parse_args() + checkpoint = torch.load(args.checkpoint, map_location='cpu') + new_state_dict = dict() + + for key, value in checkpoint['state_dict'].items(): + if key.startswith('architecture.model.distiller.teacher'): + new_key = key.replace('architecture.model.distiller.teacher', + 'architecture.teacher') + elif key.startswith('architecture.model'): + new_key = key.replace('architecture.model', 'architecture') + else: + new_key = key + + new_state_dict[new_key] = value + + checkpoint['state_dict'] = new_state_dict + + if args.inplace: + torch.save(checkpoint, args.checkpoint) + else: + ckpt_path = Path(args.checkpoint) + ckpt_name = ckpt_path.stem + ckpt_dir = ckpt_path.parent + new_ckpt_path = ckpt_dir / f'{ckpt_name}_latest.pth' + torch.save(checkpoint, new_ckpt_path) + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt_to_student.py b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt_to_student.py new file mode 100755 index 000000000..e44f66d02 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_kd_ckpt_to_student.py @@ -0,0 +1,48 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +from pathlib import Path + +import torch + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Convert KD checkpoint to student-only checkpoint') + parser.add_argument('checkpoint', help='input checkpoint filename') + parser.add_argument('--out-path', help='save checkpoint path') + parser.add_argument( + '--inplace', action='store_true', help='replace origin ckpt') + args = parser.parse_args() + return args + + +def main(): + args = parse_args() + checkpoint = torch.load(args.checkpoint, map_location='cpu') + new_state_dict = dict() + new_meta = checkpoint['meta'] + + for key, value in checkpoint['state_dict'].items(): + if key.startswith('architecture.'): + new_key = key.replace('architecture.', '') + new_state_dict[new_key] = value + + checkpoint = dict() + checkpoint['meta'] = new_meta + checkpoint['state_dict'] = new_state_dict + + if args.inplace: + torch.save(checkpoint, args.checkpoint) + else: + ckpt_path = Path(args.checkpoint) + ckpt_name = ckpt_path.stem + if args.out_path: + ckpt_dir = Path(args.out_path) + else: + ckpt_dir = ckpt_path.parent + new_ckpt_path = ckpt_dir / f'{ckpt_name}_student.pth' + torch.save(checkpoint, new_ckpt_path) + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_ofa_ckpt.py b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_ofa_ckpt.py new file mode 100755 index 000000000..b28f15f29 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_ofa_ckpt.py @@ -0,0 +1,110 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +from pathlib import Path + +import torch + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Process a checkpoint to be published') + parser.add_argument('checkpoint', help='input checkpoint filename') + parser.add_argument('--depth', nargs='+', type=int, help='layer depth') + parser.add_argument( + '--inplace', action='store_true', help='replace origin ckpt') + args = parser.parse_args() + return args + + +def block2layer_index_convert(layer_depth): + """Build index_table from OFA blocks to MMRazor layers.""" + index_table = dict() + i = 0 + first_index = 1 + second_index = 0 + for k in layer_depth: + for _ in range(k): + index_table[str(i)] = str(first_index) + '.' + str(second_index) + i += 1 + second_index += 1 + second_index = 0 + first_index += 1 + + return index_table + + +def main(): + args = parse_args() + checkpoint = torch.load(args.checkpoint, map_location='cpu') + new_state_dict = dict() + + index_table = block2layer_index_convert(args.depth) + + for key, value in checkpoint['state_dict'].items(): + if 'blocks' in key: + index = key.split('.')[1] + new_key = key.replace('blocks.' + index, + 'layer' + index_table[index]) + else: + new_key = key + + if 'mobile_inverted_conv' in new_key: + new_key = new_key.replace('mobile_inverted_conv.', '') + if 'depth_conv' in key: + new_key = new_key.replace('depth_conv', 'depthwise_conv') + if 'point_linear' in key: + new_key = new_key.replace('point_linear', 'linear_conv') + if 'inverted_bottleneck' in key: + new_key = new_key.replace('inverted_bottleneck', 'expand_conv') + if '.conv.conv' in new_key: + new_key = new_key.replace('.conv.conv', '.conv') + if '.bn.bn' in new_key: + new_key = new_key.replace('.bn.bn', '.bn') + + if 'layer1.0.depthwise_conv.weight' in new_key: + new_key = new_key.replace('layer1.0.depthwise_conv.weight', + 'layer1.0.depthwise_conv.conv.weight') + if 'layer1.0.linear_conv.weight' in new_key: + new_key = new_key.replace('layer1.0.linear_conv.weight', + 'layer1.0.linear_conv.conv.weight') + + if 'depthwise_conv.se.fc.reduce' in new_key: + new_key = new_key.replace('depthwise_conv.se.fc.reduce', + 'se.conv1.conv') + if 'depthwise_conv.se.fc.expand' in new_key: + new_key = new_key.replace('depthwise_conv.se.fc.expand', + 'se.conv2.conv') + + if 'final_expand_layer' in new_key: + new_key = new_key.replace('final_expand_layer', + 'last_conv.final_expand_layer') + if 'feature_mix_layer' in new_key: + new_key = new_key.replace('feature_mix_layer', + 'last_conv.feature_mix_layer') + + if '5to3_matrix' in new_key: + new_key = new_key.replace('5to3_matrix', 'trans_matrix_5to3') + if '7to5_matrix' in new_key: + new_key = new_key.replace('7to5_matrix', 'trans_matrix_7to5') + + new_key = 'architecture.backbone.' + new_key + + if 'classifier.linear' in new_key: + new_key = new_key.replace('classifier.linear', 'head.fc') + new_key = new_key.replace('backbone.', '') + + new_state_dict[new_key] = value + + checkpoint['state_dict'] = new_state_dict + if args.inplace: + torch.save(checkpoint, args.checkpoint) + else: + ckpt_path = Path(args.checkpoint) + ckpt_name = ckpt_path.stem + ckpt_dir = ckpt_path.parent + new_ckpt_path = ckpt_dir / f'{ckpt_name}_latest.pth' + torch.save(checkpoint, new_ckpt_path) + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_quant_ckpt.py b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_quant_ckpt.py new file mode 100755 index 000000000..9fbb06125 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_quant_ckpt.py @@ -0,0 +1,53 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +from pathlib import Path + +import torch + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Convert quantized checkpoint to deploy') + parser.add_argument('checkpoint', help='input checkpoint filename') + parser.add_argument('--out-path', help='save checkpoint path') + parser.add_argument( + '--inplace', action='store_true', help='replace origin ckpt') + args = parser.parse_args() + return args + + +def main(): + args = parse_args() + checkpoint = torch.load(args.checkpoint, map_location='cpu') + new_state_dict = dict() + new_meta = checkpoint['meta'] + + for key, value in checkpoint['state_dict'].items(): + if key.startswith('qmodels.predict.'): + new_key = key.replace('qmodels.predict.', '') + if '_val' in new_key and 'weight_fake_quant' in new_key: + new_key = new_key.replace('_val', '_vals') + new_state_dict[new_key] = value + # if key.startswith('architecture.'): + # new_key = key.replace('architecture.', '') + # new_state_dict[new_key] = value + + checkpoint = dict() + checkpoint['meta'] = new_meta + checkpoint['state_dict'] = new_state_dict + + if args.inplace: + torch.save(checkpoint, args.checkpoint) + else: + ckpt_path = Path(args.checkpoint) + ckpt_name = ckpt_path.stem + if args.out_path: + ckpt_dir = Path(args.out_path) + else: + ckpt_dir = ckpt_path.parent + new_ckpt_path = ckpt_dir / f'{ckpt_name}_deploy.pth' + torch.save(checkpoint, new_ckpt_path) + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/convert_supernet2subnet.py b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_supernet2subnet.py new file mode 100755 index 000000000..b9f39a517 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/model_converters/convert_supernet2subnet.py @@ -0,0 +1,60 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import os +import os.path as osp +import time + +import torch +from mmengine.config import Config +from mmengine.runner import Runner + +from mmrazor.structures.subnet import load_fix_subnet +from mmrazor.utils import register_all_modules + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Process a NAS supernet checkpoint to be converted') + parser.add_argument('config', help='NAS model config file path') + parser.add_argument('checkpoint', help='supernet checkpoint file path') + parser.add_argument('yaml', help='YAML with subnet settings file path') + parser.add_argument( + '--launcher', + choices=['none', 'pytorch', 'slurm', 'mpi'], + default='none', + help='job launcher') + parser.add_argument('--local_rank', type=int, default=0) + args = parser.parse_args() + if 'LOCAL_RANK' not in os.environ: + os.environ['LOCAL_RANK'] = str(args.local_rank) + args = parser.parse_args() + return args + + +def main(): + register_all_modules(False) + args = parse_args() + + # load config + cfg = Config.fromfile(args.config) + cfg.launcher = args.launcher + + cfg.load_from = args.checkpoint + cfg.work_dir = '/'.join(args.checkpoint.split('/')[:-1]) + + runner = Runner.from_cfg(cfg) + + load_fix_subnet(runner.model, args.yaml) + + timestamp_subnet = time.strftime('%Y%m%d_%H%M', time.localtime()) + model_name = f'subnet_{timestamp_subnet}.pth' + save_path = osp.join(runner.work_dir, model_name) + torch.save({ + 'state_dict': runner.model.state_dict(), + 'meta': {} + }, save_path) + runner.logger.info(f'Successful converted. Saved in {save_path}.') + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/model_converters/publish_model.py b/cv/distiller/CWD/mmrazor/tools/model_converters/publish_model.py new file mode 100755 index 000000000..e5bf48287 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/model_converters/publish_model.py @@ -0,0 +1,91 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import shutil +from pathlib import Path +from typing import Union + +import torch +from mmengine import digit_version + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Process a checkpoint to be published') + parser.add_argument('ckpt', help='input checkpoint filename', type=str) + parser.add_argument('--model-name', help='model(config) name', type=str) + parser.add_argument('--timestamp', help='training timestamp', type=str) + parser.add_argument('--out-dir', help='output dir', type=str) + args = parser.parse_args() + return args + + +def cal_file_sha256(file_path: Union[str, Path]) -> str: + import hashlib + + BLOCKSIZE = 65536 + sha256_hash = hashlib.sha256() + + with open(file_path, 'rb') as f: + block = f.read(BLOCKSIZE) + while block: + sha256_hash.update(block) + block = f.read(BLOCKSIZE) + + return sha256_hash.hexdigest() + + +def process_checkpoint(ckpt_path_str: str, model_name: str, timestamp: str, + out_dir_str: str) -> None: + + ckpt_path = Path(ckpt_path_str) + work_dir = ckpt_path.parent + + out_dir: Path = Path(out_dir_str) + out_dir.mkdir(parents=True, exist_ok=True) + + tmp_ckpt_path = out_dir / 'tmp.pth' + + checkpoint = torch.load(ckpt_path, map_location='cpu') + # remove optimizer for smaller file size + if 'optimizer' in checkpoint: + del checkpoint['optimizer'] + # remove message_hub for smaller file size + if 'message_hub' in checkpoint: + del checkpoint['message_hub'] + # remove param_schedulers for smaller file size + if 'param_schedulers' in checkpoint: + del checkpoint['param_schedulers'] + + # if it is necessary to remove some sensitive data in checkpoint['meta'], + # add the code here. + if digit_version(torch.__version__) >= digit_version('1.6'): + torch.save( + checkpoint, tmp_ckpt_path, _use_new_zipfile_serialization=False) + else: + torch.save(checkpoint, tmp_ckpt_path) + + sha = cal_file_sha256(tmp_ckpt_path) + save_ckpt_path = f'{out_dir}/{model_name}_{timestamp}-{sha[:8]}.pth' + tmp_ckpt_path.rename(save_ckpt_path) + print(f'Successfully generated the publish-ckpt as {save_ckpt_path}.') + + log_path = work_dir / timestamp / f'{timestamp}.log' + save_log_path = f'{out_dir}/{model_name}_{timestamp}-{sha[:8]}.log' + shutil.copy(str(log_path), str(save_log_path)) + print(f'Successfully generated the publish-log as {save_log_path}.') + + log_path = work_dir / timestamp / f'{timestamp}.log' + json_path = work_dir / timestamp / f'vis_data/{timestamp}.json' + save_json_path = f'{out_dir}/{model_name}_{timestamp}-{sha[:8]}.json' + shutil.copy(str(json_path), str(save_json_path)) + print(f'Successfully generated the publish-log as {save_json_path}.') + + +def main(): + args = parse_args() + process_checkpoint(args.ckpt, args.model_name, args.timestamp, + args.out_dir) + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/pruning/get_channel_units.py b/cv/distiller/CWD/mmrazor/tools/pruning/get_channel_units.py new file mode 100755 index 000000000..cb3f890ed --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/pruning/get_channel_units.py @@ -0,0 +1,84 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import json +import sys + +import torch.nn as nn +from mmengine import MODELS +from mmengine.config import Config + +from mmrazor.models import BaseAlgorithm +from mmrazor.models.mutators import ChannelMutator + +sys.setrecursionlimit(int(pow(2, 20))) + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Get channel unit of a model.') + parser.add_argument('config', help='config of the model') + parser.add_argument( + '-c', + '--with-channel', + action='store_true', + help='output with channel config') + parser.add_argument( + '-i', + '--with-init-args', + action='store_true', + help='output with init args') + parser.add_argument( + '--choice', + action='store_true', + help=('output choices template. When this flag is activated, ' + '-c and -i will be ignored')) + parser.add_argument( + '-o', + '--output-path', + default='', + help='the file path to store channel unit info') + return parser.parse_args() + + +def main(): + args = parse_args() + config = Config.fromfile(args.config) + default_scope = config['default_scope'] + + model = MODELS.build(config['model']) + if isinstance(model, BaseAlgorithm): + mutator = model.mutator + elif isinstance(model, nn.Module): + mutator: ChannelMutator = ChannelMutator( + channel_unit_cfg=dict( + type='L1MutableChannelUnit', + default_args=dict(choice_mode='ratio'), + ), + parse_cfg={ + 'type': 'ChannelAnalyzer', + 'demo_input': { + 'type': 'DefaultDemoInput', + 'scope': default_scope + }, + 'tracer_type': 'FxTracer' + }) + mutator.prepare_from_supernet(model) + if args.choice: + config = mutator.choice_template + else: + config = mutator.config_template( + with_channels=args.with_channel, + with_unit_init_args=args.with_init_args) + json_config = json.dumps(config, indent=4, separators=(',', ':')) + if args.output_path == '': + print('=' * 100) + print('config template') + print('=' * 100) + print(json_config) + else: + with open(args.output_path, 'w') as file: + file.write(json_config) + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/pruning/get_flops.py b/cv/distiller/CWD/mmrazor/tools/pruning/get_flops.py new file mode 100755 index 000000000..409817e10 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/pruning/get_flops.py @@ -0,0 +1,55 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse + +from mmengine import Config + +from mmrazor.models.algorithms import ItePruneAlgorithm +from mmrazor.models.task_modules import ResourceEstimator +from mmrazor.models.task_modules.demo_inputs import DefaultDemoInput +from mmrazor.registry import MODELS + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument('config') + parser.add_argument('-H', default=224, type=int) + parser.add_argument('-W', default=224, type=int) + args = parser.parse_args() + return args + + +def input_generator_wrapper(model, shape, training, scope=None): + + def input_generator(input_shape): + inputs = DefaultDemoInput(scope=scope).get_data( + model, input_shape=input_shape, training=training) + if isinstance(input, dict) and 'mode' in inputs: + inputs['mode'] = 'tensor' + return inputs + + return input_generator + + +if __name__ == '__main__': + args = parse_args() + config = Config.fromfile(args.config) + H = args.H + W = args.W + + default_scope = config['default_scope'] + model_config = config['model'] + # model_config['_scope_'] = default_scope + model: ItePruneAlgorithm = MODELS.build(model_config) + + estimator = ResourceEstimator( + flops_params_cfg=dict( + input_shape=(1, 3, H, W), + print_per_layer_stat=False, + input_constructor=input_generator_wrapper( + model, + (1, 3, H, W), + training=False, + scope=default_scope, + ))) + result = estimator.estimate(model) + print(result) diff --git a/cv/distiller/CWD/mmrazor/tools/pruning/get_l1_prune_config.py b/cv/distiller/CWD/mmrazor/tools/pruning/get_l1_prune_config.py new file mode 100755 index 000000000..877ad42d5 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/pruning/get_l1_prune_config.py @@ -0,0 +1,127 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import copy +from typing import Dict + +from mmengine import Config, fileio + +from mmrazor.models.mutators import ChannelMutator +from mmrazor.registry import MODELS + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Get the config to prune a model.') + parser.add_argument('config', help='config of the model') + parser.add_argument( + '--checkpoint', + default=None, + type=str, + help='checkpoint path of the model') + parser.add_argument( + '--subnet', + default=None, + type=str, + help='pruning structure for the model') + parser.add_argument( + '-o', + type=str, + default='./prune.py', + help='output path to store the pruning config.') + args = parser.parse_args() + return args + + +def wrap_prune_config(config: Config, prune_target: Dict, + checkpoint_path: str): + config = copy.deepcopy(config) + default_scope = config['default_scope'] + arch_config: Dict = config['model'] + + # update checkpoint_path + if checkpoint_path is not None: + arch_config.update({ + 'init_cfg': { + 'type': 'Pretrained', + 'checkpoint': checkpoint_path # noqa + }, + }) + + # deal with data_preprocessor + if 'data_preprocessor' in config: + data_preprocessor = config['data_preprocessor'] + arch_config.update({'data_preprocessor': data_preprocessor}) + config['data_preprocessor'] = None + else: + data_preprocessor = None + + # prepare algorithm + algorithm_config = dict( + _scope_='mmrazor', + type='ItePruneAlgorithm', + architecture=arch_config, + target_pruning_ratio=prune_target, + mutator_cfg=dict( + type='ChannelMutator', + channel_unit_cfg=dict( + type='L1MutableChannelUnit', + default_args=dict(choice_mode='ratio')), + parse_cfg=dict( + type='ChannelAnalyzer', + tracer_type='FxTracer', + demo_input=dict(type='DefaultDemoInput', + scope=default_scope)))) + config['model'] = algorithm_config + + return config + + +def change_config(config): + + scope = config['default_scope'] + config['model']['_scope_'] = scope + return config + + +if __name__ == '__main__': + args = parse_args() + config_path = args.config + checkpoint_path = args.checkpoint + target_path = args.o + + origin_config = Config.fromfile(config_path) + origin_config = change_config(origin_config) + default_scope = origin_config['default_scope'] + + # get subnet config + model = MODELS.build(copy.deepcopy(origin_config['model'])) + mutator: ChannelMutator = ChannelMutator( + channel_unit_cfg=dict( + type='L1MutableChannelUnit', + default_args=dict(choice_mode='ratio'), + ), + parse_cfg={ + 'type': 'ChannelAnalyzer', + 'demo_input': { + 'type': 'DefaultDemoInput', + 'scope': default_scope + }, + 'tracer_type': 'FxTracer' + }) + mutator.prepare_from_supernet(model) + if args.subnet is None: + choice_template = mutator.choice_template + else: + input_choices = fileio.load(args.subnet) + try: + mutator.set_choices(input_choices) + choice_template = input_choices + except Exception as e: + print(f'error when apply input subnet: {e}') + choice_template = mutator.choice_template + + # prune and finetune + + prune_config: Config = wrap_prune_config(origin_config, choice_template, + checkpoint_path) + prune_config.dump(target_path) diff --git a/cv/distiller/CWD/mmrazor/tools/pruning/get_static_model_from_algorithm.py b/cv/distiller/CWD/mmrazor/tools/pruning/get_static_model_from_algorithm.py new file mode 100755 index 000000000..8d28842e7 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/pruning/get_static_model_from_algorithm.py @@ -0,0 +1,82 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import json +import os + +import torch +from mmengine import Config, fileio +from mmengine.runner.checkpoint import load_checkpoint + +from mmrazor.models import BaseAlgorithm +from mmrazor.registry import MODELS +from mmrazor.utils import print_log + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Export a pruned model checkpoint.') + parser.add_argument('config', help='config of the model') + parser.add_argument( + 'checkpoint', + default=None, + type=str, + help='checkpoint path of the model') + parser.add_argument( + '-o', + type=str, + default='', + help='output path to store the pruned checkpoint.') + args = parser.parse_args() + return args + + +def get_save_path(config_path, checkpoint_path, target_path): + if target_path != '': + work_dir = target_path + else: + work_dir = 'work_dirs/' + os.path.basename(config_path).split('.')[0] + + checkpoint_name = os.path.basename(checkpoint_path).split( + '.')[0] + '_pruned' + + return work_dir, checkpoint_name + + +def get_static_model(algorithm): + from mmrazor.structures.subnet import export_fix_subnet, load_fix_subnet + pruning_structure = algorithm.mutator.choice_template + + # to static model + fix_mutable = export_fix_subnet(algorithm.architecture)[0] + load_fix_subnet(algorithm.architecture, fix_mutable) + model = algorithm.architecture + return model, pruning_structure + + +if __name__ == '__main__': + # init + args = parse_args() + config_path = args.config + checkpoint_path = args.checkpoint + target_path = args.o + + work_dir, checkpoint_name = get_save_path(config_path, checkpoint_path, + target_path) + os.makedirs(work_dir, exist_ok=True) + + # build model + config = Config.fromfile(config_path) + model = MODELS.build(config.model) + assert isinstance(model, BaseAlgorithm), 'Model must be a BaseAlgorithm' + load_checkpoint(model, checkpoint_path, map_location='cpu') + + pruned_model, structure = get_static_model(model) + + # save + torch.save(pruned_model.state_dict(), + os.path.join(work_dir, checkpoint_name + '.pth')) + fileio.dump( + structure, os.path.join(work_dir, checkpoint_name + '.json'), indent=4) + + print_log('Save pruned model to {}'.format(work_dir)) + print_log('Pruning Structure: {}'.format(json.dumps(structure, indent=4))) diff --git a/cv/distiller/CWD/mmrazor/tools/ptq.py b/cv/distiller/CWD/mmrazor/tools/ptq.py new file mode 100755 index 000000000..2c00c5b11 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/ptq.py @@ -0,0 +1,73 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import os +import os.path as osp + +from mmengine.config import Config, DictAction +from mmengine.runner import Runner + +from mmrazor.utils import register_all_modules + + +# TODO: support fuse_conv_bn, visualization, and format_only +def parse_args(): + parser = argparse.ArgumentParser( + description='MMRazor test (and eval) a model') + parser.add_argument('config', help='test config file path') + # parser.add_argument('checkpoint', help='checkpoint file') + parser.add_argument( + '--work-dir', + help='the directory to save the file containing evaluation metrics') + parser.add_argument( + '--cfg-options', + nargs='+', + action=DictAction, + help='override some settings in the used config, the key-value pair ' + 'in xxx=yyy format will be merged into config file. If the value to ' + 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' + 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' + 'Note that the quotation marks are necessary and that no white space ' + 'is allowed.') + parser.add_argument( + '--launcher', + choices=['none', 'pytorch', 'slurm', 'mpi'], + default='none', + help='job launcher') + parser.add_argument('--local_rank', type=int, default=0) + args = parser.parse_args() + if 'LOCAL_RANK' not in os.environ: + os.environ['LOCAL_RANK'] = str(args.local_rank) + + return args + + +def main(): + register_all_modules(False) + args = parse_args() + + # load config + cfg = Config.fromfile(args.config) + cfg.launcher = args.launcher + if args.cfg_options is not None: + cfg.merge_from_dict(args.cfg_options) + + # work_dir is determined in this priority: CLI > segment in file > filename + if args.work_dir is not None: + # update configs according to CLI args if args.work_dir is not None + cfg.work_dir = args.work_dir + elif cfg.get('work_dir', None) is None: + # use config filename as default work_dir if cfg.work_dir is None + cfg.work_dir = osp.join('./work_dirs', + osp.splitext(osp.basename(args.config))[0]) + + # cfg.load_from = args.checkpoint + + # build the runner from config + runner = Runner.from_cfg(cfg) + + # start testing + runner.test() + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/slurm_test.sh b/cv/distiller/CWD/mmrazor/tools/slurm_test.sh new file mode 100755 index 000000000..3c74ec6ec --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/slurm_test.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +CONFIG=$1 +CHECKPOINT=$2 +GPUS=$3 +PORT=${PORT:-29500} + +PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ +python -m torch.distributed.launch --nproc_per_node=$GPUS --master_port=$PORT \ + $(dirname "$0")/test.py $CONFIG $CHECKPOINT --launcher pytorch ${@:4} diff --git a/cv/distiller/CWD/mmrazor/tools/slurm_train.sh b/cv/distiller/CWD/mmrazor/tools/slurm_train.sh new file mode 100755 index 000000000..b3feb3d9c --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/slurm_train.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -x + +PARTITION=$1 +JOB_NAME=$2 +CONFIG=$3 +WORK_DIR=$4 +GPUS=${GPUS:-8} +GPUS_PER_NODE=${GPUS_PER_NODE:-8} +CPUS_PER_TASK=${CPUS_PER_TASK:-5} +SRUN_ARGS=${SRUN_ARGS:-""} +PY_ARGS=${@:5} + +PYTHONPATH="$(dirname $0)/..":$PYTHONPATH \ +srun -p ${PARTITION} \ + --job-name=${JOB_NAME} \ + --gres=gpu:${GPUS_PER_NODE} \ + --ntasks=${GPUS} \ + --ntasks-per-node=${GPUS_PER_NODE} \ + --cpus-per-task=${CPUS_PER_TASK} \ + --kill-on-bad-exit=1 \ + ${SRUN_ARGS} \ + python -u tools/train.py ${CONFIG} --work-dir=${WORK_DIR} --launcher="slurm" ${PY_ARGS} diff --git a/cv/distiller/CWD/mmrazor/tools/test.py b/cv/distiller/CWD/mmrazor/tools/test.py new file mode 100755 index 000000000..a69133158 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/test.py @@ -0,0 +1,80 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import os +import os.path as osp + +from mmengine.config import Config, DictAction +from mmengine.runner import Runner + +from mmrazor.utils import register_all_modules + + +# TODO: support fuse_conv_bn, visualization, and format_only +def parse_args(): + parser = argparse.ArgumentParser( + description='MMRazor test (and eval) a model') + parser.add_argument('config', help='test config file path') + parser.add_argument('checkpoint', help='checkpoint file') + parser.add_argument( + '--work-dir', + help='the directory to save the file containing evaluation metrics') + parser.add_argument( + '--cfg-options', + nargs='+', + action=DictAction, + help='override some settings in the used config, the key-value pair ' + 'in xxx=yyy format will be merged into config file. If the value to ' + 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' + 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' + 'Note that the quotation marks are necessary and that no white space ' + 'is allowed.') + parser.add_argument( + '--launcher', + choices=['none', 'pytorch', 'slurm', 'mpi'], + default='none', + help='job launcher') + parser.add_argument('--local_rank', type=int, default=0) + args = parser.parse_args() + if 'LOCAL_RANK' not in os.environ: + os.environ['LOCAL_RANK'] = str(args.local_rank) + return args + + +def main(): + register_all_modules(False) + args = parse_args() + + # load config + cfg = Config.fromfile(args.config) + cfg.launcher = args.launcher + if args.cfg_options is not None: + cfg.merge_from_dict(args.cfg_options) + + # work_dir is determined in this priority: CLI > segment in file > filename + if args.work_dir is not None: + # update configs according to CLI args if args.work_dir is not None + cfg.work_dir = args.work_dir + elif cfg.get('work_dir', None) is None: + # use config filename as default work_dir if cfg.work_dir is None + cfg.work_dir = osp.join('./work_dirs', + osp.splitext(osp.basename(args.config))[0]) + + if args.checkpoint == 'none': + # NOTE: In this case, `args.checkpoint` isn't specified. If you haven't + # specified a checkpoint in the `init_cfg` of the model yet, it may + # cause the invalid results. + cfg.load_from = None + else: + cfg.load_from = args.checkpoint + if 'type' in cfg.test_cfg and cfg.test_cfg.type.endswith('PTQLoop'): + cfg.test_cfg.only_val = True + + # build the runner from config + runner = Runner.from_cfg(cfg) + + # start testing + runner.test() + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/train.py b/cv/distiller/CWD/mmrazor/tools/train.py new file mode 100755 index 000000000..8b150e5f2 --- /dev/null +++ b/cv/distiller/CWD/mmrazor/tools/train.py @@ -0,0 +1,121 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import logging +import os +import os.path as osp + +from mmengine.config import Config, DictAction +from mmengine.logging import print_log +from mmengine.runner import Runner + +from mmrazor.utils import register_all_modules + + +def parse_args(): + parser = argparse.ArgumentParser(description='Train an algorithm') + parser.add_argument('config', help='train config file path') + parser.add_argument('--work-dir', help='the dir to save logs and models') + parser.add_argument( + '--amp', + action='store_true', + default=False, + help='enable automatic-mixed-precision training') + parser.add_argument( + '--auto-scale-lr', + action='store_true', + help='enable automatically scaling LR.') + parser.add_argument( + '--resume', + action='store_true', + help='resume from the latest checkpoint in the work_dir automatically') + parser.add_argument( + '--cfg-options', + nargs='+', + action=DictAction, + help='override some settings in the used config, the key-value pair ' + 'in xxx=yyy format will be merged into config file. If the value to ' + 'be overwritten is a list, it should be like key="[a,b]" or key=a,b ' + 'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" ' + 'Note that the quotation marks are necessary and that no white space ' + 'is allowed.') + parser.add_argument( + '--launcher', + choices=['none', 'pytorch', 'slurm', 'mpi'], + default='none', + help='job launcher') + parser.add_argument('--local_rank', type=int, default=0) + args = parser.parse_args() + if 'LOCAL_RANK' not in os.environ: + os.environ['LOCAL_RANK'] = str(args.local_rank) + + return args + + +def main(): + register_all_modules(False) + args = parse_args() + + # load config + cfg = Config.fromfile(args.config) + cfg.launcher = args.launcher + if args.cfg_options is not None: + cfg.merge_from_dict(args.cfg_options) + + # work_dir is determined in this priority: CLI > segment in file > filename + if args.work_dir is not None: + # update configs according to CLI args if args.work_dir is not None + cfg.work_dir = args.work_dir + elif cfg.get('work_dir', None) is None: + # use config filename as default work_dir if cfg.work_dir is None + cfg.work_dir = osp.join('./work_dirs', + osp.splitext(osp.basename(args.config))[0]) + + # enable automatic-mixed-precision training + if args.amp: + if getattr(cfg.optim_wrapper, 'type', None): + optim_wrapper = cfg.optim_wrapper.type + if optim_wrapper == 'AmpOptimWrapper': + print_log( + 'AMP training is already enabled in your config.', + logger='current', + level=logging.WARNING) + else: + assert optim_wrapper == 'OptimWrapper', ( + '`--amp` is only supported when the optimizer wrapper ' + f'type is `OptimWrapper` but got {optim_wrapper}.') + cfg.optim_wrapper.type = 'AmpOptimWrapper' + cfg.optim_wrapper.loss_scale = 'dynamic' + + if getattr(cfg.optim_wrapper, 'constructor', None): + if cfg.optim_wrapper.architecture.type == 'OptimWrapper': + cfg.optim_wrapper.architecture.type = 'AmpOptimWrapper' + cfg.optim_wrapper.architecture.loss_scale = 'dynamic' + + # TODO: support amp training for mutator + # if cfg.optim_wrapper.mutator.type == 'OptimWrapper': + # cfg.optim_wrapper.mutator.type = 'AmpOptimWrapper' + # cfg.optim_wrapper.mutator.loss_scale = 'dynamic' + + # enable automatically scaling LR + if args.auto_scale_lr: + if 'auto_scale_lr' in cfg and \ + 'enable' in cfg.auto_scale_lr and \ + 'base_batch_size' in cfg.auto_scale_lr: + cfg.auto_scale_lr.enable = True + else: + raise RuntimeError('Can not find "auto_scale_lr" or ' + '"auto_scale_lr.enable" or ' + '"auto_scale_lr.base_batch_size" in your' + ' configuration file.') + + cfg.resume = args.resume + + # build the runner from config + runner = Runner.from_cfg(cfg) + + # start training + runner.train() + + +if __name__ == '__main__': + main() diff --git a/cv/distiller/CWD/mmrazor/tools/visualizations/demo.jpg b/cv/distiller/CWD/mmrazor/tools/visualizations/demo.jpg new file mode 100755 index 0000000000000000000000000000000000000000..dd613cee3bc13a3677908d7d6f1899e8278a4b47 GIT binary patch literal 259865 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

    xGF2ym!j9*!x^ZN7JorIS zGv<~b1U15iwIa#vXb4F=iliAKs1ZVBg%P#FsO;#Yt&{b+jrs98ki+is=GMa6`t;($ z$kd(f!_~=o$oAaY^uW~O_{!?^PHW9zOZ8}D`Djv9d3<d5BK z% ziC;c_$-nRZ>yQ8N#XG}qcdmSe3{0tw%x(o~`=``(&0pr$O}j^yIENO1!)^U@ zePb(JLi63id47o{e(?n@Bde{WYmNPjO9zi1ee~O%d!Nkh-*n9$rIh!0CluQUW*9m} zBB&LdQrk9pQa^eaSv=^P(#ZD9M)j|jH(E-$m}sHtSAj}zWzQ0pZ#5zneBZ$f{X}(Y zp5=&LXb09K5{~Q@!W8gBWgW|8ok|s4%4BTw5I?t$X?ITUv5ss|bFScliKy^0m=xKf;Sanm$0vvit43T#(C9`xc#`Uyh% z@h~P~Hh>>M7cv$(s*WWJmU)s!=`?mMSu={F6GPRF1qMJ1Km~;O0T}%EfQMG3utq46 z1#Ec>&sYYSC3YAXZj|0mv&aCH>L&_ zdRrzk6U*|_>a7g@(qbyI;;O20JJu%;N17&QdlpApMi&O>ao^tc-rei{J1;J-PgmA= zW@Zs+h1+tyv;A;?@6{dtRSVy}c>d$tSHFDx8XoS?AH9Hl_UPiPr`NxH`~m`n0)h7V z{OSFVA6~w`I(u^G@Z(4K-#mN>PTSqsoSK>%9>w*3o3pc(855(;~w zbDG>D@;E-J4v~eiC4K1)Q)pJ5KKp3)?4zd1$vpUdw#_$bK}h z+bW>Y%%{N6s{rR(9jOpBlz9}(yA>;Wl&ksGY6Uc@detbo<3a(1xJ&pMF{d&y+Y*E? zU@%D7mxAltx?Ml8THYoVZi}*Qin?QlnoXK@NS$4Hy_tWho_n6Y zcY$?8t!;FZkza+99aq{S4IrWE$3u6Zt`F7)K_lkYMTG-G(u#*F5iv+nwkeP`&yp}m zWUyms+7VQ(a0>QaE0m-aO4N)1HUJe+2fzSG2&)G}NURXDMku~E*fk01ZXE1t>|2>y z2SNthhu3E}$GS(iX4Yp1Ca~@-?BGZ3wY}|iL-7$gzAkajR-v}0{?Y#2jOgN$^oIVL z(cz}?p{C)f-s#=>?ak@6dk5zSOB*P+LVOkS#gm(R+gs1iPOrAManHhwlQRr2MF8ZR z7muJ>aIN{<%abQ3+b{3zfBfJMDoJi{6+{y7dT-Hfpx-Dj6~?(XiM?d@+YuM7+g zHMVuuGnj(W+BB!euWV0@Cp;3+<=UhxRL>@up;B2JRR>04c8QWN5?CZ6I_52zTCEz zy0N3~g{zkFqrAEa&&Ygh@1*dI244M4Zo_>{>}3B!b7kk^_ zkW*3EP{ghEa*nVy_j9lcwl?!i2rswnv2!kP|#bBoVamt zg@JzonhG&h(k!}Ck)I<&Vm*cJSD@*QK_yw5o;gN=MRw5@UTIC4brVe!haFRg72OMg z$ra8KxhZA+MXd`FIb9t8JXQM?9sg3zplXfqW=Z!-nnM}gp^9!_O|!0KSXYQzp{TD^ z%(|RrSwgogg9w`zlFW)ooI-whoRd#CL#um{VQ{lSK)s?}9(G*RC`r;JNy;oq);tCO z1OuN!U_;X-6RVbMwn;##ZA6oycd0xlg`pEg*Nvs?#E~>2h19?d(F_}Y~&FbILJ z8!c&+Af_Kn(+s7k1@eUzEUXgT-s;lM%F6xA zi^q>{s%lyiQwnkm+dTZU>^w6$Zdn|kJiGAn@ce<+xd-W$Gx{zWidM-`&`S1MT3*Gv zK4=#$R&&pRL{={*wd`QFDtbt@yi3$Q^0A?^4#|4(7ZB`MHA7X`VjJZ=DXyY7EV4PQx`@B_o`WQfcdCc({_T z#bPeyq7KzGTSzU#rdG_lf?}LcH7jITlnNQ;LlDcNBJ62V%0~-_CjxkwaK$*;sxIhk ztyOa=fnfj(LEI#TrV~Zgi4Zf0ma~XgvrA^XW*K_rX*s1UTPEtd=2!()nRt~dnk9+r zL^3o(Mc5I*0GL6D6-3ks#tH#xi0Z{i8^q!}bXG7~H9$ZufS~G6Q1Qbmq!vI_@rMYj z1_&$r2`Ksy+bhfZ>#Bx3Tj%n!8*0jW8>$8?OFAoxJNmk2iwj%J3fi;MtD{2m z6JtspY$7d9gZ0>6I$9padcN*XNr7HDo(_rmsVzn6t@$Z+ZPlZFjgu=Ad-J1fqg_** z^V?U4m-|aw@OSQP?qYrvGJ5ZyKHpndI@{QKae41}b^YG{0q&H1eed%9vnL2?KEFDD z{oo37y52s%e{*?`Sk}Y4caOHV9$aE1_1W?qLYd9Hdl*$TrsKv{c1Xd&*YYVqnT@)80o$ik)g@2ElUFwNfbEBX zbDpMO5x;HFJ(p>pr0SmOojqt7*`Q#Xq3>U%|hpYq7FRk%&4Y+kqht(1RjuL--LhEL@rp)a+BS)%Zd_CMY<2TkhPoF?)r+nbK+y~!vHXP8 z{0U0lf~x)u-AJZUyrf<@ zh2_)D{p+Lig`u&ly`zUGXUGMki|X$F{^b#-$gZ62?A%;kAr*)jp=bL?%X15}GYeC* zOBGeE)pfnK&0`bu$F&_ZQQSHcuLS$3B18XNb(eHacP=Q`C9YB15r$=Dao<5y`2;HN zlpN3ulFxE0RC34xndteJ$l4?%Hm$g2_s}_!@&JYlR~ZdNo?KOzjNqb4)3AE<9mCf^ zwnEvnLczO2&aa&5TO#LQsv1_Q5mloZjvm!wqtHr}@t}nnD#<&mGpBtmt#&@Sd^(gn zWF1tiV38${+8c`kx&?Gc0dgXOM!7`8Tw$X;VPjP5x z!_C~%Ii6XnoJa=CgQDh6R`(QE^`dC`Q(68*Wgn_qfFuy2A1$gCN>TSAssID71bLTR z5s-C;2+Fw#$-4?Gx~F9|CZ{z-#g;?xkeE^z7Fp~UkQ*FYn4H?^>7D8AmF4S`>*JN{ zXp`*jnC0c1>+fA07F6Y6lZJ<2pHd&!{OY3FFu&5I@am|5qP&#m+~me$ZhLA>XDI~i{Px!TCVZl!_5FjDt^L*Qhv%0^TiYi) zyC?jx{mkjX;l}dn((L@=^upx$Y){{0aaCt_Nm~qfETgujXSuF#mDf0tSlY*Sj&+Kw zw!xr0k32)aQhl#NEvGCbvoxKP&>oWBvKq)6X1Q?HoPnP_btkTdYc^8nk`|G;blWR` z0HZijp@;HL)ck7&U?wNeJ`JOQ+c7H-eyFlnxw22CihqrAU@b&7xK<^oM$re&M2+mA zMkUWOgf*lbQJa^JdOv8cpuCZoqM4k=?aaDuJ@*nOiu}#e8JsKt0OY`@2;)qODHpXC z1f3-0!UXk_P%;4_up*JjKtB;tH%^EhC9EArW``HEfT`~E8@Z%A_A+DV_MS_I-^5sxhcJo zffdm~6$zo0+{EVSz~ZvJz96s6nv$X9sN$-^?#}wLw%WmF3^%Cln;%_;x|tbTTAAFO z9GG1gTLQ6656vu3FQKXbbnkd=e&u-gXlHGEZfbr5j_Tz6(%ec#WphpAKpL+(Ir%B&nSa89xgDY1*J(RR(%aL$7z4>v^HBU8aLTH7_lGqo+X zZrLfmMZqc&+#+Kg%l6Gxa!O{}$D2f!2NjRP@|1HC2|drYF6Reee| z{HxUcsv)d^dUj}wZd8Y6NUMTpjfh2ogiQ&25Rw^}f#QF(09a#8iO3n;rM^R-5Q58E0RXb@72Sr^E z6$5W210PNE5PiF7UF&G3ju&0oURc(WEN24|khTzFT2Yl87%C1_MO(ZVl;#kmIf6`! zTOr9=LGV5xG#9{d_RethOn3Ci^a?Jr_sE2G=j4+W5ME&C90LxCi>;1}s*VmR5A!QY ziD}A6Xv<0M&Pr}ePiRhwZGfc3H^oO($A(s<#WiLmG{=WmaZ_5u0}6A~+frgGGZX77 zdA+=h#)`c5#IXE|{8nyUNke&0SN(8D!(bb3%<7yh%d6^dADSMX-Co(A8=qTQSld|H znweVY?;RfK9jmKuX>A`0kIj$CtVQ<9A}GtyKLd(h!8kB5p>AmEyr6W1hf4%}vP09m zOnr;l?nPoI337I6OshoL^O}xns^+oU_Q|2SeW3;YsxC>=wy~1dv50UgyQZ^TGpxeO zB1*504d8>YO{Q6IP7`icS!cDGeV&TP1SNrP7Wi3~L?=Z=fm2 zCOir2axwE_nqi)pX+F(>%P`D zLG^INw2||o=p`Xs38MnOBvCC0W+Y7`2;?uO86qg>N>cK`sTXDYs9Hx$8wTNMQ&rq) zN*-i+SE{@lS=OE;ZB3W6rpQ?kWzEP67BodmF*Q3`Ef+a$S4Fm)nt`{5u^(1h4JU>? zha_c4k};;rnL#K_GpZ~HD@oc!K+^EvA|!20lrez>hULN3ck)Vi^UL-RD|PhZy7=Zg zcxC|`(Fx_j;d${16^Zdx8OaUYl;-@*j>@88UV3L{Dbd5+yAXm^LX)^8|TLoT_EKhFy|^ zWdz$J6%DNzfFNxfkJ%qhk_j{lp;sNPWXPB(c;w+yUDv#Ey^uN$ z-|`O=S@RLhMEw;icxjv*k}2xC3s6%*GtLz?=1G_oF!Xb1x|uYCEabaI_^qZfGMsoB zlL)p`nrn1zTIIZJOoM_+3|ZAjLN8LxAO>+r%7;ib%n5$Di4{yz@h2(!QdND(3LX@B zcdDX0P1%j2+oSnV_^OLCOewD$F#+ zc2k)qVhR>AYIcfR4k|j%8bkSL7#G*6`YMQp(HooAS~s8Y_C>I~V8F)ReZ=Rd)1rj8v93RF^lk zw+;06jK#%ghJ_{h1|~Ojuj|_V5zWAVE{}B`J9lWnIZY1sFr#i3nzpwG9DI<#EglFA7J;Tlps5Hj)W{MVbSX`W zxVkVyktU%g%G3~%){s{>VjI|L>Dfrj>(C|DiF5@ax*SPVkt8NB#9$IA5(KKGFhfR| z&h!sU$GzOp9ln8Cfg$;DQc^RTa`QS1i@O_}#wshjYpQx%8%Nq2hQa?+gR4!Iz0*T$ z?TsVt4Wr95ht@m6tUX7u9gHOB$Q|c*S)Q z(V0$e5vF!waak=&dY&q#{tCvviY9(qwvl2i2YI%es)47KTb#D3m$_3IGOESR!@3SZ z%2p8)#-SpH!D6NnqGpj|7SWQHu}r%JX{%@@$9M$Bl^tSHL;w`4=^AiEv)WKQuQG!BT(Qjq~uOk^9C^JELRbhi=eEftbw0fbcLx`8e9oQ6MsQj zjsVk4K+1$5VMGu&!~>8ZEW*=9bpZfjNgaw58|nbtEh?kKR5rmX%ut08=_(X4 zmJm&uKvNW;D+w_aAVh{di6Kv<$q3V=C?ZS|F?kA2T9_h^l}wYQGnmp$HKrU(Rb5|6 zU5_E5AV3m>5FkP{z7XjIA%?Y6pp8>#KxkG}TuC~&iC5f{oL*Oiphsy}9Z!Ihb@&Ec-O<*B{Nfz{!zc_3%3cX45S z8(+g8K?Ht#X@6sGdv9qEPV33q;la}G?)=vL;LQB+JUo=Sp}Dc1iT>81-j>0h)}f}l z&X$Jm)|NhyMnqIf4zDUTvnVD$$H_g+#LCwRW~F54rEK6S!?KrA zw*fFXj^Wa(97DSROl>M?9MN%zmNE1Ldq|lCNpix)Eh8l?qv@t0a*l~&oDg}t7->!@ z(<0I+fR|7^XBl3>a>_(OID$($9!1Ux-7;oLqWaNHPO_wNJXJeP)jk_$Bth1VsOpD6 z0YQ!*7Qntk1Qp#NBxN_UiaS<8c_)IbgOI#~u%Z)$q~r{Pfuv|BtY8Uqk)diUqGCgo zF*b6FF>r{|;P`5q`$?!XMPDME0-Ng_%VQAM(d z0z*<+Rm)6>DlJ515=asRL2Rpp09g_uM3E3Aiwjc3h-5KA5?z2u6(V7y$pk@?0Fgov zqVOLC$by0tyr)2IxOsDW#Wwq>;jl5-zycuj)Q6oPo zs|XQJn6SPdSu5U)SOKh{GeweC7qKtmHt`pZOq8>hixONai z0Tg97?6s0{I6=aaAZbBUb|y%eLCEsfa1XJ<>7yxFQROXh-igwtLQ*DJZ=bR9MameQ zPhr9^&=(S8Q<(-78GU^le-pbPISnfnJ$qSo4oO^Hkg6m=RS=*k3Nw^J^&oZz6DTs4cD{D5VV?d;pbo$z zBBrRQyr;0NJ2S7Le`ql&nb+4h)7L%K-!<9QHZ(uIJ~}vi=lFh8Lr+KRNKeny%*@u( z(!oIQOncMdaL;sC^U(an>f+QolKvYD+hctbn+sbT3+qec^Qa6#AQUA-s82rK*g9U@ zI9lJ_n4O;+9z$8t;`r>sr?G%g$84Vi+ zV-HDv4`G&rkcKnE$RDJE9(FmaXl0vtDdSKX<8Wn*81K0Hu=F+wmYbx8yQs3GTWATw zj6^98Rn}Zs%0yJbQb0r(x?WI3hrrOJ%Nh$XSg`a+qFRC?8U(sJjyXOGiL&q>Z-`=A z5Io<04ey1;)CCzTx4Hm4Kp@EyNYV=GCbllYk_v2briMD(Ojc1_2*+Po90FGVaFB7* zX*mA;9VZY81R+6?06_?w%am7Uh)D1`fgr>u1i}a50|P7p5hf6X2?F>d{68fiOcNqA z2%r%%gG3XiOA|uWVD1OG?ZDUhUOmjt`QFI(cVF6 zff3oc#cf%rkb2l-PDuSv?5Ma&29!%IY>r8BKY0GZ952 zni5Aw-(AHjMA0%t#X3^XG(WR!@K;&ydm-m0~d@)C9=T+Hyi9X+dErVG{H>6GEg&5y>*bRB8NFkOEsyj!2Uw zkfkB`KaV%q0%!sLrVEO|4B&5yuqgH&|1L8N2Ng9P06n3Tk>o#M-^mgJG$|ronj!%sgh`-Ek;N6j z3<5M+vbZu)T!}2HMv~GXN~jYhHEDACqDp2AWiu!^F;z_ zxZo&mY-&kTW`%c9ayGB7q_QJFzpl0xIhV$~+?vJ3{nplDD4O<;vA)6i?!K9p_R;yJ zgXWf@nc3~GuCdwa^}epL86;4q*VdQ!4z^EF?7g?Xx4X8BjsOHahq?!LRyWWswYRo@ zyuE$2y|KN#yf!yKJu=?c+1=UN)z#MB*wDhw%FX8$yL!mQdUme z-qD9jXA%fBDri=a21;j$GKGYoj!9UdwV}Ij)i?G_fKTZ-<2dg$KFRa7HiaO7XBvS3 zs^_l)LLwh_93MdiR4N0%mMktUuW!UrWwG%~B&6juwDlO`z|sff@OCAOW9x}jNeJ`{ zRx(3Ih$bZgU7*4yi7>J0@IVO+B|$M&Y&Th26FV*}$pX9L8E>evx(o#<&|~x4DAez9nGvfeS;HRd?KwK z{m>R#Sk@XDmy?@YQ(D?uz^kvW>Vkf$tZeV=pRK9wuBz?s=$=eYFBlqIZ0{Ty9G>g! z932{(8-<0ruroX~Ge5Vnys&w8dEKRMD&`3K+S9f<`8eNRW5V3c5QDtd6dwA0& zm^5)&nuLO?mI*^rl`5tL3k?UBDxtzu(HD_nY3N#lVFH3;Dr(xJ<8ovb4Vg;DIR3Ee z1?Vv8`D&d&ktYaC3)AEUh*CfTQCN&9#DLIgQl1`x9_|5nR#w)~(9i{qlPL_SX(1v- zm`ouGfvyFFVAK(aeBtYEyb869Dy#6O(%*e3osM}XmWIEmIzZ5A0hYxUMgsD z#N_n^VYNzXk>w19WekL*^eA%1B&H!zTAwO!LXqb%l&z@BmLvrZ0;j@q9HP8AS;>l` zYC~4Brl{D`)g9nK@!cp*cQGw*5Gg~;OHw~TLP}9hU0+mOL0!Yh-q}x1SzFK8+RoW0 zEGpH-D?BH^hRdx?OD`@jYfDKf0BMw!wNzGhR8+QS=Tz1-bO(gQcXW-mv<=qQc2-ul z0v?_1!?QDMJ>8?DBXeWJGbp>5pIV+81vM-V^^H`Q*MJ#D`$vF~xyk9a#wMVuyQ6Dl zc)Y!}yS}!$q_i?FJ~=cz!o$m3-_S@?o6WJXbaVG6k?C>@it>tzW|mgQ9CIjHGF==e zRD!9hsHTh6(A3`9BM>%;Uuc}Sf0T{0k0MK7L|WO(&eO*~R$PijqRJ5j#HkELf)I2x z$QnyUL=jnGQGNgc(Ig^68J32yhzeiC)L?;7 zrL=%mF?oG39$89DP0vnV+mbB7f+;1fVJWR;OOZDcl+q!~=+otm!TBU%buoUMN_qvZ4WU`Hz^%2ikc%$-G!>= zOj32CsJn=0dy+L=@j%h=5YhG))%KOt3zRhulQs&KG7P~gAqm1H=|Zo#`oiedVjDA| zo-OTc9XxCtytDHw!@^UOQu6Zhs-vURGc${ei|e`E()@zz=-7%WGSkJM;4jdwT|A zW0RYkVb65s=9lpbD^t_+eEdU9&8;P6nOg?XuLK-!@$JO!zWybC@GGU_`e3*2e#)M zX+)@UFgf;@Py4qvfDi-r0C*dYzlE)vh@|4}aps?NzD^ehhx085vNS9TcoQ%upuveE z3PPev1e|VB6#_&|RX|)#NJ4`otqmrpFm>Ufh^yL2sM(4rS&ArHiK^Nn2?9Zy3_gyC zvMs`%QX0-`WmhICt6?23$#w(t<2~X$ z8a5H)I-X)|4+&i_X#-zLT_1*q8$?3KTU^_Rrs08H4A?+iKS0_zM8+hPX&R)1pW*sB$Z+ zn(z^&SQ-!bszL0YW0u1gbdynI9045~Rx!$k6gQ z@_hCt;G0xgLAt!AG4c^M;tKkREJ1NYp+l9^Wp#;S8c0kCh_Q%L+9VkrqKqC<)_|gD zBCNm{lA*)qPp~qf;80r zWEG`l6u=?1bMQ({=P?yEwe&a+PQE$@RyOv&_?;YUF9+8UJJ%3%J6~-hJ6Sb7BP$nJ z)UfTDN^Ja1)U-`;RAFF*$7YC1t4hjgz_fr5P7+g=P|)G)Vuk`g7a*btEesD=TFpRM zLXj+`Op#VIwe=FD%30X^3DK31IH1Y0g(O)t1wA3yY_e?FW@H&1s+>M}o1w%JRk6S- z&9aeaJIZL-N~v2T)TVCatz#7;ENukEEvjk*4Ng}=nj5)n3#y{^|D9<5nUysTP&5x$ zwv1G?ij@Dbq1aP-vv54inMWejCX2WVgcB*M7l0KWw6rmQn~;)|w}}3*Q-L_nC@qjP zL*U(yuH}P0#j~tw1U^DUb^Ni>5HZ~V34LrRe+35QIZTtY?- zT9_;<3qyzs7FE+#*5)W_aWwU9*+veArf#>Qsbi~U;2^7F?C24$qGc|pqA#y%0H_$6 zI2v2H8kxIT*m-Lk*dSCD8lB7 zLDfh>-AqHzPDAhi=j$z>>rAqJ%?}fCr_br?VkW!HAeJl(EnAYsENy0HW)d^AEHD&y zHJ*lZ&b@ag=6{VvPUI!7%xsyaTsR?o4~S9e>X^0V75w;uG}Z0Nn$I&!~ll<{`c zAn$xt(eYJf`<3dB&u%wA8nO`gsDG?(=+u6EyX{I{@8@+rR~m=DY8d#sVffmEv2W_f zZZuAQT{r$&<c$^xwa1z0st()~NcdYUIPa{hw3} z@wfkJ)%a)C;xC%!2^1e)YqQcnfqrh+I-KO5kxE3#3DpE&He1EmYA4g|lU55^${#iv zIRX5r(ezcDyZ6UOe2zo_{9dhN&GR5QNw>8-DBHB>kC zeDLMHrYEDfsyeC~dl8TIX7%Hnb)8o$+cD9fU9J7*PV?2 zYV;I{Xtnn0#!ZpR=D~)?6A!yo4V|j4aZkfjeQk%jvVE$qQ&;gwMQ4MmPD5R<{a%N@ zs@r<&k^XAa6k_rHx_;zJ!|0t>HEJ31-F!H8zukDdRsV6-&`11fKUBSQzyDUJ^=h*Y zxBTZyVQBCk!v-7JK4=K%`wAkOO(f+1Z_ud23dksd! z*S>z_`MS-;G4Yi)2TeJ?ZZUn?WOyIy9%#RAwSL)b{)m6#f&Sxq?c4Xq-l-UWw{il6 znEdA6C=>ZK`SOj&4!-;;)YWVG4qtw+Y7)K0GQoOLG0ucvg~i~E>FtWqx9;J1Ouchg z;2|*+5Y}nhaa8$G7Ub??3FXZXIsw zR^P6F%CqhovA6Xa9uHbt`V2i&o)KfDebC(6Z*1??b#M!Z$~S3@a!@j;3Jq!^16n?{ z4;$ij{Fy)1*LUk4_L|#=olOHanw;Ej(_DQpey_uD=aK%Khm&_6n?G-uV5!A`f75RH zinPfN+t)2dbdUDG-OkExXH~a{s)Rd_>~|hJziu*Kf8_Z5q4Dz;^X+cmhqdYttJGH> z+Q_>3y3zV+t>NQ({m0chCSNp|KdI64DY+jc?p|rO@wIpF@-O-+Df+ZV&!->N>N$UZ zw@O3$_irkx7tp;^t^ZB6{#SR^Z&m8wt~UOr%JA>^wH({MU18wmTh)gD0IscU_ zT{*@76e&qxHoI;-7-c2B-!gT(aqMo>L}i=0q1#aRSX0q9$)99Jr=g+W^043fWZcUG zdOGRv*Mxhf0==qW&xF5g)YCcQ?pFr~G@(&rymQPWKjPCtU3AQxny_Xjt$Dp?&fuNb zx@JZUDIU7oSx`ChBgVwAK00EEO_@ zFGrRXpf&V+?|0cA3G6>#e78Szt=s!`hnv~~a)!mNcHMq*%kT9C z=nj3o!(KfQx$($N?T<_syvF@R?OxLMK7C*(1?y^y_v#rHlo^Y}Q+ub9xcFF|8bXdqM=_`js2!(;w{|E z$}wpoFeB)#`xC#ZnEds<@!tRdH1gvWs^8q7LQKl@w<_S!!2caJ+ILzsEVcLB^;M4y z_gXY}nx`t-wbkvqO4#}29H|^l+#8BgVsL99%9VDv`bAm6)$ZW6o*)HBREt#fhik`Ecl#pu2a_DZlWKmw zGeYwAHyz>YPog(EV|RL!*B(c%b_99<>&F2q6s~rLzU~N8&Wyf#6p$i8om$jSo82FC zqgj*dvlb86)6lky+Y&$GeyaxihmB4oTC6;Dar4m!4R%E~zK=d=u+iWP{ia6nL(1a2 zwXXrIF}z!YaS&8+_>11FGQ4%4;v)^_h{yDsd+L9`GtNVlBfv2Kx7%aCx;6UiyAuMK z3YB>D)sz3@{_ww7jJ;c@ey>*82gST7cBV#{rgy5f2oC@4z8dlS~}uwb3nzN#)-QRCt;(u(^T7S;r-STU&mO0`r^(pY(;ob9Uo9d z`==s|eUstNVK0+mZDQP*8P%u2W5Sfh0%#r60*}zD#lPeTuQ4)rL{{v zq&NMk4WZ^cs?FW4^{gH>RV$--VingH2;$D#$APy){GO zn$c+8M5=N)is`u17rfOMq;c!*{!qnmvSuRvP?K*pmg*hP0IRJK%D zEnE~V6&?#MDBrFzNY{l03zNmCQdl!g8BG`{u_v`as9D%O^l6jr(?$#Fh*%pYeDpc* zP>J7Q!3@4f?m@K?VfO&B=FnZ>7_L9LlV}pdivOBWw zPi%W*o4)9VC%l5}zIl_gWbsTpee<5sVmP(ti!STRoARPop=w#dxPL0YCSLvw|Y- zPwY?L>PuXI8pWjW9Hnhx&V(lmDrM1K7I9-51@eG_C~`sEsRt5_Kmsk?tS3i)!?o@R zfC)m{DYNoQFc`t$g9p~nSk#&vtX$y1J4kr8?Os5F4TM*Kc=V!EN41`(|0!nep`Emo zkLxi(X4WP~<~(tP-NWKx05OLAD)|ff=lF&4pXQw}T098bSohS5>U(T0gYNbb9~b~b z_e5Au82hH8gPO#cLWRm&)LKh=`^=;vJE6~@QB9I}Os;v0XVKUW^YRBMo;par-`fG zaqicX;<{&$z6%iTWHKxYM)ICIREe`B{XC5T*%`_^845 zVZ9YG`J~Z-K5BGeFdBbziV)qwxj+EJ7q&t?*nH@LA2h`!7$x#7Is~<~YVea<{kEL-k%hJ-&0Jg<{qu0kM`fT*men*Vl zk@U;FKSZ7NjVGb6ANeSW5=%@^0wk~%*ScA2VpqCi-1N=uiU=^c(D~C=59#SV}5WL2WLM>oPiX$>Lmacvq~hMJ9}9H|Ao+;Fv=u z`<#tWU5j?-g3GfU3~wfqyUEmEBDo!ntVJR#;qY=Oyby^l#$!wI#tL}dYoys69@ ziK)C3jV;AeEAjNIKQ`+O6d}YNp0W4}T6=O#8!@t-@yw5zGIZd1G7)^LP4pSk-MZAH z$w=#1@XVzndDX~L6Y!VA-`QL>=cXJxtvH4A~__JS%D3@tN=+evz#k#kT*hx zfGb#V1xv2bw8LLgn_^>{=!7we-#esB(5rL6kV0Kk5&jptCZj#-M3*YwF&=KmhKz(B z3OxMn6WEiez+*U6Kj4Rr=BaeuaHMV|O8+j#>cP;1@dT4+` zM1sf7Z{YWQ*#=P#EQT~1pSSbdTpu-AaW)8=;T!NYl|OtVPgZVk*|2~FB%qI~HSgRR z`=F9oItQt0!g0iEh>Z|*{iwk}6$WA0Z#sRV9HYhdL7k3`Fgxg9SLo!fgi#U#7-Gj= zp~G3lT%gY3K=){HZ|y76euXqZhgHIg;M@!F9@-Dr|^hn;WbaE$E_``=r=;TuntO^`CDU8Lw3+3lx0 z2m0nIH5muTv0&jeu2MQ1TrHg$BkGNjX_(juYSnQ)Z9pN$<5COUxEhj7-seIX}|Dw@=K5H}( zP^Bt|pL)Mm`$dZlUyA_jCyge43O3lfvKf(r1Tg`LN=`IyDIgv`zrn`hnVShRW9oPkZdZ{6Zqvbk3ru2s8p#pPc0 z`8Pws&2VTd8Q;yO4`8F1+b`vJ^V!W@X1$o-nknrHHs&^^g!L$G z5AIfX2u`@%gk8_|-q7{l08XhCo}}~^*pTukkA1)z@QANI_VKJi0zAa1upy{ub6xFl zfAiP_9_Xt_F7N;h$%e2H5UxF zX}k!tW8UmoL>9*~GFlhx?lrT0$?9COdsdykbw-DG&Ewld{=il!yc><|AlS%ZH&VOw z_kfK;ZmXExm@aJ06gNwyjhVTP>Dl$U`OU?}-Gzmn>FIUeWGv*C(&_n3W`S0a>Fk2X zpS3z-W=GuRD_UGxQsPPD99H{BbfF1TY@8P5x(LDcA$6GL25*G;8}Zd1O}tl=d@>n* zG!|+f4YJnYmf*6&2?4aG(Fl-$3T|rsXt;KmfJvabKU9f>+7r0j?Gs|s6CkvH=P50K zm;~rTe5=cU^Qn*dtseg!?n&WJ@Da8!;cuS$u5|f$xIAJWE2E&I!;Ls}11*UGCIZ0& z;(e$?%=wh}#Rw`LVts)k-T?^#Lz@G5m?P#K-ob{XLJ}g@jt1kW_2PK$^9OoHVM%aE zYIH0&L|H$oF}_>LS)PcnF(H`7Tt;gl0ZF@otw03%r3NM2!aNUbj!Eb|(}w9Yik#Ohkcm|!>T&Si&d#qC-11=g_} z(eP$6x|K<87qfeSQ7Y`r7I)@nb{6M$7iM?JRG*$*MX<5DvPZVq(!vgT$SVswi?f?^ zv+MJ-n=>;Tg~CcaITIxPERb_~GiG~IYYb271Cxf}lsTfZ#HP&AaeWv(M${orWZ2FO zYU7AirdJhX!}WM1&@t?P#5fuR61oMpjYV2V;6w;WP{VMjcEDfNAE@dB5~1qBaLrHz z4}@q5o0{6uxbQ=i5Q>~IuNW0>>iv-@`xk=t-*jCr3Ze!|dFayM(Dvaj5xMRFFC`DR zdqTWA}v~(azcN?)mQe(eB3K z&f4MT>cRT*-qPYWASpSA%jt~R+OYHWN2WdD5}vBfm$!QICQr`j$f(V!F+&VjWYmxt zHKws42-ljmre769(1O?fR26?ZmF!X_JEszlrxG2L@%D)r(UQio@B_w)C{5uWs^X|| zD)wM9io{Enp~*OoO0zn}1V;r`jYiqmh#gHoP2>WEXYUOV_XuKDFfUTKdxiaB&JoY` zr#^zW7@V8E0p^!Pb$MtA0}>ntK?OzwiSe584wby2`;GOaxltOhIhubF~FG8#Z}s* z#*ow-G6rM%Qs%tgT+o|}2qzO^E5HLVw7MCUy2uC{Cd)k7SnZ2e$GqLm?sdr@Sc!zz zQ}NAwdIyWKFnzEzcL)_!D6B8=5fZ9O~KJ>}jb5(R0Yu(x@1uzm7u_l&BRi^CV^ z`xhs>C)Bp^CLe9A?5`|rFU)UBOH!O(qYE4v!pZzfG`+xXHxQrmL}uB`SUm-kJFj;U zjmfEOIki2{0iWJAOALR^kRH~h5Z=g;J~L>@4(juL`dp7T)1^sws#A|u$u>>ASsghG(Mxy#~f}Md4 z1Q?X!0>__Za3`t0t4T;3%Lw{%$e(3`2+opn@Y(JOR6IYrc)ox3Z10$N4mS_> z)^;}*wpM1=7H3wM=EPb?wmQL##~e$V}NX z{~eaT|Jl+C&V7(U;Y$Gys~BpTh0 zCw5Zl-CRy=Or{HaGo`)x>AjV?{q=?Y&82;oiGvMcCHB_$c2;-L?i$r_`v)8Q`)db> zYkMb~hi5w{r`yNRwhxat1QP-4~- zEKpNpa3qPQ5-6Lp;FKmv0~j%<(6BK*!s24h6LKH5muOr(>ZG&Z!nkK))HOHaoE^5$ z4LWAH3gM}})NLzvSxQ3I8Ey=JYM*07yhNRrX*hwI4pW}n*&Z7U^pa}RDl!z?^d+v4 zCeYfb&LQs6s8eN#y%T}27)w@+C+>_yrNDzw2~MmuCf9mI14AUEqat$N#f9}8>Rs+< z@obUsa*2d=DElCVA3`F6q7EXi&QBG6*2blQ;&23_WJH}2L&Wx(XbDXx-hE(rt5yRZ z??2#NSlOPCX~5z_?6lsDBpXa{`}M}8!IYAcY*Gev1N?c!wKE z;iuJsKB1{mi=B3t1Z+QQ1{=o*55a-{>5-$F&JHX`5j-wo*c1$)XFI2K{kk|jXFS_Km13d6uwXh?7dGdo z*JfwdW{WGi?0hCYEBCpCL1M{yyi@#AoKlNBhs$AfBr_mhq3U)TqQ~YrsVA2CN9H+B{96n~ z)TCzxNw?|?+$rB~m}b(X&b8?B7!AN+O_6L=DR{sJU{s8y@3X0SEvUFNM8Zi7U^vdZ zHPZ0h_B0p-4GI|$pc~5AVt#Dc(FNBgy7_v9fZieFxz1)kF-CK zgCIvPTf)?|yD&9CA`K3xhyy-l1Rf~Tn-n+0l(O6N4oAUd7joJPc3T0vfy^u`hJs#K z&}s7;O#wm0_(XPiG(I#E8y$GZ5+eH4t1tMmFCzELWGnxg?nRJQz|Cn=>E9yJvg8d;gQi8CIU_n6P6ey zo)%=q0f{?9etOn%tOFQ)lkcz$NjBtl!_5DIji+KUlF?cm7{ooK7#ZFK7{LYyc>)j2 zi(k%ZyDBB_HE!dAGZsq;(*YY=bzZH` zPfq1W$I^qt(Sf1J@JMt@#R4=98)5%SBD$W6t>+T!rS!&pac5)Ukd_*It4DilV#zpI zKa?H?trd9mr~4;Dd(ZGZ1ueVunLIwZkdcRf=CIo5~fIMT|W$uf*7A#YrxKGH;RIao{m(&W;$f>`nSX!jQ*kAj!s4 zeXh%p>(b{t4Fyj8I}EwUx}0<*1RILrgmr|GrG$=@t@>P>fFTVYO?201u1z(nl9Cq2 z2UCd$Q;gz7ra?KEVL}hmU%(iRh?6_I91n|$INKcvi$&xOHi((P#$6I1l_NhWLh=j5 z*+i&~CoWtRFLTB#U7qqn0}n_NA{QO;QW_0>72&9G)a(0KHl#@rW~bASjHbBRlC;{= zPFvpXxMag)FJU_9Mr*}@SW8yC4t-v$$!SzMl`1zel^GpRVl==5yP;BN&8CveF^Anq zMK^MZ&0>0MF26&opUuUit;M~Awc~@eBfvm-nBak{iB5KpPIeEV;%x6wAi>oJN6%gz zok(#H)bpdG7sn?rj*t21WN-g?cW-xNYioIJb9rNHWs|~cED4p8IH)u1UrOQ#CYqSX z_wWX%!NcaC)_Y1CM}h6hm^sh(1b?I7kd-cn7|r=UQ;}xEWpyia#x7F~rVynUq zMW11l(gF`kT1dlGtU(odpo-T|k#-oan~1QtZJ3DEGanTa+uPv?BjSXY!`!=2F~U|Q z$dN7+3<8gygFJ+Hac7X1Atr2c#mKSmP*8qZ`mS^`yw(>$T=7%Zm8agXyFE0{MNHW8 za1JO(CXyN0_y-acHh@Ih3TZB|7}BkU4WY*YsIWV-2sY5=nqtY@%vsz~*(A_JjFba< zb(-ZvHJO>3%8pN_$0kx^6G@DQRtH5h9@j!NxR!};6;j*N*&WzeDDASQtWIxl%x!Ni z?69EVdG4=>W#wpn|8Q#`HlFPrVi}$vp1eGH_UhT`_s`C_?CHB_&%QrBMND2P0+O@+ zeegKg+TLB;+*{w;UfWn-S^W=CNh5^I82KjO7e6u>V9$$KZpuh7k&u+x__FgCBqSSOl3L#>mKAIWHbFWV z!nEcp$c}$Zp9>Sxsq^DTR!NltGt<4ZS9#QD+hU zC$<7H0StqwXt&LI-HWhMUQ>#x^-^Y?-fpwG)y2Z<^7IZ%292Fb?q(i(M?i_6<{ zb6c1Wj`%Shfyf*gWv<|iMKK*B#9=FpS__g5@Q@o8f*ZngnDdu*Lvca~cM$97)Tf{5 zlO0+D9g!AQqv6O}C5jYM1lIQ#V;6h>M)Ab4_HI`(~FLJjk4umy)p+e9=N`mBw-Nh4sb!`f_P~eRgwWeiQ4#Hde4fylb14 z;`sdV6gFO>6G%{Wc>L=4SXoLA&kqg|MguUQ;$VB{U~>nfv9Y|0?*SOpS&O>trJcEj z?R;q?om-7(mc#KyUliAL))pX(wV-z7L}-*{#grd1=7!9LK~tW^rH3OqL#A6#f>8E} zE<=Ad=3Tl}r!MhC8-JvYwyHwSlYyoQf5Vu!VbrI{Uq9j_TUCt1p4uUI-LSxev4+Wz zr*gn0*|_`Eai`l(uS)^O6YI4OniE>DKCxeWVy7oREb%k zTiu?!Prcv)Ki8hRfd@jQJ;AV$RzxTj2ZNBi48n_Z93{khwF~wHW{hCQ%d6N8njd01 zm=KU}BNbU7!6-MgP=SC!@*pQ=HnhfwS|8FF!fKt6P8Wj^VJ<+$6gQa@&|)^E%)hXa z(`mCvtx6$$RFkP-vy|MZ~(Z;+%yrsm7TXY*=z4B5KYJnX)8|$;84Z>R5+5 z`e-WJp^80L#h$3+NW7zpw5vjGQ^DpbU(=-b!I+C?$cayQZ*tqt{3Lc^;@{x_I8C0HAEXfVC)TZ6$Zj{F^ zMj!#6Ygm{rC#Htx+l)MMVH1?6FRcyF{Ts539y=MYb-LvD#n|bh^Zz#;jd`=7pg0~W)l^cWN$K@jgCWQJHcOGMjmJ3+8|-28$qmWITyaB$IA*uj z=Gf8_=vZHy+aS)lxwyT#v`OG%dv%L$PIwXQM2@$1pY80Q?H`=(?H_GzA8zu|`X&vY z7FW0=dag9TIJ>kwzp}WnGB>kSEY9b1^V$47A@mes($qpE^?EfC+t|F>ouLPj#+Fc7 zlj9~)A3>mlv-@sURAh@ygh*U(9SgLKay@jQWh~e>9#X_4*g6^D+UTY+cjJf?FzQDf z^~0`)kxL$``|MCr%h+qHd}^!cw%&bWy4_*8^~iX;!*uJh8FBI7HLmS=WV+I3_^L(s zWwVxQyDP0GDreEv7W0*6Q&}WkAj3Rx{1(7{6#W zGm4kZW~vlLrCyUkevR&_Ldw^up!}lQNR=Gl;l!2$eZ*nz=M*Mzm^B7g$rchh;jyHCNacLDA`Lu5E&im6`RW(h6Fc60&&djYV^jSS}RF(FsHx z;s>%04`(Y`;^#(ZN^gs6EKv^e#|$FDqhB2*D~x36N27kk_1~?dUU6wS)pMi1<}p8z zw2uX#1vc6zgKZOm=5b#mJPbO@svDq?%7Or+y2o1e)KbxDzW3O8yIps)Rdc;nccV>z zz0HWOwi&Lp>c4K)1IFjg+Ao?kUp~}*O;t6$vVo*Y|5c-w26SIH>aRRBeA%G=qF(cP zow_VCxW1s2p6dI0)hG2TF;PSf{$~$FCB7_;XQV7zim&kz1^B;+Z}Min@`ZXWmDh-Z zS+YAg$5&8cG|CJyinXOg;isa}Nmm&RtcOM$Dzkyn5IbB$Qc()KVKwA!#sZ^Wn?~$k z5J6NK5AnNZ1D;vIMtF&5n_t>m zTHaY%-CbRi+FoASURvd&h2qRiwv>sb6OmLRmZ8B*Jem##VqS09wWLd1|@;#B{gAfTZ2PbbQmIM_;$-5ayz+ zubOz@cn#C>nvJia<)IEXfJCzKS*=P6NT7laDm2p&V)9xa)=)Aps^(=64JIGgOwmYz zFVLLfk|Kzzo4Wk*>dBAj##2oj79mRVNgxCgQ4aiuKA^Qi4F!)=)X5_92Gu&6t^|-) z7t-m&dIRPnVlu?cMiKWw(l2$Gb52XqWtpbwy@PCXeGXLY<^m!Z5^&E!MT}^9Pyr*l zluxeAX4mL5%t;DfD4Ucuv6`%I%&xA@uWZh*t}m=Ia^1Pm0*58byUUk4SX%P| zXwv8()B1WR++5E@ZRVq4PfNd}b->v+=mHGX3>aJ?J?2H25z6R50!t!*8Fn`gdyq65 zH3RnAK}YS74b==Zn)Z}M_1Y}g(bN( zCM~+JnrUCDr6oHfcwj@me4wFSgA`p>L^GB;o+Av5qK|6nr$H};k@u^HFI7p2G|9u` zvj39u^v8kW7bN)E>T$mFzVc17Nzr9D289rTO3mb(qUKskd{m`2TEZqvOvnrj31qb- zY?hSW`b*q{poiO5gaMCz#%rJR*yo(qlFK&D3IY|v`3x>4LgMx=F7smdI-T9XVyu+5 zh?W!CAgsZ0>fZA9-pbbg>h{4Jog#M+*0+u}#qx2qPKw6H@#g07);c=cTtnjJ=H}7X z*8chi1_XW->rp6Xa=An{8B4@Mac*lv7!bcd>U4)8#O4TD?LiC(9qOZ0p z+5u6ti`Q|l+kT(zNv9Rjz(L$fFB}i5`%O%Q`_X>6*09`&6-Tix^m*X^i`UZA7C_QM z&n3~_rG7%{71dAN0&e1IzL7N;y`d7yG-<_jWG! zwxrH>HqQ38&-ZtpAMTy+5e(UckoCo-)%k^`nc2B~sg%tX(%Eb(lS!tNiA+3}3WXBE zVB8l-c>Hnt1tF(5VRa{rj=0Vi$K@E+M~Adg;c`p_Sy{RmCxVa11C)Uys6g#gexb=A zoZx=2%1F_3lOnPwt}2!owkm^e@Q?zPyInScN|*T- zf|f4pjZVw;C+0FU*Dx{)JWLds7$rhiTTS>U(!!MO4BaHS>Ep8pQ&PeksS^tdlB)?g zy{XGDu)Zjg%Mc?Cf&>h7bfL$HvgpWBAS8`R^_1I_a=Vi*chciddp#MiJLh(0kk_5} zd5a!*-s>v(-7^v2e9XTj@5o3;*10JITY)%l&0{Dsn?ymEO55Covb}h?vvjn#a!8!~ zWb>GlwXVNq~0JGU@BJ6$Lh^3&N&A(bk` zQ~7A3fFiL%Ae!@pvNSO^y4b43$IP)2V|>sM@6*J(RgoS>ZLCWZ?NmqD#!|EYSQ~w; zj&x`uPc%_Rwy|<2+d36)nG7)!>u8w@66FyeZ&Yn>|&Y>Up&+!wkq5JqRe&W5oc9=r1W(9;efpf4BjiZSFXh62-(z;rw?n+(n8BFm-d`gCk# zCceoy9b4nVi&AnGr$Ts}vpcJEoV4!lER%_G#FetA8z)>y&DF!t=|{bP3=-cRAOCQC z^7HA*A1==Ru(hO6b94uzoB+fRs^8MuOGD{@UR{%}AhTh(P*f2%RW;#gOmr zppPp=Z})r9tv)v@&u{j+ZuB^>KXst;gn$MjSW(tDoerXBS09VaEU+%Ma#VxQY$LG=G&WVg!~*vx*`%$}F}1(|iMr-p?&H4BVo$sSXY za5l^}SwTGijF3Nv!hu3GREh+PvG8;@I#*1r%q7&qv$Bt&;6{Vft<&c_XRmh8zuiCk?(ppUBQC4H`04BnL-D(dvp>B!|J%1O{^t)b z|M!ot{_o#?_y7FihyUyMKm70CegEG-fA?R%{q`^4zWBq%>CdOfzkPP}{qfdNx!?EFHZIGf4Oq_VSbvf&7(t-g%Tou05I zhpnkWOSZ?H?lEP$O&K|M88RX~uFG`jGTcS}Na3Mf8%NBMoVV)YTqW6}jWuhcO-LPi zsERhJ$T1d)#}6h&60$sH6NheNp_;K!?P!o&s->z%0{4gg;!t(SFOJ;@eZOcxoU{@Z zC-`}@-*cnSEp@%uCEnpkrPo`QjD#~HQCrtZBO0MEIvj|=xYU=A>{4GpBKBn`eO=VQ zypDa9BV80RA@;Czf@1vSp+Sn5Ou!=?O8J_lFlh9HTSI#&1v0SVXW4 ze|dTF-`~IZU$F7>_Xsfl=WoCL&!1lX?S~hCczKS+0E{1w_Fv+J>~5d$Y@P0IouHi^ zj0VdJ0T52yI8xc&*xXs)q;D;e^VzwjLSZhQo5pTLQ_~oYU@R}z6o1C-%V<5BaeHdW zmL9O?`Yg(EiAf}ga+)S8@i~_lX&V`FNxdO0vqniAl_GsqB#|mF$tXq-weco(tWgsa z$)Xx1?VL2@$#}zLoYVPwRf0*~lz7QlI~hYY6VdAN2&J_g#Y)|$@b*$srL0n%$^MhX z8T}h?iW6H(wqGBtkZvk!a$g^&aHb}+);U9w$;l#4{@BS}zLeDsB9*<(L1^^TW~&qt zQ6_}HK0(c!^$7)S~Eg#nRlB%(9v#C$2e#Ch3Leto5|wK=`J zJ-aWESUB2SI@w!3W(DC09x$ZE;C{~+yXRbc@!i4s_ebZKY@D8BH(=wpXU{MTe|~xK z_wS!$I?7-`1+87f`Xa!OrDyV|8zRWq*AgkCZSeE(hjfYjtg7 zjSDr_SWpO)&de<3igOqZ2?oxFH=J{lW9-WqyjisyHZsHZY`-<%W63?W7NokY1(_P! zX)coSrQ{5Y17) zoNaA9+Z15zuMrbl*p) zQF1$;B6U!{Lt}2bVYql~C#!si0 zVElCU49fr>tSnd$AOVTLeEafG-#%x<^3(arcla2G`xm?0!eXqi?yWBEt`HVm+E_+- zo@)XLar`QdR1jcbF#sc@fPo7N82A_tU)tiP9wDu9q$cgD5nCEh1EYbtz(imxo>&w^ zfvqqX+JuU&rb3f3-)PJ;J~ZSS^;t$K=4CyA4Q(0$0BPi?UY)H`WxxO)P3P`kB zBwosIsxoClWJ0N6L%~C0BS%=Ono3GlP9_j(W0w<5je?e7iFRir@jD|i@Q_xeoL&ed zl*6F%X}&^;DDfs4Ok@cv>0#wj=81`sL?H4#9=lBzzttMF+UOn}vpZrgSHkU1`@C5{ zTa{oj9+~EHJ+Y?1#_W~|WG(IOt%&SCv5ssWpKP6STQs+8y*zmN-O+Pp5xMyB=;Ej2 z=Rco5|J~V(-=B8XB14A64<@-<_ZIB8O~npBNC z335^}Chd;|tYRX0e>`z-3_L`2!(EICX{AasDmFwqCvwGs5NSQiHUu+L)|-9{bG#Qa zh4coW*%Go?A~stL+3j(cE93FxP|#oEYK&BTzK~v;%dc@PvN^vk!dYtvf{Hhi!(Sf0 z`2OhCPtRTm9Y6nxb>!K_&u16Ezj*Qci|5MI7XbWtaf<2q;n^|!Q^d}NK*tX!BEJiX zgpK`uu}fWF=SnBMi>;MaLSAc&%gYN(3!K5uF2h4D~aSn5l$jxFdBp5ca zV@(-63B4Y0 z6>w5klX+UI3=eEbK?q>f>+=neV<-p=;0GD94Mu?nY}D$~0;+$+15VH-T7oXcyeRgE zdA%+pRi{n!QVJ&J_a$RhEK*bHN*1Zf6p;L)vAD=Dl~pj(Iq3_&xyndmf zQ*wczMe%QC+L%V~LpnpqV2U84Icl*c?T(CtxTrfH^iRh^vzgeuFdfsJty5#Nw?{b% zc4O=Cc;{FoitnGkP?i#m#*fEmKcAfc?%Db8PcQy(E(92VeDU&k&(9U(a0(dTpB%Av ze0y~Cost^*^6=#R;7~-j_Vx*IiL|b@^$ku^=9gCH7nkQ2IGUfCo|kJ!uDFQO#f5Zk z4k}{lnE-K&Xx_zxyYOqM=m;I-BHYov?M%tq?i{b*|HS7k*U+C zVWa$f`P;_`2oFSsO%M}4Qp^#nk}wnq9^@}6*L2=e*=3pi1 zv}e7ZLfBu5M`jAC)3z&LkCozIgs0&tITF zzj*n_=OVHJ8xVrskZim7j>sY=mso&7&W6GUhxOuUetuErY;fC7Haku1B3lrC zMXE5L%+JNMGvRb8m?(OpIeRdT#Q+SAE2ehDChU=ME1hqnBc|xEAvUN_icB7Mtj2sN zg(ntKP|%Jnr8etyiy{HW8*E50U;`d5ktk0TZ$$bbkWkiZHgXRPJi9m9$kZDo8{%;b zuj94K%LEfXDl?#1iC^B~{WsnbY)Hl~0ekJ=mVFZ3SCEiSEEBSq0RxGo(*ZxJst7zF z;TAcEB$WY1kCX9QkH}PHB;ZEwA_2FFDfgu65)VlTr?Dd4%bK#=Qf`+BkP-pQB^GB2 zE0_+h1t)iFXJt>Yv2#fI0Lj4L9-V*x>|B6xb`BMPdGYe^FJAra)l2l(?_T}+<#Q!4 zPHdbYm|z2=A&yZFjtHce*&vO4pQ!l8CMjMd^DNIUElw}Y6z0g;NT;S#nHjbrY*CTe zj1UqJvl&U-{7JJ1?;@^s#3rrbadUXs7#z|E2lRmfZJ=KhB1leWFxrAqheCaUEG5AC zy!141HY}Isf{B#mL0E}066RuyxrkdL?Z&0Qs`#!rD)8_RNEk8=|EPL>x=xo89;~v# zVUHsxY;VO5SMGdunFso`RHH%6*%19A#R29w;0*J#LTa%UVh2<+nUq^&HpP|Wk&3bK z{m~F&BIh#Bc5A>(Y)y(_nux9Sl1@fmqT}XMJLC1&(GXTu^q(z*P~(#$$HbpnRS=u^Pp$+9SXcXGyN1Ta`cuoZuO z`QpF6ef8hpeT)A7?JM*juU>!$rh_$wod{q&=lZVQ{c~zkcEnObP)lS8udK?|WO-(O zp*S~_W0%A}I-iW?N#o&yX@4Xe3}=1ej60CD`{FiF+~kfL98s+;JZTP&8vVn1|A5Zd zukrP2ynSk4pDNHxlWk3`OPhSGP0QMo%X$;@Ye)1o9{%K~Cxz#EcK*k+)4yDt|Lw)||9bWEzrK6{ zWn=Qw>B+YThc9;bp6~3QZEv4$ZXa)KAx`QKHa7Rx*2vkQi4U2*g!*?0FBmZo-fYV z)CtZ_FddYcNH*l|l_xHZ!<%bI*>05CD1WCs;Une}3~Bb|q5vdvayjbL5{z1&`)j)a z7$Ov=hM?M@JY!tK6ysWF){k)v1LkaRcr0ssl**ydZWi+q?#$f zwXn*5HWuK1oKQ9$Efmvp3x%cC8ByR&DJwOt$D8{cus+{8c(r%*!|}79pPl~x*~uSH zpZys;o}c~w#l?TVe9rjS7w3PvIQ_jiA`#mY$;QR@&e`S`cs$$OdAr!o1bjJ^qjZ&dFc(+5Tj zff2n}R%rT!2DRZHb*NJnQ@06!e2;XkX6V|{Elr4aK;t~M)rksm)=N~Cj z_PqET!n;r$iAx9aAHcx=|9`VlMIfDsI?IYWj$Y#tg^F5rv_=)FS4V}YjrvEu8Hblt zh_cz?K;^I>L4}lLgE@HI9rXSa9;_qs2>4AlK;qhC6NDh_hFWXoVl1uBf%FEK!Qe3( zy+k~SiTS)S@*?<~&BP1S>Dh(C{Oat=_QD3*UD`Tc-#y(rxMbtt_~+x3-<=%8z@N{b z{q^GPKc8bgPSIaqoR--DkMAg6+dp{0YO=MBh><&@G6-XFQZo*?I_X zL5Zc8|M27kp{n5^svJ_-81Yt) zcq@iIjHqhVCnvmff5?4r&~E*5Yb@Wece7}G6!-232*bT9!0LJrk@Q~I6(*ZD86~6Ez zyI1^;y?smvCnjgx>);^;9tWJ8tclFPt%Zfv(#%}8P)KG(rf4t`_QeC9xCr4oLj331 zl@u=$y~y&?TLXG)NNWvgtYJhSunA*$+z=Ym2N5evuPQ*!2Ca;#J>e)#1k8=1fd*n_ zX}1&!e~Ad#Ye@{GWq6Z^H|Ns-ERS+2k%avJu)*=ln|c$H+Q}%ActAz%RQR9Rpt4ee z@lR}2(`6Tpa_>W+0vIq9!yW;H!ge!)WA^rJ2m!e136ddX+V0XK|C#Me?{V?+)8Cznt;(Oy&;ItDHRZ*Bzj*Oq&!7M8?Ch_nr++>@`Qz#F&nJi9AMU-{+eR<; zw=Z_rFLpQ2cQ;SBxz}9e1cC=E%i7%BVzJ2Ok<-~+Hjzq%MfzXR7w7Z`xxG=3FXr~e zT;8a|8?$+1CJ1qaa7y*IDEY%GQy8hu5eOO91_!j^E^YXUE=H+Zrzs;2TTSW5=G+rY zzQZc?$XY_+!LAlDk)G$9c(C;FrhNZ0#9_=nG-e+t!tG@Fz^Opej1bU}s?ny92w5mT z+H-5f+rdT`~F@Syt|i z23S*W4|!QuZVd{@HJn%YjMCCq(jfwP2%NB#l?QVy~?6F$Bj25#OHtg0QY)tkvwe7X6F}+%j5&oLqn$dozi0mHWYW1tth({@L(IuR^?C6U$BS$ub1Bn zkM#NT|Gc>P`}z4_&QJezcJjN^gWsO)eSfrrzCGG`d9d|je-nWRsetluZEs~|eSUs< zdYU#0;8DzEbKEkTNQn)LBJ#Up$y_*|2}V=CNZK7tfQQu`Gkao2XAC^3J|GoP$p(zD zz6={9y~fy6Q=;3P?zZGQt+_5+zSEZPvKOA%i$b<(B%@*f#D-iu7~!FehaiNNNU$L` zBV}*1Mw3A0;1z5@MYSf0h`gC2EM4= zp@{9th+snsJmdsIzypED^*$$i*gL&$i3cN+kU)hL7jZ&`+2pa9d^Sr!vf*)xW7$|J z7Z2xB;X*DkJ)2!vV4qT2qi%6`X$QM;Oec-aeOwOkAcQ4$vPUOBJ|lvl8(R_X@FdOd1m`Ixr$`pnT4P-L zHfoLyS(5$MbiXavW6wWz6j8UM2pe5=aI%%z0FP-52&+tsrNGl~GUbq*Ga?S=a8Wp} z<*XJq%7KV-;NsFaD1lAsqe4YB8xtjzA$BDS7}B4VF#H05vZhEIA`M7+lwg2_luQ|t zBNjsnkF?Cj{jp$Ku)&=1&alWSDhE1#;QLS7;QM(LcAcqVNKBWwVM5H6@$*bSBy zwTp+CVm6=AMsRf*Jhl}) z$jn%tn?*}=v-2}^3$yb}^xv3YoS!4Dc(GWT%N1uy=^@uEmMn_24dry+>Cey|4np)I zAQm07#z^`auw@49`F=;C*DlyVl8sJl;jy(O1r~S&h9y^Z`7t3Wo(Kl zghWC{r2v4J%rPJmjH;2ZX?e%qx>sw<2avL{z~;LSnJ{EtY`U?6(*LR#VVs4k3p%>UJao zu5{R!jr$AWQHafzl5?}^g~j~x`tO-id?|xnZxSNsAR!~A zq7jgie@F@<<@uuQS}DHfe2tToZ+a=Vbzkif1=>>VO8$k7u+tWU4ZkxL@?_(_QYti^ zi_C(@bOO_{yjENXkF7bJ((Qw#U5UrZ`aa(2>GqydV!$r-kg(^AJupdtQle)L>=ew}hUbTu4D6MtQqrG=k?fsS&_+hV_fk6WK28Dl27_pc8yJV;2rL0_R z@v^;su(^uzEUBp#eX)e0Z)JNMW21~>QPl+QtXq)}^`e~JLx@VhIDmtYD0N@a%n--2 zY;wO<3i3e;bF9nQ04dnl`KgaSGDg=hS1dakEWCDZg zFPTdzLkkcDoxsCwWxL|8q}b5g*9&Dlhk=yR{Rjhm=)a)J`PV{!1RMTq%xx=!s1foT z7v{#s7hLENumKpqxDl{n2d^Bi!3Gz9TsJm=1jCJZHU0ZoyY_DypSJKNuS(b&XJch_0G9Ph3j?W{7I8v&J0$I8>@9_RSS z`@58#AMQ5}8hdsGvqMqXMr~=8<9qO+WR&P4-J*qLe4 zIzzz6sX1A#AjP7n7Iy-N!bjY{O+QfQ?6&=2)!wNY*jsEQV6zVQNGruv#=qAPnHXNB@kCCk;4~E#77|TaT z@-t(__{4lF>e!fDnvd72DcD$FEw14`Eb&;}w%}4TV{N-r-(cKZ*-{r9Eo?Nefy$xV z9zWjRX20v%&eqFa!$T%EUN*O721#=pJPeZk&7h&Fx%<4`cy-wP_V^H^3h3;x_5849 znk~(JL^-G(r5FtFL0t!(2m}|5!xvX)p6#U#VIqHLEN5(tsY(RxykBEw2-;RbXkc2`Q3MB9qm}$JYS`I1yhz-C9vmpmE6p0NFv&}e* z$B@&A45jF6n;0uh4d-V@ONq&HdU_#0w^WGN%c=T8cD0sUT}5l9ylIKY!WMX7WFRD{ zY?-nFvbnTD11#fKod)^M#>Ork@y)f(!;LMrya+BY2{C&+ul9Do*>8N?GGk%;*Mq%R ztsS%W_8HdN0g@N(owI}8uaEb?J#Bq=+Wzk85k~bOguFaLpreKN;BcSnVj{~DnR0b0 zU#ezY!8tWQR1`<1^L><>PZnU~i;;khPb0ajLmAlksL%E~*a~CQ<4?V5jCKPW4c>p8 z_+w8JqvPPchjTW{QQV)S^}xChpyJ`&l?StC_fh(ql`%ixx^%0~x9?2r?fbV32COM` z0>Z@4J7*#~83{(E3gMA>;eUMd%NQmv0TRC?!~6_33<)MbzcHy3c{`MMV1&ziOmouA zl;tq1_Hor6R@&hzJzygeiG#=RP+V+`45wjZoZ6n@d~9r9Y~*HZurZ%ps%BOevnzGy zI@U_-;DPrDMowEmqGtL$7?7CNX=vTvSv59jeLdOU<)H1XL3XkGbz|?ZttPu+q^T@k z{Mz=f$Bpk!_P;%D(&h#dbh>@_?BH+D4=F^)emr~ny;U6_e{+hEi<5iWM+AEZ*%pdP zi7enzpen4i#A$vsUK*Jx^hfiLC-ECuQjVLEEKcLvP{!C8ObZXdu#ST#DcE474@F3v zzx@sXSMJRk6?hC_xF37x-VDYBFp&R}{rf%B0TT}f#+_*d!5GO3WbV9!xl!T4@INwP z|H|8i%)x`9&%?grSGUjyGd5%@)nJquR4{g`zg&r+u|cg@m<=T!u)$<-c!ri(>P0CF z#D<2Fkw|(Zl7)?_ks@r&O_phG!*3K5%dk;NFE3LQre|y%(pu)g-c8vY_ z@&xl2GClo38_n}lFvYkPZRYi*sq_I1lT$~CHhlDUOwsysGZ8k{NiOcm~q zlZ&3S@yTEs`=~#I{pE>uEm?!olT^TlbtmBvta&Y%+~eXuv)8hL_b^oM#*l`C4Iy!1 z^vg_JIB+x;oSd@OAlwAC7B~bC17DNzi9ACmi!et46*vlb=pgYrDqJy-7YZ|P;Dl-g zgD)1fA3JLn&jvok{KiNEJRBG}5c;MwbWFoWbhHE*@u^BGwt&+prRsoD%`5}PQUHb_ zA+u6a!~kok0&bhA0_t9i+j1b=%a(z(*0;zy0E4z@zc~4CMrqk!RF5K4*l{CYI~>` zrALYWHK_RE)Eb)p>-o{&UmXAN;_yenczMjo95x6gW{!=&K0E&Q1;y&eubv*B9UnL_ z4xhCT5Tb0dSlK|?Wh?L-^L468W9jllq7;dh`ld?{CktPW1%88M!(z%n>Z88IN4=>J zpCsvfrMJ;jLB1h8tizF{g787SxHE$Z4}J0M`MH%mtbhW!si$+yRc}Y zw=6cmupGl>8a}Lu5CLGL^B!Oz z68z^-VV`_DVNl(Oj*P`e$5MtzB#F`jG7ID5`N_%R)Km#DC?rnLE>cSj80EZyQ4&BGnGKKAG@Ffb0A-_Qzu+@@EBnjhIe&Q36p z5EXzS`~Jm|*uYo3JUxI4#urCzLJ5f|MaVb}z_5UVD%kS+C8tpunl3zzST5>JenTV(kDst{XU6crpWJg`+?^2{ItybC z9$K3y%{Yg_1&i|^1I2O^r&WWJ2=SbF7+yQ^gz!Q^B}~f&HsnBTba!(od@zRDun*bX za5beAP{D@b;Z!(AN7MADz(zDWAD^kF=4$EqQZ}_TpIwCwIuWQSHbF=y`lqsUx}-6h zR)E2Fz?^Z~q6u53w9<3nLgg^+C-lWbg~=&AZCex58Lf`86S)h4o*uq9IedE9I%&6#TUMHmoOOe?>9y@u6o6_R?5`Hf%LJ6!Ol1wC&cO(t4 zGD3z@3nGP<6^xx`SnG;~0U@E0GT=9<0S?)}pl0ms4Yny<-MFg9RX{FasaA4%p_4%Cn4N6AE zhH2N=cU{eSV{fgAc{YGScDi%$ym9=Zc^oKFA0V?}!Wysv7a9YA6d3NFD=@)@j6?wByO>z$8N zX=A(D&N%=EI~cG55A10$D!tSQ8(MWj#c#fv#c&a7oeops-Gzt22;o`{D;-ZV*XQ1! zh!F2g_?)?1hsPs4u|MkUeJP_bJlHCC`H5$Pu)^nTmX3~74qqvSm z^h(q5is3P6nb!y#|9JKMAFrOGzwsj}$MYle6)%p+LP1DWygX{19X1Iih%K<8(cas& za&+V+*Ac9?KKjn4XdOLC-N!`J%5bdEKb?Ctk-I;hBcOa1$$l2evu!TF@kw9uYOm!R zW^SFrom>c0!-fnzl!XS#=lukCa;aZlqdK5DQMJ-OH@`F0YdD+Mcl9rb8loLdX@*)Lxf!Rm*#-&IW7#)5cJjgH^&F$FL_e)1E) z5nR^h*a+tv#)erEN5P(_%u0FPfxFICHR|-lH?FE@L?fN8;K3KfhTWHO$2z0wKGQ4q zY=FmG+@oq-_qXzgm@vmhmSSDaKSt+mTfvV0OM!u zkc*AZDn@OOurV3p~a%#GTq`((dCinmgN# zZF3sytF%jVbYCx*m)I(|4UK%2gEp2YYJoWX)1h_g<1+q zH0ep8O-(fU;9(p#v>(nWPP7-=`7osu6JO!^6E^Oq=o0||NKnI?M&Ix3yPn|zD%9-E z`{lI;R9NFY4bhO0{wd6W-ZgPurm=bzq~aK9>G?* zTeE0Mi^q^nPN$}(GZ*VFZF`_+06SG6gehy^T42#HyTdF9XAT^bJbJE1vA;(@E>~n@9JK;pM55SNGMO^pNoXCp@->`NW56F?n2pZvCr?XzP zfA3%rW`oZ!3_lSYj5rYa5alP}K?WPp((xpq5@thw12)1<)6=tAEE+RBqA0Y? zlnL1lc&ht8k^L&}L$SE#_G^o7UR*;q%F1>jZTxLF+EKJO0M`G#7bb26~?wLq&K!1NUO)h$4DEa9?8a9+;C<|2zs!Zd3M0g&h zIaihWBls{CuwivOPGO@{x)UG)32JT?5*J42QmmudUcH<{XY`+V1_C*b&==Gb-RX=r z$pypA-QvU;{OID8{}4QszS`2p9mpzKHK*a!U4F@x$Lx)}Oke}C1$ydXgX^?Jg@JK!ER)lqSzc_g7b-$j=!KRSc$~Ex zFDUxrq}3VoXU@=&L`m|<8O`;049YgP*VicT!34%arH+&n?U0Et9OF3E-UDA>MPdXZY{3f zQHTxwC{+9(IaG50N^7$-@gNvHD*6!synaIXk3x6^!7EIN&7CNR|L_7EJ{5tDV70=@ z>`g9Yu@hKraj-!O7>vp{X7C#^LP>_MF$^|hvBKP3DUm4SHxy7{!`q2U zg$0z&_L2FGLvCAx4XQ@niuLF`nj9diU@--qK-W9pgb*1{12!P!`91}KW~Wq*?(cvE zhQ`;y?v`Y}ER<|+P^Cfj7e!xdOLd9^E9J#Bw)-W3jrIm$;fOv%m%eR zw}vt6P; zgfu!x^1pv%_Pd9<-#*B`bw4Bf&Al`e?=+Z5kwcM%q?C!zTX^;1xkv~`v4OWCO}%SN zp75$CSQmdjCp{?ez;D2YT!+~3r!8_FP!XLW1x-guHh#)R-esW#l!_Br;4TBUHMGs8 zXoAN842+BU=zk=jsNftt$UlQj!zCMlAvS1E!2$>3R3goFI0F*Epp54TBz87iD19MQ z>}tL67`q#svjWD_D(lr+eW_fl6sw5dXA!+m&zs_XJRgncC_5jErAK3l;prr7JRVOz zh$Qcgq@@LSV<2~p!?g|@+^OVr-t3w!kgyy2dd`imWN&IYk;Dq}8i4>yM<@d}Xm1a9 zxO*zjd)^=AKq73yLtwxLZUHLfDDVIlR_+H$DHGg|i%J$pJR27$PAW?Ij8-}tMF?!z z)>&AQ;}RReerad5f|l?9iH&Sx!Td&UsZw0A4ti2h6IigdiMx5toCZ|rwqLH{)BY#j z@m#fbnGKuL*6Fsjg*lNH?(nmlGEAoh)!D^* zy}Gzitd{AdE>tt=viXf<5jLnc2M^d7nNAKzQ)1)cNQ#(pcO+|m1Cf?N6Og>xmqitj z%eIgQ#A86k74BzzT#&u{xZo{#<6ds%N%8HT0w%xV8Q^PSSq%TVpS=Aj_xne=w;pBR zdYHp5dk^`IfDM;Uc%R@IP!8jNyfE=G1%AR*_)RloLwCSQt);^T-ox*d`u$Q|2VhK^ z&U11qn!eySGV!Xpjx7H}xx8RQY*k1m%Bu?rnUZ3tqY1wWoL`WRlddH|`8Uo_G7^{~cML-qOE4 zDPpG26S8n*@ksa&#l~+R8yK%;Lw-Z9V-B&}B9hS!{FFnS~YM(aA*> zQ^bbwINvY5HWg-ruo8`CQ7VqbN-R|}iE=)TzG$tQU$!$864CmerJ$GCu&Z6&3Wd!s zlOT3f5K}xGmWu{v?m~tnHB@Ll0vHM<@*DI&f`q8B@^WN+Q2nYcqrHGA2LWZVv>?Bc z%avgxkt(6UK#i!CiN>-c(bV8%5^<-V@$`d{%vZx{lY>J;lKvDlB;7rI>WbyESCa?q zoqrEJxD?o#2|D$bW$*Tu-$B>w$^3ux1tvTgJu^&vpkWf82k<;D{@bGhej{X-btv&5 zxL`^(2_NV7Ao;ro*1UjuFfOyp;93JZ5H!v$OO6FKn1xxl2TG8rmTj8$Q_p59Okl*)YLjw-`}0QO7h?1bx$M zYcxLsh73G5mR3;mF*d68g?XCZEZ=|)VhZg`P{GcIX|}}jBU9-?1Y0I-bAu{kiHqJE zE`By#x-ncb8OgySf}-l9H@Ovu#2@=j(JK)6>Z@Go7V{ecM*egp|Q6Gq{oPlN}f z{fN(T3SDm_68KX#6jpo&qV>z~$txaMrh)zbVG2{<)Bnf@UkJ0IJl1pK9f;VF_kfMS z-05w2%hWizInC`7W8-m*8)_ydlc-yON5DqBnoBO0(u!Uh){ z$Y6tjqP@`blQqYNk14?lrEOA9TC{3sBbYd( zhG|F+R6iJ~zCW<=hyH3u2C({Ge_$R7KMAv8a)SNkFdl#*^K2LxjtvuSy97ok#26m@ zh;Q-se`iBpB8-RTK}d4(NO*`1ATd02nCnjE#D?$y2@i(wFg6G%oWo9_ENa@bVgtDz z?nFq&=5z7t1vW@IT5BzCI>2v$2M6&u4f%~T3o9t|9NOlFGXe@B1|)1}!|iWqH-izs zp?pIt6or*w^(wIi6RFF34ab2r-Ta>2G*2!cOBH59A`f z2@l@;<4l-`e|?zTfeAD7>~epd}Ukc7*w#G z?%6OTZcY5+v+-Zup0vr$iP4F<(J{&bXAwLB59c&UM@^U5vk}CU#VsoeU2Y&s++Mef zFu+3>VQ?3QxsJx6^cL(;zH^e&2_;BJ+V+?H2BX#~;GtYp+vApzvJtu)tX`ea(+1LT z#s*hN*Vno9)9N(XCofjArAnq)#%TZsTjk?)qr`H9c#NqWQq_+~vt*$J6w5+~vY!nW zKN~6Eh%8(iu3}edoFA(G8AXM`16+WPx`wb5U z(xW!d(^jt?5_rI|F!E(`T7Flno?zPqU^?CR{zV5=ye_gR(AeIZe2)8F(Z#RBh7T^D z4P_mk4NlxBIu#o~zd0sCetu&dkrSxEkgbM|i3#pf$$2(d#*%MT3-#JOw{WiO22UN$ zdqVIY)NFuyStv^8sNCNko+k^% zXW`^R7U^g%3mJo=KuWZ*gstx!DE0#D4=9vLuPvB zXjUf?7hR|nYPB+2aO>Reiud5SO~U5H7kmgMJyyIy?y++~Pkjduw*%H$x*{Fv%oejj zrs{5-SFQNzK^rzG&rmOtv9Yzwz4L&vwX$g%<~2KYwZk>*dtJb3Bn$I64YE)zPbk4)0{a|bJjFIlHJJ!(JliG9ct=IDe==P@pw zr;h+Oj@zw6N_XgT-D}vr^Ui4i22NwGzCoH%Lu8`sE^o^d z#LT%ec(TwpS?rxEJsL0E87+7=Zbs%|}>vH%s}5wJ0|fIu;Z4+&ey zS2$^FQ$9C+u=j`NJsbXYhhDndNbh8);K3hxHiAv~#~js}6a#kQ{qk~ucQ5f;r=f4Y z_P6*WPZYoY+q-e>tvhoVg^22aQ}cpfm3SVQ_{)7zp#9k=5nG{*Cndh;AW2VB7U=NM zEh?~4$Sjs~HQ2Cgf6a9m8{1aGan6Pv)8jN;;=xg@PGiv>{pJ{1+LLcij06Y)j588c zhXTtx#|pk!kZA zeN%-elQb(8ACBcI+aTXSc>}*e`}~cO%JtDIc)$i=m{3nArm$Ku*AZd^Bt%GvjUbLF znq28GV7zXx9H^t|LgB1c)y+yKJ?~6@+5e#BAhOO zahVOjFaZgL5=I1RWvFoc)74@8h8JdZ!3B}VG+76Pkae&@s#{b_xmwv}9rcQ_L7n*) zS8>&?Sd?=&N#Ezdb^UI}TP_03U7xi6;nNKE))RVJ%g$<*07>bde)|Cg${wi6-%~4nJQ?@i!&5kq(ssju~`){7wfQLK5QaREMQUT zfd|{)aHjiH!g5|(i70jiUIJ}uM+G`gGGxAl2NSWu$br7+!Mpv-FH|o&{JQ-oykfmv z|E|Lm|1~E5n|wb!R}f*8QnA|Q!U088creH=s%v-*z$lfM3&lEMq_b8nJe#h{ zUAUdDoPjZ6m+7!{<=T|{k@Owz{p1)W#K!fZJVJ0E4HZz^FmWCeo;^2-HJMP)fGLh5 z$CmspZq-D~V=5r}K*$5aNF+gesDH?H|F+ZL8uqlIsv2&-UTugflo#1;Y4;du_z7 zWv!iNdvCwFx4%ncnxldm4QzE~gXJn)8Me(;v96Q(%1XY7)2Ju2i}7?dma0r8=cyLv zUW}osEK~>#?o4?YNu%I&H3umha=;K0jH*2M@7GUwcj4EnH_M0mg8o#2 zAPmxlU*Sh$giL>fXG1@V4N>twvH=ogp574q5*x_3YJY>aM;SeCV`E$>oE@9YO+*WF z9fXxaj#~*<7R%Q5$dSG3139v%amoC~&JnkNa?c~K13PJ)a<2-vtLTCi#>2(|^7!1k zBD48Uv$?(B*tV)J>OftspY<(5g?WsH6-xfdF$!Fbk+-|pQkjLhWT zWTt4h^^M!LDLo@;q`mGBCGQL-z8s8yF_id%J7I^CR<6; zU>`X9LvO~LcMh6d=|zGbA$sKKO>7(!8&DyWyP%rX%gKt3%OvnZFT7~J!9e`R1vc;)GA?kB zL}oEs>FJopAcW3G@CewLnV;jlK2^ZMDInHo;yh@1A>Sk|uRlCVzSonGz4JJZz1x$(VB-QF{OFwq6H}x|g}9?OjJvRI zCfDGm32*rV8}jr1ZH8a2pYt7zu1Q{Q*kgE3+{E@PUSqCCRKKNvOFD8LHtcc)@{QN} z4WDfI31NlX1i-@#Sts!5+}eigFgC1dx=2{DJyN&PVI_h&TA7yB#}uq*>(r4pv`0#T zu?#j^TZEf^zz`d|YXJ|!!@yYC0t~UCi~9ry)#Lfxf)#WnN^|idU?43!HG{lcf%A9N z|F}%&3D>5KB(TeDeBM8MdtmOf-uR8)_@{lzYnWq$`eDxoam3`jLTreNFdLqb3t)&1 ztv=MHA~v8xrWQ!>==_his3BUypJ*O_%OK&|phr>x0v>*9=8pW|<9|J<*0{qzYRZKC zRboRiMTGct6bFKlj{00w8L1!1I{y2=|5w+#PoVn*x=*0{1iDY4`vkgAp!)>6PoVn* zx=*0{1iDY4`vkgAp!)>6PoVn*x=*0{1iDY4`vkgAp!)>6PoVn*x=*0{1iDY4`vkgA zp!)>6PoVn*x=*0{1iDY4`vkgAp!)>6PoVn*x=*0{1iDY4`vkgAp!)>6PoVn*x=*0{ h1iDY4`vkgAp!)>6PoVn*x=*0{1iDY)|C=Z9zX9MZ0eb)d literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/tests/data/patches/scale_0.npy b/cv/distiller/CWD/mmcv/tests/data/patches/scale_0.npy new file mode 100644 index 0000000000000000000000000000000000000000..334f417d929e174fb6dcb0344a6e4d85dff89c2a GIT binary patch literal 43280 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

  • hG^B=qFJR*k}qb+8EbH6wP|VX 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�+A zdLze2Klx0C>!})h712jua3+MoH$Hy08*?&?g(8V+nGt0gmH!vTU!U zCPB2YDwzM3zW2frPl;D#IVWEwE{Q2DzmwwZVL`*2Tcwf}*s}?U;g{NG_5NP=7TB-a zLR>RDD}IX?8_u+}wyG~NPUPl}vzv&4FjQZ4S@YIdPzqQ;@^eGORhTE$1Aelyf%X7% z8o!0UmsqNTloE#N_eEp85E~a;3IDj83kvqs%H=1vKByEGMklEEEVR2w7nRox_!3)9 zU-X{@-hJ9vn@*3$Q7{d!G6⁣K9PJW|j?))x*37fZs3cF){N7m7bly9|nxlMIX$@ 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 z z54otsUyq4U;#_=@R^k6DNIu1vA-ie0`;5`K_GkU)D#+2d9_jM3WZl)(G}7Ht;N{P> zd3bKaIIiIGMPBeNAprnBa=hD8eSr~(dAQ%IlY zN%AXTpn=SUdtw&{^WY{Xkf}HK{X>+Pba6%%qe<|O{sNHuHfk~1$We^-57w^f(}2+- ztSkAzRX;@Ov#wO!KXWp8-Z2)0Fk}#NF@yJ;{Eg3m9V}N$`3llPb(CT$*;#<71`c;D zSGR7lq9--HH3OOW% zFo#Mtr#Ur*iptP|*qllSnX@_jJ$0 zE%h|$!}%nA4G56@lT(pOuRb?$r~d=nn#5^R0pnnPzJnwI{?_;l?eynfnESNYW#Li$ zE`5J14J@v};fuWlJ_RtkE;n*%afjEx#b{}e05(~&iKInp!S3efUHrlY7_v&e0DNYZ z2@f+P(ENG8@sQZdzOla5PZhe)Rqu8>VF!ei-FMbu3XI`|$-#fu%9PSH1_~;xQir9f z&}D`V;JDL6WHFB=HY0KP5jH}*0RG7F35sFT48j7Mx%L!y0$9@qtB_Xs9rZUoh{V@| zK(J};L$oPRD5zxEfNn~T&po6y48qmYYzX$#IUi}5U1@ELG52_&Of0mn_HGeGjNY8_ z)Hw$UdVP4;Bd+fIDqkpLzVu^tDJxR6Iv-XywX<%a=ta$>?Q{f-ZDG3hcz}eC;mdV( zeSNJD=Cro_`UP<-p-VUtiGgn5qHv%D=&j|4A*mGPYbt8D{&86xl?cbxBMxbTMOv;D zZtaD(A3?Zx*am|EUAiok3j@VLtchK@^%@dI#l&GSX4X)&eqb3Nkk3!m&Zg4=F9>stKB${P_3YM zz{Uq7(B+`xA8CVW0P_~Ay@hge1j?&O|LCM0x7R2@?UuUqf*wsM?v!;=i*Kg?jvV&~6vEJwz-JzYQYF0ORHv_c|K|me zL6@HlzDI&br*{7ex1|gVhxBaGRQHl{5UEpD4nk9s4FI|=8NB!)6dv1OPzk8205}O3 zf;b@R!}JWb?A3o6f|dE)`N30y@R226m%XywH^CpD7AFjUOek6m+itgaYvhdKnHs>o z-{2?X4IwCbZo%MA}pZun9>E(WReIck$0TpCpg+vX~k-R~+x0}(R!E#C4BJ9oZ*$CoY{DA?kERXiJ7 zkIFkQaQg-!{A7$@!jDEt_QJ(v^$;Q|Y^Q6(wV05GWz|z#o@E$g{KS!dx9!ZYPu7c0 zxjEJ?z~AH!&K}QZN3#;!5HJ*pK&5U33*YjwSW9Yt)8Uyo)wWPyP#(ZAd7<~anW%HI z_ku-vi07_Sk5BtauT`%k0BGaurku4B(us9Yw_;k~`U)z^y_($bDLs7A^Iye9w=;eX z>3y2on2bA4Dsa%MGUcRd9B|lE`|_lrP8?`ITG9L9uc>(lZ9yU;Kz1*w(~Xmm@)lNu z1Y?XP_=Sq5jw?^BCPLu(hd?7i00rc{r80okzc1dbb}zA9>aAYFe}OOFoxb7uik)jd zH(mCjhyRlj&SnK04J9ikzQkabWYxh-12+K%tv2>ga+<#a!D0<}|33WLd%o_cqpMk~ ze=TZygq|fu9e;h7WBOKS`j+haLWe#!k7SLkuC%UvsGHpynHl8V3xbjfwjI|^Hp99^ zQ#v&h!=}G}W#HD0nvR7}{Rt9%-0530`FATNBC;-i?-7xxM0EaihiC3$@0Ky4(0pMo z#yZj5f5`Z2O2_qT#a6q{?IRPD-T`kM*?xg5pymo>R3AL>dG7n>t$pj!&LMlCxzz&k z59m#TD`U6M&qekvUSj2<-UztGqI0%;%J#N85PulhK^4Kl3=^qx-g;RQM0q19CJhph zAlm~_>i-wlfp;z;iu9$@+_i+mg=b{fa0|CxDOB6Sbv6KTwZ<#N(;53it*)Wz+?uZ! z@>lGmai?t+KkNb2sC|ihz{uMU$H#gj^y+LVx{HCehpH!Gm-wr=>^(W--r%z&#c>lPlLOz3#PZ3V&G1M zd`q~VR15%DQGg*JBnK~VRT5L>@ezg3a5!MAxIY00(<%5Y#VEw>h{I7G?q*%Q1$fD4 z9I~9PAdKT}m;=Dn`qtH%?3XC9Cdk|OS^{F>L5lA#4e0Yf_i|9&H^}x|GaP$?41piW z1FP=ow)*(l#mhNQClBvxb4v6Jrmjm$g2o}Z4S>wG^GMDhJUUOL+6EwnkE};_C6WNl zbg=yEqtuKGL?|B}EvuN+d#@_R{s|7A41-w_Gq=`P@!pTmj>xQj>oOO8%F@lvEjAkQ zS3Wh>tGQ{4=efgUZXBQ;!Mcvb>WItYNZrDV6))eq<#her-roH+)u-3b{J4f6-O}D0 z11iauU$Se2fYOb(G3ZzpLY9EhgyS?1sw(^uLJkhwK$zy8o9_?^SbgtiCkRPGU{IiX z*zSU0q@M@iFjbqRcL>=tRBEaN@#^^-#C0Gc+8+jo&mDH3{av>-)z`!Y2r7AM2E3Uc zA16hk>?RO)1u9$1my|CqhJAsiRWZORMfKk!1vsDJ#;yP$dvQtA-9t}v_lI~|7i_f2 zjhJkH|Fa;g^~&DTuiu@pmvK-)#@Db`6296L_2qTbv;zqKek5|RHA~SdOh16v6{9m? zpd4(&1z>lOv;rjZ4nE0`1Na-sJDs7^=Wf^Y!@MxJ_T{HCKm<3XbJ&rZiT$dw$i1ro#uc?q_9LTaEF1f%@<{Of+~e&JSM^6XKJ*KXkfbos4C4ki(jp`RAX} zPQIOy7j~uJR4rnBA|<5*@;hJfSF!-G|;G z95zqDBIVZwzbLR8?gbgQvfSV6%2M}^q%n3PkVw%1tfj1?I_DA&+`{VSya(D z|L&2|>s$VuW-S8MSkHC6LBDEvV+3)m>76lWebIV72<;8QO@Bz?cO=7JP={QRD4abN z1{lNee^Jsjj^uC7u72Z6iP_&9dM)4brF&FJ**UHOfVz`6G>b-MpM%3Yp(sN=C@c?d z+Asc$105zvNZM1wFj11(2o*r!vYTj@sAR>=ayElD1nB@8lBekv32qK%7dLb}Z>2 zCI7(RhoE%K283N>FRz?U?fCn5iOUnUu$Fd|C=; zX|1J|=3ooj>&Vpc4J7DYqO5F=I(m=*O=OSXj#JwXMFW~T=Da$UIxb~{<#Ty=odebG z%9JPkS5i>v3~T(`-up{X!CIEdF=Gq(E;-&gKEXl??n=EF7>|Hv1Nmxg0s=U5pz`D# zQh~`5u<_R_oNUi-Z2i1C>%2P84+@=}rj(s?R$TcSxty`KiI-6~_sNu9K9ZGXG4H$b zJ$Lb5AZ8IL-iW)38prLU8Nvd%v(S zmXd^M;iH!?zgKXC)#JO85_!7!l-qvC^-r@p{)F}x-W`QwgxG04me#j&1V&*|BKyClE1}6CxviT*O)xvc; zG^QdScau?K_IOKIPJEqwbvx#7|7My7_2MT23(M$H~?DDPhN|`y?p}6 z5Rk*0PSkx98~h0HT;V&N@ET&^PA<3cYnTK^3(r49A?fSh6DUy~iekCuQdpk8#&HI_ z;%IbGKLx_gkhFL=9oFn>mXP8P@D^;4{Lz$I2otK+-3aHvx0 zlot@!*@l)x-EulueWKTF1o7E;f+C2dBq0h@vpOD9-t`XCFh>9s1M-}3*jb^@u)=-^_T?4Lk3;6|Qb(m4WBScXGB9bTK((73<(+}?FO zn!)2#MXfuHQs}E9F4#wFTYOuT@*;d-MmG|G)&M5K%!2RT$y!vDkG)sc?ysQc(zo)U zZZ&b`i_3EE>U`uMmxx~vD!PWo=l+bwNNiE`530_2QdMqVj*0mAe%=HEkzou+e=rhS zN1$$&t-q*WX6^nYS$NdJ0dwnqRbV;Mjd_gWiZSbaQOiW%qcG!s|u!CjGH%@(V zzW2Mx-;jo|v?&RO7}b4anpKWkyCFJ@5kmYYTHGf!RC)I>NiA~rce}M6mffH*AxQ!1#Eg~J0o&Z%wCT2K$( z-^xKYRu%kjD!WsrI}eroR}$dmARP#GV`(qNcIl^q__RFQ^uYZX1JA^F@5 zfP}QPhj93Nzw=;vUuZ~z)sM%ms{3!uVKk>E`>)M>8qqalcc=e-npLh}H(xRqF?lVl zTD6?ysN&!`b-00lT*)&~#Pi(5?rSZ}-zPM*MR` zrk552gzO2WFDu+~Sf_7UX>!?MH!T&(0k}3fs%OcNXW*Oenw80z+z=7(MdY6Vmz5>w zl`sFfV-OpG>&9Z``uEXKdyCpL&LP)pNg+;pojC^+n^JM`i=jS*Z$fdyzQUy;P}Q|R zgP>&q#1Omxie()HIt_Sn6ii|hs(x|FOB~hv zu(z+@R>F=(dG(sVPf_a^x=nLB4qcy=b4RIznJOv?I$)fHfezpt(1$SCFn8za-@pZ3 zCF=a%yV$#6R#7zrh8*{uefR%bn|O@umnS6tE9`u1J=^rZH>8^zA2vy;=N~@EeCm|Q zH`rfYwR$b_e7QNl7$19E#^g$^SO)rW=AJdMg&v7K-XA#S0~D4FMe7l-mBv6J2qNk^gO$!wyKuh z^8`nb$1N$qeA&yw=3yy!^;*$`zB+c_#dlf0kpqK+mLmcFY9Bi0yBS@tQvJh%H(dEX z2C&v5-i&easkeVZ&G^M@j|Hz%aU|wm*>Z2)V)smQ=**9W=anzIhA8{xYiijkug}F7 zbzBdt2oOasEL*d}6KNqiXe*!(^Lxw=Ro#E$*bo$!!6;7`WR7REO1iu(rwk6k312SZ zc(iqSqTL+6+L^N@Mk9mg4(%z6%aKRIi)QZTGuDH2l0#ZR^g>_;&fRjlG)w_Q+zg;l zNtK_338mFFxI7Yp@$oPW341Mg6l`OFb?oJ3Q$EHxcFSeo$>((yPjR3Cy7sus)``fy;=oLW6X>k1-Jw}ewbIUcPBc7r zP{yF;DbjlSXjmL~W3>4FBeSNsWfwy|zM~|u>ncB!^f$S&@IQ#ihlQ4f|9LOL;xEs4Q&{X%!x6%Fc2zZ%;PK8+T~dFX45F^~!8wmpS1d~V ze|B{mn#wFp(I#s9M7%)0*I4*-^3$Vd&ysgP{rAmy$6ZYFB?ToE(so@e^3kCf;-$PD z@SkdgheNl-9AY=R8R@N$#oQ7i@`evifaV}P1wQvfH7`&5LF9dcRda9Jtf`~hS)Ccu3N{H0ms%F@8w z+rk{hkqAw&wZq3=7DC!(I66f<4uto_@72&wp^Av#tDh^rt*K%$s#v(pLQfhD4TS7s zTe22GGk61}jwfZBUS{}z4$EEGCj~7p$A_$K{1~zFnU%1SVSt*<4h+jzd4mN2I z=~W^Duf#UVR`bql1i9_BCR|8Casp{vbkChRd-h;##mc9*Q@VA5Ge5dpJaTq_I;t_H zwo-2q>0f4Q>UcsP3V^Ug4?5A!;!?OHg*@722s(dC0ya>jFtjk7rgp!*(lK4&L8wz+BFUA_SK;gBU*o7G@K&kqQ4JEU|0RuUr28*VH9Uw54vjW9-H# z`<{{71xCMksrf?lMLY8mpHsf(4LxJ7Ime=nTpNVqt-0zF&!77(DBSluL4Zt^uRt*5 z<~&fbzQM#ni}QlID?u5PplmFrT>19882p%CL)rxiZ?Sgdo9nV)LAL#yDK z5_T+Tal39sYs21_(!*16&$RJaEoC`m;t6@=xaUwt8SqwZ!C7jvK?<+Uj%6tb7_BTc z39_+Wu~>P?pCBs%=IZZ$#daYF3%dVaKowbce#X^__;&_b#917a3Z7VN15+F%k=;m@$J zbBPn`J7T_)RyVnGb;4y)^ooDpJz-*Ed+SOW$d9R;2#)x*)g`>{g7?^)NT8CHuTIu2 z@O;BZz4kP=oOf00r=qOHtu^twWOxUXqBV%Hzx>>FmN?;de! z6qO1lCgg#fHh>lXMUbVkT+W<%E!aC%k0e-M;;q3{le~EuVBMS%Vg&+_n14%-wErkM zL}pMiuLbwjAPe;^-P57y0uYWU z2cwF#kIM@|{4&!sT*Gyku0aH$yMCG5VEdRf`%TXE?;3kz6uQDf`U5l(nM*Z#FQArlh91#WJp>dvtrFtP*I~g7Fz3TDoM!93PhJG)9Ee{p`sOQ3gtJ zh%{TV&s>-dnUQZJ_R@}B?lbHV9~h6CB0AW65MvoxiYRh?U;(4*;yZ=6{HFr82`-c6 zNT$4tIBPA1c6jjMs7ttLB6qRs#f?QTm(c0omXu@gZ_6B?iXpY7p~wa2RsQPSvdcn2 z?&7Cl!HpX;lO3bZz81CYT6T?D9gAJ`k+1YF*MFv;juWOK2RNft14I%7;-lbs!jAox zNSSf5LP(X62NF+g;RJmR-Z!Vmil8jJHX`^%VRU9{8fZ6>$P;8rx@2CKVXzV!E(_|t zGzk@*U@HN=VU6l8Ed|$23r*ie^_J+vQl-bg8wBE=MT<1OU`VsP^H<1o?Ib|%9jQJ! z>{Efz(>*lCcg8y$pvAEBJ3|X+7iU0rQkR@S>6$^~^_73!Z>?p*a`hX1DvG|8>Hw>5 zQrmUiA`;v_jfLosaj7ptE?)5jC?(EF^nciJ4=Vy>PSw4blT(6Yqw z0B6y%fm<^Zl9TT7@O94^K-UO)XtMq;WeU;P@FTb)NsfV?ur>j6+3fGy1XRMR z)b6;~1CZ#qjhu#w0`c6kILPtQ#N@weXP1!0jL4NNFzo9RL=4?ME)h$qj0gz>AuiMZ zloR_n?=^j1OmqjBRlfV`7c3zu(+8=-?o1%vTyy#pwC^MEelSohoLz4}mPWpWBdn21 z{ZuMU;pO`kY0b|`V%yW#`$?m|A;hxbD%ObWH(x!pw$p+mIVyN}#wL@!wR03aMXgQ1SQpaSkM*{F?(Qe;XJ^SPj%;sh?HM=MZMA z3NorgWp)I3g1n@x`hf#zc_fMyC3~7sP?}m0r<|OuD2MerdkPwfGXyVxVlh?&|CmUz zN+@o++mx*6h`s7gJYjY4B(rp50r#VW)j@JPC>TYhCkQr}^rj&5SnTj&zLk9LhS)E;4%HI;7$FRagBqehhl3;-%O(IPucb1u=z<3q zSR2PPf!zxki?B4-Sc!!ORbh0Z5|7u*<7H+g^GZSjjEuZ|cv)M~uZL5K!%8N^6DO^1 zEDZjf>gg$JFWXX4F$}T{Y59s464ZAv8)cB50JOGVEC&3ETQh$wAOIh{l{NQZb;gJ= z*nMx}?|0sc5L_o$|JI4Rzy|9lyL4r@y1vL+hrYS*ZU~C?_E=01oq( z;dj#cxl412K0(eE+b(rypF3yXo1Oh>O24(mOt)l4@O@_LsbJC0d_it72rrsSnXjM! zGv9nQNIzGnU1@%xeWX1l<&;q{F+0aQJ!EoN*M(2Yd|K<6p2cFx%?#O{>lI@0jd35Z z8qo!rC)`vRRnNU_f-5Q)wCh9>Ir?z>k^OkG)*X?p0~(nhC+kW< z0((CcY=l>J^pYl}F*FO2h1&P>8DPPi>=jR;_hwTV=kr5aXr0?d+sIagI2z)MlNZ^r zQIf;I{6rpQ6yTeDj82G(&1}=wHI*_Rnbi&ddDY(s%l~ba4xJ#M^eD{V!LUM$!5JDS z9&yB9&LfkuGmr499YqwM;AypUW2?X4&#Hw7{Ri~2gO93WPIr};lHl^L6t-bNuv;3J zW)SSs6`B{a>HeArSqH!1?h##s2D(GS8md>{40 zC0EkteT-Iqe^6VU9b2*+W3K}JeMJO7uWc=-x)N3Q*RZR?=f>+JSSg+rJsTn$J7Nw2 zI~fxT5>kO>Sp=L|jN~MHGTpX7{!R=XWvk&zX~<3T>lfnm+qu2jjm(ca1Tf{I<`-k3 zv@|mDI}BZV?zoNK7d{EAjt2HdC=Ltz48wW+?1+)5TWF~R7%KFUsei(K2gn}MVErdx z`yFPnelX;-dq){S8GsX!v#*n>H1dqunU$4c8=X~UdWWfGZ8>C}YktY*HyjiY5Ed3J>YuzyYg?EW4owBC0%qw@tLmAYE9oIB zL#r#+k*E79Id~2Hc^~2b9_GaFrQDKWNw?zU?nQSZ-pGjjKJ+DCsk!(s+c3B{Ky*11 zvLa3m^MZT$Us(*^)Zr%Qk#K#y(S{#F%DFVf zuj&810FU=0KSfC^yhI2=jY#6CeuFL=SHpa$a0+H(Qqjj(&)3gCK}TWF5rPCtAwlUg z6@K#TF73AG)b&XmX%xoKor;JGOjNkPokl=P-QPZ^s5h{Ky6F`nE(m^2c@tO$5r27G z9O-^R>R)iB@$EWTFKj*OOk`~5t9ePkc#9Q_iNWL9W}F#3Cs|BhEDln~h@s)O+9+8^ zhkRxdnPI3wba#&jT}A}|#fU;O_JTVR2Z+&4atueuO^(Ml9Xqy(fn}b+YCj@^m|rF{ z?ryP8+6h8>=?Mt}+A*y_XVm&kpN~bAqGx;aFp@x_i>q2{+(F1!TZi5Fvisr$^a357 z_l527XB|}65_gW5Iio|Qh6dL87L7x z!xSMUKZVEd%^oHO`|{$i;f>_uxN;^M*s@2&ckQRTbbWkZ9JR~sT|+6%5SaqMePiK4Ia(75o&38rNOd9^M&94 z(5iQKN#~V%?`>%=^>*@-KH37Gl(3kK)HO2h;mYhj3WWPsyYxcSCbjT|!5{7c z;VjMT{t;imPKirR&E6ri8IK&7bA7_Dx#sqfkx?eISjo*G82bMT2bnJr*mgLzpkyPJ zV8Bd0sw$1Mto${+Wy_Y5c~CZV@Y1BmRarw}h#`LGYxr?)Aim4{zfwdZ&G}=glva+;wm- zusU!c)dBwdlQvopA{ssFcObs9Eik+Z$00sS322@TKZbGjM;>RfC+05v-96aMUwC|q z6*>2Zr&jBvsd!n)*tCa9mqjK;B)XH64FZ(9mYvds0_P#G#$}(#u;6v|Sy?7XFQEaH z-0hTcmm-ThC}qRr(|m{xT)!7gTvV|RL@)hFN&+BqP@s)kn!6*;!jg)a+#g$@@f_j) z+R&E_nQizM9iR*nm>-q)WLB6T!DVH!QigfzqqAWUJ6Pp}jb=R;f;AlmaTtZM2-Ops zHdM0KLuQ_Su<0cCT{5ZKh{{mE^O|{AftgA$g(C+D)GV}u8}tYqXu;bZ$qX%YfA#a8 zW#QnpmElF-)rJbe;=(C`i75k53^29W57Idod=}rzSS**Ut^})@U7uSsarxHG|9)ST z0DXA?%!Y`%m^08>YQOxpD1 z&!Rd2SXg-w+;=h!>=F@AdYnu?GYr1}j}$Q=n)3MNZf~fUFZkCr^W(?0bDQaV8snOz zjE30EyK$Y>MlS%}gp%+odTFk?OukV8NJq|H{$T;(5fOWjlo=(;jVSOyW;6pEO&H-_ za-%T~0tN`=pTi|aR6z2~d?Khh*mzpvI}U4}qTZX&^ah!<$;cj#)b(*gaLDme3{ zTAIA8<%<&{iHswqxaTu$Zek^$9R`6j`Ay)}okUdLq0tDe8QdD?rD9aD1cSUb+#*xF zjyMGL_ykw8Q2mDxNXoGSZo^XE9iW+H`u5}8@7f%#H9hcXjLEoO6yTOKIqF! zMSxo`Ftx!OVWsoqnzZq!R6vKr)vTHt_}Seh2p`%~w>V?5%J;3E_*vl>BnhWfg1wN$ zWmQe;vv*%#aVw2K+&~}Z+>PnIz>kSF)z%X~YFB^U6}Hb6*iV4Nim8x5&;25z?nicGJ4$B%j0LMRJCzYZp+f-f=^w7T~1$ZCI9$GX5d+8 zFS=7eTIZ{i!x1XXY8I7#L{x(`JT6~784!%=R;Bu7rBz{Gkbcn#pXUft0T)RKfH9FtWO*VP zzxZWvET`3_?!LfeCZi%Ok3^&A$xG%xv=xg!;o)%$nS_i_LRLp8g zitDY2bWBMFrLigY_45&hw_GQ$hGbv^iw!K!N9a9fTpU)2d1r8h7jI7no(|;aUfM}* zw1nJwgCw=^$v-Ji?d(47o*j_{r>sqqtp=Kkp&^;m1;c^o$|Y*56Ev*eI$Fx)fDK$U$^qrzg~6`mmU+C2Y7-6Bua7c$j0 z-)wdz{mJt6S^z!*Tks`AdXNH%FEty7}fsQ`9Gh@(^P6G4%FW6}>{$qe%& zjrmc*(Syj*_|j{4bgzAU;QhrKZ>~2DW9jfkp~#jj)*OZhBZ+8~ZB<{QT~2LYw*nRm z!r6NgmxVum#16NVroQeQV|p?&xMw~OKg8*c7thnSF$D|3 zC5E!Z4Fu&&bv@QZa9WpspTgT0;gTsBR%aN*z;%WI`hNr)BL95S6cJgW|y?CpRajI>bxbHFKLF{}58*P0M(t^)^W*)?mg&0rSP=j_!Y<(uRebW0-RrI-Ro%2*bP zLc$k!^;%xQrHfTUpyBuzrD9Kjq>VAIGHk2OP7n z2~s=q{0zVtL&>;`ttepNkt|9z?(W|;ZFiTuWygN7tkx{ zDDq+%e{lA#m&!G_EH*Z^^!-)?GaiTQ<-zW#EhBEsq6ODwa+mhF?f?!h3?UAb4&2LF zIL^w`{ou)T{hj(Bnwn@_ISECE+q*ag#-0mSw3sF!N1gN_yC2+4eRj7vPT4UDbR`E* zSgO09Oe;N6kXm}eA>CHHFn^ycGTlI9><#Pb3*qw)qpS@^8OUgZ|CI%BKGlEN9#I8c zRVeDYoi+tu>@1V~?Bv1P7x3~zbj%KH(Z^n%)Y=GwN6JjbNQ2ND6_PgCV2>VOwU)iX zBZ0e;5%~GI4Wj!1i~!Ng2gLRXK?FDGd!9L2yQ>^LK_m{}%gP$z&;FhMH_uy-GQ|Mk zK&1Ez(k2Nx7BvTl8Ts;9tO{a(MWm?ClK)UX*m*i3qhhtWZz+CtpilKF3$v5+nS|o6C4h{Y%rp;~P=^r)0TZCdYg46yL|Nzy7D=6e4V4@H^Fm zF&q*R5^kzt5fU`DM7c--j37S|^J;Kmqe5DF!ZAj0a7Eg|p(q@kIxYqVLZ7)L)4b%k z!zc-1L{QLQ;r8v@vpmv~vXI5?kQ|_+m-9-Yrno(wptojawe^J`5Gn8Xs=kgv^2#ulSjZc zn<+^(A;&p9e579_Cx6yV@70kbELm4R&pZF4`vI>TL;q->h+cG-bGLyazkSX-SIuWA z*Q{=_zGW-8@PBDM4UPxxL)4)taaK?cmeACl(&B*A({x41ekle8YUMje#h?75OX13=>goZ{aGQa}|&tt;v$q)(um})JvTg_!Z znDsXuPBH*aKPuGhQReSU5iix2AstAvm8aHNmw_lmCK7X*HXww=fc+{6DT~3#TRWhW zY{l$Fy<79*IQzjacHEj^^gN6KjAPDa0I#_m1%PqMI|fBIg**YuYjFf0ZIjU zZ008G=ZBa6{iuJhn8)G^-`eG_%G522%)=%Jb(eoe&X;^hyi`-wGb1RT-+C&e!l)uP z&SI#oV^dt$wZwc@3TT)>#2^){MuKXPr4RAO^l6h?PQK9gQBbJP!HZ_qkfV9b48cBHzGzpDj^Enkd5Mp=R9 zUp}8#%p`d4&03DQ0SvE{*QQ}H6f zQo-1b<*>e$@AKWwD?VYhj9>STPv2tgY9x$Z5=S{+zkag}A9wl`cbzffB3RRS`L>d{ z36pexpB~~DN6enHvtLQ}W&e&SxOf86AP*s3eEP+n2T&qa9ErhzzjWoS7y9^@!ah;O zHzra2PH-S8YiWaiB<3XoDfKURpt+rOQMdO>#FA{H>Z7wzL($Vp_WM8RPj>YQqwCMH z;p=^CVTTDAi5uc;GxnUJVd+I@vqkmixv+$9h+A;FEQX3i$rZ%NuhV%*Jq%ifyG-EM zwIcp#qA4V&krfpg{z)dF!+Vt=mwc0Xm-$Tj7#LzWDmg+LJB#e^K5IH$$kFxyGYsZ| z^ipO%=yDxwG*PnlU-nH7&kEa5vHrE_`;u%QDb^!oCEg`N(E*|gyKXI6B=UFO2_SJ) zOMo@=J5-i$c1gKc9{tyLbIyN=LFTCCd7;14W z2RkjWv$F$DMb1T_<>}EW+p~BEM~Fw;kr;gEvbp}#%YWGjeJ3)Y>t<#-T1oy5Plrea zO-YjdQ7Uabfa(Yv6Y^-#p@YEYDfbpEoDWm3`QkK_pM6BoWeG`KokCQ!grBcwA^kP8 z_;3=?>LIWfRzSzd4nwuIug1>4u}+xe@O7p$iCpjfE ztv(+tLdyfnXieH+F>Vdn5tK+sx7{@4TEZ0Ui>G7mo5UkQ241-U28=+3I7WBbuU41Z z(3xS=F#(_Nanfr&^@KdBa|;eEdu8b6_#QoKd2$m@xs66nTU9&jCm+Di%#oO{U5mK; zzUZ~G^7ZmxgFvQ#m6p5&?T!wex&yb3M3Qo~eR5czcv$~}(r_GV&w(Au9C`Uh(yLev zIkyeP?_Q~7m!1t|?&qyWu6F$c@x#4FUSk2;Z#=G^-KS2F-#R%z^ubQe;({K^1~P&) z6lh#zcF94c0m?~28I5s8AS>^j?wU|rk>~@wMY7>oP>J1$f??xV z=iF^{I$7+?W}B@J@yBqe*N2hh1e9Y|h#>h)*ZG#MX-o~g{*}}Flw}wt|oCAx34?|fEpJZK-t|=-NTcs(rKxF&f+Khn7ICWKQDlCvg7or?4O{e0XQ| zAwkB<3b5Q0G?mO>FL4%C#!O8^#Ebn1md%{Lc! zajI{``0&inmD?8c(pT5$!a`dpyBec^AAL5{z?$My|%xHfz)vmxl z;hrUXP#CPt?b~mcM>Q`NM%`%lclg$JIlO@aV-I6O0K z>|_T>AAnzC_v|2hsf?dKm9&L5zg*$6)X*hZZj|ti9G~6lTRX4p5*j6tT`wbZ=}w3Q zN+hZbdLY9lQ{#)a3nYS!H`Lx57pGxzZYA;y29bxC0y5%)uU8iN^I^&DZ>!x zVro#m6VeZeO46VK(jq;dNv~ z16!{SCnd7XZ4XCl_m4XYy_+o)zMn32RV35Z9k)LAcGSmZ=;Xq-T}cf$-mUAxUTKaQ zUiQePe8a@Rz>`VENy#GThskw52#hNvuG5@elWga@)kW{9_l-|_&=6P8j98euOA$#J z$0?X0z?#_k2dTIoy8i`)-qE=Amfn?U{b;#lImKKzY8Ivv2HU`;aXZ0b8pBZB3V-8a z^Vq;s>dKkzO66^DC$0ws?_|yJPs>;mk*iWbH`I#;pWP1h{3t6cqC2knMUDS_$J6$o z?}hvq?A4vCf){4C}LP3c5*udQXNjf7V9i3;m#s#2D_ zM{cX#m<-MNwXcQiVM5vK{9#D$4b8(*htKDC3)v+jwu9@$L6P2Df5aUbV~!x`Ma%gI z2Ch-ydw9nwSoD2b)BUF=(TZ(h8CKE2;`^JO!bNo}p1+sR)NszFK;*j^MaD6*Lp^~1 z;%!c*#mDL0(AX2rdFBA1dHQ7{A1t0^TMBT9?uU|-lS_*v{j9!&jHzd@lrFx3*(ky^ zG@QL~x7~*v=d!j$T(qn7Zg4aFxY^rM^W$S=nC!h+_e0e5#;eLL&yF3S7My>B)6t9O zaH>xrW2CSQMRlTH3JsO<-|5>iw~B5ZeqHF{Cw2V2;L_=wvZ^B)yl%I4XQlblLD5)O zU!Cb!g}tR7pu&uTui?&}JZDzBG<@4Pa%8Jo z&FW91+UY@?Z5exj&@$W=F=Vuw+qc56TN(AWh@7}!G1GJV?ci zBkQN0f*v2~nuQ~9w#w6ujQ3bBZL~p{1IJ25BTB(63YIH|1`wbg`nZYwO0@f1B+eHM zp^fx_c-H*-Dm!v{%j%@UPAuf(Sv*qe?$utC;%=%R z1G`QGiITuEMFMi^nA^tY%YPwM`ZZ(a^dbMu&^K?CGnjW#^4;IBntgqCIVU6V#xGW1 z?h`FMI9a(tiwiUF-yeKqrkXJ2lk>#!%fNs+h;SY$CH-wrWdNyf9DRptK+ppewWJpR zWFk>DK|){S(tq;*%#YCQZM47LLK9^n#R7O9z1a12CoX=E)J6APu;~H4k-O+7<^Q{*?_<~kF-o&uZ-N^ir>4pSz!9zLGt=H3+iqvW%)8-Y#c%eY(4E zyydq*eT^@(6W3{R-n^iAjpe0@8JC4&2@BC0bE|VorY|f@t>(5iAo)6uFPSXhIhBjY z!p9b?vcS~j^K%$towTSjlCUkvl$%IZ+|iFZ1F4*j0+pd3!s$^Zdim$edek?dFjNR7 zi^4=nV5r-vRD@sRqQv11-#2hLa3sN1O#T}T9>m${3aOA>;XdOF;#_@(QBz+Y#T<2eNVTt)MPgNcfIFmEwF;aM3frh@g8X%_&D} zD=fhY4e8{9BQ`6_pspl9;Bbu2YKr52bGH(=*y5UmsY#CU&N92#l+rIwU7wq3KrC5{ zr?n+3G57pEe_VBB;BU8cg|0Cg26_+w#-eIwaB=f5&q&z zeLHUvI{DifWHGE1tqQv$myK5cw1?NRSj+!@7R^rcw@g)6)v;Ro2P%~l)~&22efwst zj{4R_109JtHfTyH?AUIxG9kkSR~jUsRdYKRk$E%bb}Vm3_bh99Ww6v|^~e0s$o9nD zy20&VCs&tOKEx>(sMgecyC~jtd+4f}a_$+IH~roVcQ0SK*prN2%nOaGhH5MxAfqySj9G*%o&~I+EsFf zQryh50xJ^K*WL0&eU~~ee)zh=!7ZcIU0z?EN>7D+Td%4~oTe(j+*&+<(YmErVn`%n zoHCQuqljslWRUy5Tf2x_xNI70DCY`RbgfJN{*-$PKVJPWsm{mh5U03HhHkmUkg|(r`agHgjoGFJK zf6qR@+xK>>KkCNKY|q#8@p#-H_rn9PpK}@m%k@zMt791hG2`9C4jG4rS8UdQ=&UVF zuhqrQq^w;z z8<%$P9u`>#51yV{zqPSs!zn2U6eENo!N*$Bcz3VP*^r3;CJ82EETj~x|2nAJ|LNBb zceqLMksEd17TQD;qW<9!4+o%i&{eHIv3O$`c#zihN7A&FZg78&jkLFar36l{5A85n zT#05YD=R+UJVE;s3H@jHvz(Itr`Fw5n1R)qeAd!Z@xAbYtDdd7 zor@bwiyL3go44p|( za8HpeB19Gq82T`nEY=7HN6LeZ$x)$f5u_ktLNLI&Rr(8fq$`~bqWZ+h92G(`@>CdH zemC_^WU?wzD6ErJa$s#E)C>88b22A%e2Vq37q2M%U1o&nh%?6ecod0*F=+vRmt zcjP*qO5rp--N&mx>kvTp`E;P(twbrM^&+Oh*AzO%M@r!|FcB9A$f%STndef_m%f_};?17tcc+x)ZmBs-Yp>Z_-Q# zgGCM1mUHnB2>$vO)hOQIE-} zbtlopi~u`?Kpr}i;s&@Ld|j6p&g1BY;ZtqbG5=Q|uFU3vfUMW@AV!Kk2#CNCr;81> z7(BZ=Jo~P)#c;9uu+c3bl6L%bb}=Jkx@xgM_UFK=VeR***dIVfyzx1BJ->Esz0%9G zb9QXx&XZvxeaP!N*6i(x?)AA!uPoqvcOYiz z4Gju1e_oB8|M9UsW-2r|c4;k5PMu7xz2`p7=`hyTR%+4qDha5$5*;2D8*z5*QJPoF zcLKPe>E)WKAjhs@7{+}3wG3TWS$*d=rs!8WfF%ICK!k{!;-BbE0u)>8D|2Ow*7Mf$ z%~TR?r>!c=?);-ufeJ#^#uq1|FI3Mfw9=CH6^Qnh~ zNe@ddwnKkCJn}2a)h&?eDANlb3tx{^K;ee~52Zt$DM@PN@jpc-)6Y;8#kwgk4W1Nw z9jl%BE7EK{NXzH&7M)4HxZuxIDSOYlDY7{MBxrBhfBfS|FuMcp$n7%PjIrC}Mk8r$ zYWhvX1aHDWVP$fY9l$Pf()(!ef_{e{$NrP_24#nR{l79Y4RLfr{R?a%sd1gyqhtAL zS0D_SItm=w=Q=5>-Xg&GvIBj8pil1G!Lv8)qz7c#7`SI&@6{h`pg_!yR4Dy~Ulwfd zg$AFi`#38YnKR=+%AoHRyvR)9!MC?4iDWHk@yEw)6IUJ-m#8PaP5g4!fztgyNuOnD ze|Tjy31T}_I3Qc;dysj@pQg}}l7hN3?M3(RbvSmQyVV_?D7sO1pN4saouQyUx)p1o zikx<#%69}LV<9O^QQxG?J%d(Oe{x$AwJR0L^sG0}+uwO#r!nT&HHO zS$ZPJs=9x21TeK@m+tGVjt#7o)GnI?wv$c7#_asN$+g+#kL{C_hn&dj;v=haEjd>6 zm}W2@e32j1!xg=>vu8h~Gw4nTy<3fqbVuQSg;q0&h?E^vkXP?_2Hab5B8;s52%3=; z5j5Vak=2XfM7%AVC6DeoOGtnT&xlTFdu+V-TJwdT;4qJ$bX2B<0XCYZk8VJv*C+)15sdYUseJw1A5s@jD@s)~$WS<_jMcOnf>lbug9I?91fp0gHx7Zk&HpN{M2Ef{ z*mTI0YkV1`uccA_=yQ)#cu80cvWqZBh@5uGa6wsWDse`xJb0?`xP>6QQ`X2)bT0|} z!QC?U(tLhl?MAZA;?PR4RgSx-*91FmO&iGkWFHmjMMNhIZ^nFQ<^Fzd>SBa&&C0+a zWL|erz3iQxhsuv2lO_)KC{Vu_(MY z54#tmFcG({Y?J(N9dCw`qzBJU%*-&6KN5|hf8`!n%BdSMl~m;a(|$x9E~9Eec2slk zyC40SwwoTvAhekZX8_TM+##2iD(B|Dgcm+rd;5RZx3x?>O`nQaHr5VC~Qg z)E^EVKX5^7{CP@Viyg12%Q-)cpQ=t7e;&pv0mb3N?vzs^zOT5*_7A>yfWVpkuoeSKtoYzBb^7qVlBkFdTyJ9z5;J~Qid-Ji%r zMi<1|s_y^x#786KFo`=W7f)!EuTQj#M?nge&GwXUlAO9)l8mJS5l6(Cqq5R_Ng=WT zRH}p0SuD_y^L+vE4eXI_*4LkL9DnZXp&NX}p#8vDgrz}aUz=K?r%q9Cd!6FG&vS}e zo|UQBVDY=K$BzmT@&c9^2=Du^@?#@S7r9nAJTVi4l2Gkwt(?iln&tM5p^c>kuZ^bI z<-Z4}r-E#ver{f1Q-?t%_*K6@Kb|OzT^og_!Yk8ampq`Hs@1X*3p`M{;4a+-ev84~ z#f(VO@wOlTeY_R8{$;lP-MgT>&(;lVHeRAJL%ifQ@UK60e~yeSe0wAgD6Nd$UsY9p zuwePWTbYQAf6cbNj0_8j%q&PJT&WkeWuKz7(4P zh;K1EU?Vx-57BnE;QlQQLN8PlRGW7}^dB##M=XF*Xk`gK-$jvGgy+xK6a>D2j<(&t z_y+>2gOd%!7g?VbBFB-b#?GI2p7(H|EpYS05D9jt_>aS^3P47Rr9yVuq5_kLJ5Aw( zUNQezcR{PStLNj5p5*fDX@c$WFhd1T3evrmeL>~9cURHj%%fs&+1%b4Bh> z8N1;$dyd;DmHQt-PgYc7?HkB~yxlNJA0a6SIqoa`=a&o zRI*`pb>1O?ZZ{#}Hc8c%BJw9Dz%Q>P8z&NSDBDCpJ)pw%m9se3mb@!XfhGnq;ptuM zlaAc4lCH@`0v=o-66kDe1%Ot%`X?8lj<7wBlpA#@BZz~_(l>d7z(3|06AlZoPr%BK z2>JVo>#?jqAK7C-5N!dEl_W{}ag)xLJS04Li%xzlxrWNJJECsttZs^w*{_+}Fl^T` z|8A--d|+v2&9Hi@_3QW1&a^^9Wo7X$oq@HnfsKLnIm5NN&YGVloi1wOi#PmRa{32! z&iRCfho4xL3$BVVP`Ks`7$&r9lYi>&!G+ipapWEj!<7^JKU$zZo(}B{NPv^21SlwE z#DtD?g~%N@aq%>EV(u##_9hKfySG$7)m<#;uRz%Z0wgUAo{pI{Tw8VNU%5p4{fcX6 z|D_B1#I%Otp^zdgp#PsEkkLC6X!c`o`CQ+dNkFrpnbx3w$gBk%g@!tqElF?uKuc&~ z{t?vdH?d1jbw$=w?Q|axr^uh({wH#*C)@tE)Z_uRNl6E9Y<=C@1Ot-WakhRt<9uCd z;LQVzlrA=~uk`4=u@VKP+a>A_KQ7r$Ad671j-4gmOk(GsqWB_&@;zr8?sgOZJz<3t zo&>x#0;~sT+!4lle;G%)0~X{j4V*~!ejy3QM@|V|ec4L$BX#X8FGx-~Hr{uN1l1?b z&Yp;w`!f3oU}3)Z-Bu-=f<-lzHdV7fDvsDJ|7h1)omDm*31E3^2!mo@rrN!^4B|y3 z{dZaYQG#=wrlO>)`?Z1p+?$H>^6u$y{WkD4Mow4u(S2@V@)x=J&IEibk%|US8`9JB z-0^Bz#K&hZ7F|!JP*iQ%lt=c55sp$6tY{GwsL%d3S4Rhyek#W<1WsF3_l#OzaeeZ> zPpQ+TtV*~hYrXc{z2q(DJkHQ* zgX&#FG|1!wGitD5zwx;)BPIm43)il9{CU0a+M216?DZQie<|8&s`Xk8h6rytoK=%( zbsHhf>}Yj$FhW70N?M%N45o^?)odK5?C|65`sOl7Mx{swex|qf%{$#0_>ytVcx(fI zP;G;;+F@ghl6fz4ZMV;D{2!OHh%_#?=!@!mgNyox;}xl4x4}MQe0NIE*?W8MM|?s* z0<_Nn=M$6$?uefvZWo1R=Z!||Rrl{C4H6R4JCOS^+m;LjoMyyieOJhjJs9B!5-=v0Gsh6z+ z!5+MGv}Yq#2@EFyW1&kvW|@Oh!ogx_BpNBk0GIG`NCA>^=(0$#*TUi50=tRBa3(@Fn1r-9N@69kuoStu_O-d(jm4bR=IJ$5k>53X*V1=#HY)Z# z1ltN*b=D%F1tt^Y!uW3_R?g7HDmcoJ+ztq(o0>qLy zuuXG-I33_O0@)6y4#O3Kpy4g3?2$caJA1%BWsx}oXoe0hx8A1EX|2nF$2dbEm`N*- z2NFPAZaqI0$f%VbPV{xpvN&-|kI4HUjg)GPlYtUmFKI%-gIL}xn2P01`EHJznLUfA zE;|E==O?m`bzHJcec7Y!bGBL12nRV}9{$zg*_lWw^!Pw}P0xJ0$ga<+Grv&0eDZ*> zuI|y%IG%Sa_Ckqnf+z*^kntCkY)MschOv(w5bia1zZ7`$ALohi(>{Uptkct4>Ai3a zVRx3mUXh~Mes)LUDH#NIk33f6MP{2mM#Be_^l5EgVdbz!->wizvH5U z2@MtYe!*5a@O_8h^7DF@XwEO-@l04(czC!@^hQ)me?+K<6K9eq1IDEYoXBiqukl$Q z%gEKT$LhLU5}l!8)@#Wt#fPN}pGCL0c0?lG9}c~sZ)Hia_~C0GBa7`?FFV?GrQRY~ z)bH0;=0NP*pw-6Tg4;Esp|UQyN8njy>@*Hyv{45-!xiuDp$WXEN-;@ zniuAR*WCwJf96OhpVslMqnE!74Gq3bH4d8APO2SDQERy(qrpXXHOs3|_$fI!RJuSH zHlqO5ap6RhgdNE=cKyv3(10m`-o?=xUk2NuK!r0Pt{#{k90}yldd=X`f#^03vO2YcO8pp#rwqUOmKDca8v=n3qjMDh#zZD*gn@dIGVeB>+dPY@F<0F4i_ zOZyQ~=GvrW0dQWvHsyO%pAe+osB3C!nt$Z*-O^A@><9yaWd}udLnkTGW2Wz+*b8~T z3+b5G)W&#V9Mj1DJ2qAs3zl8mCXyOE6;d({vlLdsrMf_E1nqY*%Kt&51&HR&f3=*<$W*O!KO zr4_8~(;qMEIpGyG?Ib=>|9n@c8fCdZ&H88E^xBu@OEw)8|H|ZKj$U_AzCX$DM*s(i zD5`mMM*VIme{s*1(9mLOQ*}7G0hGf&ONX~^hc7*NDk<7gS#rjQjrwAFf)FY0U)cw~ zgrnR2Uw-;+-ecB2OYS=}JWVWbA2@lwHfrVFu-8)0!T(!0EUZh@w7t@Nqt}+FB5g{a zrM+xJ3M&vL=@)gdg3HI=;E)#PCba~X9k)8DefehMag^Xv8-c&gqOvgY=4Uc;B{n}zZB+*yAh zf`aY-H8q-9-Sb%?1n{Tg5Sm56kq8@yksnNwW|URF`xNrBVHFXQ96P5`_Vc%$%hxJ5 zbs5~=adL$1um?vwvb%^Tk`eFzhgI@QDPPPlIF$6yMO+%^2<2B}1g3=jx9Xo>aP2g{ zpbvHt8Rz(4TI-2s2>C`0I%}(VS63I`n~r3gA!TP2kZ86!8kAJ8zTUOLkuC$B$&qSj zzzAb`FIP(q8i~cUwX4q zy>M6^bK-=j&U*8}h9bD>m2TPqUs6?n*5HA$`{DhSWmV0MgqWFK8>>?h^ynac6I^j= z2cRCc)qs%e(heNpN&%OB>r@@Dsi))OH3yyAii4?rL2hZ|Ut{iuSB5$JU7hRBbx>PL z7K?}ZU~4*mF(0IPHA%1;zTTu1aN0B<$#;1+?AJ~!E%dsD-Lp-EwSx%4!F|WF6tIm{ z+D<(A4FXs^T(0yWO^lQ;BABQd1t#E6h`3(^9^l@bO1b;=+uRrt&8Pa0e2StN$3G?z z$zxl#p(Z7}p1WO9g>W(ix+6puLIH>Fsi#}a?;$pb4%8>fLq4pezw({lchpzNG#&$K z+)^fm))jM>8{8Bb+gg#Q{6wvDrA28R9hhI?pk?(3g_Cc5f$8&Uci#L)y4gxLS0wqP?{kQE@r|pS`R|jQn)MU2)jY}%pL1GHG>*6VUoZ9{R zCDQv*&7Pq(K1B=7N4@`juu0d_;tN9=jz3!VaEBH5nRmh&l~;~$1lhJE!6j$S)WAd2 z(E<4lsWf2q{eh`Rv_B4`a$2;caO9qX! zQzYr~6&MRFoLU9RBCwjcIV{k1{7id>-wd z8bnXPf|EpNgGUJqwVF}I1pFK3+WzMLBFlj6c^|10a|CNNKkl>HR_2HPc)|_wznYGaTNe zwC&NC4mSYA&~EK$*W5}H!yobJ{)usSO>?aQHE{mk4Ga76`(L^QE`^?eWuY%V)q44W zuekq!$U@L&))A(=$CW#o#3mIP-e-Epvp{rj%jfm^wLDxi&A|u_Kq!c}*~m`CH2F0a z)>E*TbLuc5>27fe;Ma8k-3?a6nc!_E;sB*pfDm#fz$+p1j}hac3mthfz3#jAh`KEB z37VmjQ`3`0+Jqs=Yoi%JX|TL$c^&DW?~j0Ci4B6o zG{NO)OZK@)v7{qPyfc7hoXZVk_+9l(opzD zzso?>LHzNwH1EZJnrQRf@;5D|O_o>UW8_rMGU3;Xw|d$nT$k<=nuZ9w5ta`IU2F-4eo#fUY8zA+;8cejS$A{*AMcp+hLhc;i`tjSbBFV+gj%_BCV2R8%E zD>P4Q(qmA)c6EBTa|1!H`feSwwxv8NCj1 z^ZrHq_@!)EH^;Z7_1=xPh8C~rtDh$)Pb0jU*rjQCC^2DmaBr$HOk?Ia_v;p@9_*q& zPqPuWpWh@7@!nwUCddd;63e4L75*}p=Nc+0?)fH3^oFYBiH)m&ypkl5AIN>%(#;8n zyW0l>#U|gkUhOZR=J;b+`Dv{9(FKjrW=_iy^R2;6_Q9sB>2D9x{RPZb=9w`#V%xQG@OXNx#hDH zd^S933(&zLy4`qV%M0JyO8b4^db{SVEk6RY0ax6^KWv1H^2#VaB+c+LyMc6J8Wh@espK`AODXFu-5Hw7@Rgf-!z}Myws*9 zeePu$rDzl%dX)4j8)#{7!O^x&J@pZ5W9@uB)a*!;l^)PJsv4=FTwENcLbj)a+zXP5 zEeU`FN&5k%LyzzhPwkQcF4V`}I`4eZ#Jd-O9^nRE@nB%-kA62|JW^xs`VkHTx`G0B zAlDo^L@ z!u>}!QJSHtiv@+ApB9#k^sSmBO&Zut@7(u?)a!4Te%pKdXU9K%26hkU+1p;7dp5VT z(V$$;JyQlIC8*;!Crjt&!$w;pWzwlz?1^L|L95`*K{t;)Xq0%=5+p{br9 zcUHz_o<|)e`Y?-;<^RTZbmkmm-zE{!&nDBUq`dJSw^9#N-Zib8#m{*S4Gk6!zgSQ= zZrsROpC}B@sk;7G=y8ak`%BPPBgA+o>@RRirt9mb!~btWrNQf%Pe40c+Rq>rmHILF z-}19>#M&iN#C-N`#vMiAq$K3ny2&&Sb~OXoEh>;DpQ!g@B-0Gd+QQ*bZ`}qQz~&Bh z7#omfCzA+=D16u_P2dG6uCTwxXwS3oMbWF}4sB_oY%LS}x;oGa|;X37-^^!svdA{L&S`!Y18m}-IS5L>nmjAurMx^fm z^P~@5ssQ2hJl@IKVh(bAkX_N=^25AH*B)Dpe)~HTIJ^l`?oW2C2pGXr(_r;YO!$IM zV0GMm;(GdtuPZLplRZ)G#IuN+#_Aj6Ohyk+SC=d-&j&(qLY(C2InuQhUcf=Jz0j-* zU-tX9xV?wrOjppRt+cx3?uF9-Q8nQG4@Jzv=4vBp|#IN#H73p%NaZThBvh8LY6YOT#>5+52*d!x8%%ckjW| z8w`9FmuAqvAjk}E^{$rq$BcSRoTS6;l3IDPJo`0NrBOVBe%5fKq+vRGT*GGlWBB^) z^hSSY&D_GQNdJLl-1QrqBsUp{j#-u;I&p3Q`#=VmImvZ{x30DCP!`JVcQKEiG3@2U& zBv3CSXu8ORoShCuc%zxfZe7MB&)O@i?}}a0CdZb?>Q#YQjvP-wqxiag`m^hQUW1+G ze!UMM98J(rC$*&S$3wD-PIGePb0qj{d4M&OXl&#ggLZUihi2%fJXhVEp-|e49-fG| zQA>YKC8;nOcbxc&_gLI+5NLRq=0}6$Jw?x1&BWODx{uJ-ZJZ{@b);bM9>Acn?cBrK#K3E^%OUx~$7%8~)|?xLUYvgp9~ zx`5Sz*cGYGn$3nf1e3uch1iS0-gC*qC_z^%)g`$0d(5<$pO;qXwL12w_6)H5#Gz67 z`r?Ybaf+Xqo{Lid})Hj6M^s5 zl7+107JyBE#+jtuDDKyw*Sk`>o0EJ!;$ed!XB|^tIyMjT^Qyxg0cx6Ft```r*!wQ; zuGDO#gYUZ&4|Rc^HUX4x$5$Qr-3n&5-IO*2)sb@8{#VR+{56^*7bz!ec?(%q!tJ(o zdoM}KtT*>rEz0@7QjjM8*l*TZ_kk_2@K15oJ<)Yq{mE(X9(V8KoQsuTnmA5I83=Zs zMMHqZkzG_2_>G`(^M3jl^|eMog;9Y~VNr+#d6`#MDSJTA1-^)Pz+gOp>jy(%@3rnD zW2u-YWHbAnFGsdX_n}md+OlLOY~LPokNG$8zTMo=>}%Dy`H;WzyLT#NO6Uq7>dgcV zH*UOSd|m_FWa-czU;&(FSkIx_pP@W zyHD9H6Ro9$n78D=F{@MieZl>g(aGP@B~>v$ z$G)z~&K?X34&wU;Hx+$N5;k)cZ8?)w*d65tWwN#^Z&Sg&e`BK-gl_EJ#!SL~YZ;OV z2NI6ta|l$A%wOQq;wtMZjPoedZyHGP)1chZgIM;hVh0bka3 zG(J2XTXo9`_br(r9myWA;Gm^DUl=;wx$HyFQtaR3?%sKbmddyndgT1uUp3*|cSc8d zcK+hsP^qA9mP{mj&~`e?@?_G1K=OYm{jIhX-<`mC9``1s=|cYD`no#&O#nWjP{J7A7r$YKM^{Hm{n#zsfCxt;kYYFZw0>5qxtDAHRSDU(?ewZzQc^EVv5 z{8^6aYej-H0mU$XTs>>=;ge<;x!tddxxQLHn(AHy1G48L(;o6@d4XQbxM|yedAQJT zRz&RqOQuB9(bGN~a<)_6O+cZ%6#E@Cag5In6?AljHBDfhO-J+Y8a`v4w&XCd zc49+RyOE|7gV_=uGImrS0{OB1Xh_W`B{veg<`LY_l}+1dPnrC|Z{_%iapM+J%!S*qQ*EV&opwLEwucgzt}D*`1EVWqyVmP9wdysU5^;FWZ=9Q4DSPiXxrWjo?aLLs zWcWyU#(`&=dR{!{_%?FA4>5f;jF9ZE?xK|YFf?Gw)Hiowioop+6m_qP_zPW>R1_EH=#JJ$Z3n6F*G=e03mo}-HO9%f-}-|U1Qcsr;F zpD)kU)rMD9i0BF%%cHSjwG1&I4)WZ(qii&TiS9IaZrC>`lAwQj>Vb92z&WiBwcz8y z$3s1qzrFIvk9KwGZm3%pJu~ETOT*1kt6$nOOvfLcnDVFCODycpv|l~|!Ux*UkkFR* zkEbas3o^pWW7l{iaJtYRi+No)q+&;mx6A%|odKcj=0-*$J-Ai!s(`GB`n8j59LrD7 z4((Bz3ppF*1^wuc{}|QM;bw+lINy1ESGEdLyoIvsnscRG+ypEklRn7VzHr{#Zh!-u zMzVA%T*Zif6UDij*ug<^PIZU8jrvDt#4q?>ptF~ic|d}o^^EQ@JJW{Dts&jd=FYIs z+3ruR_Q)5v56yJU4@I0Kx_3V_?zep4X>D0`7Ptp8P2Bys@PjyHy+K=Rw&@7iO?o-EgG;`+@vj@>FBOHr<48~r5OLm~fFr^BeMV-!M0SjoOz$PirF zrB)-F(tu_hh5*)AJib;sc2tvqkFVT+FVsy2gDO(o`bs|;srs6BG7Ql=m-=|pViTr% zk$%jS@;|EAc8;mP;0%Qmf3T~o`+;c#nxY=++@2jOu^3_hMjM|U+H@jjrcb$cy*->W z>9tlEJ1g2{xbaPAqb>OA((Bm>aMPUk=<&~qS(t0r_#AFoUMZ`Y#RYpIM=6B+gTvsw zPI@@Oj2zE%MI3Ejk&bkMuBeIzdr`w0-kvqRn*j}{-G z62T2?JXbtw=vj63P8MOv1cD#&2g}!m%&oR?Z{QR_)|gQ%+k$Ap#Y1SqWrSWg1Oxdb z8r+CDEl23Feis2~9)T)|=Ho9;1O(!6C>-RjV;ixMqY=8dn+;wRc{$W}21%NcKuGZ6 zbtT%pfhLl`z=DI=pR$e#yV6X09@>>59Y!h|GMz9q~n3nl$ zR#JzX-$6~Ktnw5^D6SEUGx2pj;OP-8?KrzwIMC=B*@ARJL0vODZx7n6P^>@Al>q4b><8HAe?0q92^n`@zpn{r>{NUB^8#6jv-hW2D$C@ zyiHV?OczsDWoC=>KYh?NP`_46Ibohyx>uIxU8#1-)7Ajq4JD%?F;W|CI zq~I%gk(B8tA|Bc8!zE-`U2l8tx;KDJZ_K2GcIY{Btwy_GnNM8ReGW3DX7y)G{qHyf zFD8R-CIf@8eN*J^;~;~jYWQ2%H6s+zSZjX>5e_~o(B$r;+t%OK(LPbT`sLj&_sYts z^EZ)G@xM~K6{0$>M!l|dQ1R#bx|&hZSlA2_OJ0qY7cwU~NU0H07A~TajBsF8H5_mI zVkFzgydm#y*oc-bL}R1UG3CjPfS7J%3z-3<-#c`$GL8z=4+r8Z)ap5i4c9_x_3K! zz}NvcY0WGXz~t^SaK98Vy7$g+!nJ_aFTpnJAm;mb2rzrFH@C>XP5q^e<^BAUAO65P z+8n1mzC2-W6T8q|T%!rjia0r}Iw<;Pqpz#G7YNqWrH4*O zN9C7c?`SX_x6Vy1>@;~0z3}hT^^sehp=YL}JK+0A^LX-8z+wPD{PzJXYs({J;!7LL zzDBGT@s3oaa& z#q0>|bW2XM2t0Tn_h|9(T(-}>@A+?)Gu*7qU%cZySfm8=;Nrb^D6QEg_qIL|zOb$I z$BF(sk=9UJP#BaN=y#75AW?m6ALNsISBjPjtb*!7#>)%DlP_()iT^C$8;M{sczUAK z{X8&Zt)rx7roQx6vuECo;nLmPOHX+d0<{0C7LL*7|BTzy@2L)&^&-f1P?^aud45BD{3ljlKLQJqFsq? z3)yXIp-S=NLm%9V6{&!H5(3yc$L#HofI_5o#hytcp#|PI(+NNp{rq+}%jCR22g04^ zP~aE|*%eZ7rUdH8_uPSZf=MRxbZg#~9)atVEfYz*O2@<3`=fxJ^o{UN^Nr5hpWR+- z?S|`v0~@o8wTqLLQjKo&&IV-6@mF$CrVDYT@k0)GiS*qC;|`XD$yfq;w=37pL?^I@A5Y|W5$(D?=7B3{O}=}MSoP_gRwrnQ7TUst!MGbZW*?Ce3N1lTzWgx|Of-znJYhEw(VSC>rJ(C!}`x~3Z0(6p_d1P{tNA7$$VXClCdn{ze( zP(zc}NdVdmZ<~wGu7;UCl!YtV%A^SqRdRU|vxc+&v6~4sYb*1&HlpAAHln|REBtQp z$tOvf@e+=B_s@M4(7G46>b9J^(!jghn$6KKclKdf1itr4ZTq&bzLzI(h3b1RoDuno z4|W+*>i`EGIC&&t4Ok{(-e)BvYBCCr6c#m^fMy+7?p+lEP zdlo-`;YZwr!9dSLSQf{Faa-or))WEFy)wCH6qEaNiei7WUPE+l1} zg4r#?(l`8IP#dAMj^eew{ZlXZiEQTA#&c0#+Br{->*H?e|Lgk-;4(&y^7e2?761C? zB1I{Y4s;OZk2y}K0vs+mudNP`#x4ZMrX~YZaxC}}99uELD7T;>s6S>gx4Wl8v%hNf zN2kq(t7e)$9v6-}#~tQt<1cwAr&n^jBfa_~$M5GZ|FzlupVEbyh>CJIlY4-#Z5_SN zF9jyfo{>=t-A)-X>l5>5g7h0QS(!dviHZ+-IGjl-1N`QU@#=wr+PglG5xpC_nFN4y zRQko&kO}};IZ$Sn({!SDDHs;z=!Z_#yLugn18-c%T^_%LC9nF{z$7ZLAvZVaHc|*y zOuJucLiE$4bMtlN^jgr zBA$?A!a4uFX6;Y8d%7rtDifG2f6j1iyjXP6}Ztk@T8h)kNo-KXKV|2WF zM%mk#YP;v^g8T=if45>3$YwIz{YZDHakS~?vq!9O?!?HXteZ#@ZCtr~{gf4_I!xAd z6Y>{$=NA}y+>zqz)BKNNdr*gA>{_m|;NG)oXOTZ&k@=YR0_^pm#N%Xlyafk_pu(7A9hx7LTb-1@pEq- z3V|M~$~!U@nk`=cI@)Iq6l?=i_9x5BJ^@gJAa_KwnAbRHAOn0ZU_!GAo=moX%4;4@ z9=9at#WDuxx8u1*{XztIXYG#g^~Z|@g|Rcui?wSdz|?0h*~@z6yUm8Ev}SQFc1byA zX-awm|Ghf=LC^Bius;y@?}%xLny&G2SB2_~XmvXkRGGSfieXT^co$-}pmd zoqJR3+m;vwCd2WGi8xV#n3;w0);O5sD3gg{F%?y;bI z)j=&tnqSg;c#y^Ck>bB-%3|?!c9)!p>>kQ>W-3T5bknc?TwZS*EwmLv3R0%N6mBOp zLK*>89s$JX0Kt>A=$NXS-2`oG74zy&QN2Mt1}5x6F&RRXU2A=FSrP0OTtNzWNY@l4 z0Gbtm@RwAkcP0e%o|kLnRS8Hhc2P<)_O&7O;qW;l8L(CnvG(aY(X}g3lquvP^-ktl1}pav8eRaak3{uXTY?$)k|h-;fm&HrZFO9(ifOvSdN|H>`c;)sNQq`$bu}J*L52AOh@*;-~H(QqkT@N zLA#!i{fB~Y_EXyJb8l`RDFArg2m*BlN&wYj27ei zU$0;^vzSNgE~COhE2}pQ9L-u2AA|NpRb&}x|}buazqw+_ENiMs5RY3 zBlL{p&h*C<4Q&h9sOrdGYA4@QE7d{l6E&fa|HF?)xT0xzK(IX>1NwG162b&+nLMcU zwmC7J$pB&pCj-|@j(jJsv#y9hU0wK@o3lC@j9;4g8m&T*kB1`Swg*IT_l=JatRA1f z(SPv5`rM=1-fR78M0o*M9614$>o#DCsgJ|+OBNQS)33vxdj*{jocz0|AT7|3bB_D9 zZPYNKs^)-p+W4~;uRoWi{)=g+vn)ngNydno4GtjBaQs})WCG$$cITQB3WK?Gy2;9D zANJ56k3`p0sH?a&>u7e?V?!cRAyA@{@ZZybyFAJJ=J!cuoqYqvi*A={v)cFZM&mv~ z6?ea&eFhfC`VBJ}(g!&?3u{MJnO+cUa5f_8_xfxTlLYe{lPXzoTez&@h$f&;b{q@$ zx2M@(tAPEwpP-TKEQNdKnW54ViA8C-Xy?Pha{tLh6L-Oag;(UU7N7TQxdlTWe!+h2K|$q38--rLu% z_M%VF8OGOcONyfC2-mD2$XE?R6^LY3z3?r!u!PcT8MZQ*o}ja3H3qkFV=$ zc2wxXxvHyyO82R%sEt}%dd}77_ylFagv;8@#%qlE%zNM#7clGz%qjkDpDr%^;RWBf zm-n-bEAJ70tuZdKFm@t~#3xf@21KF>uCu4|V0?N4wf&8vqCdg0u1J?+&crejimEPz ziRaLGFbJz)xUlC=r}_c)$`q+$2kgOwm*>NsJyvRR3^T?q%-;d{+v?JzhJlrD{y8<# z-`Ceb)>(1v{6ewL`sBt$@aoKW9n0Rn*x7fx99QSWUezlhxES$hPBc$V;3zY*<+5~S z&;R2B)XZ$*BziNM`5OLLTMTVgXSP8awj^||w=5MNQzX z8iAQ$RzonW0m=o0fiC)l$(m6`W(9Pi84~E-n8<#n3)352q-c9V1Dm7)yp8lVYT~^} zfO)lSIJAYyROA$SZ^0JO5ik{Y{&p%e!n;cqSOAjGVOB-Ybk=fh*4u*nZE80bI(>o& z@>l0Xy9AES76qvdc)*h_a7*`*3MA=16Dz(nqH37M{p0P`3@JK+mj9k*Y+v%pYNQNj z1PpyI6!KVIg1T&<)T)~-7ULj1z;IWg)~}NJ4Jzzs}kuSY~OV-J3tQlnmExeel4@yed*o!%ovog2$f4#^FQKa@SS8VpC8N zYwE-D=oPu`O5p&#G4~q&i3xY80$d-Y(ah*HOt#|c&)mY=_2sgZQky08jYlnN&7g$P zH9FqZX%SyeM=Zer_tO%l&?_s0qze_+0xj={SW=_juCoej{!m$Y<6Sq)G!Kp&sEhqu zMm0jY>c-~kkeK?~pNCdIpST{j|)s+4l4I@UUZ|hM|JW%11BlD;HbKT!SZ3s^eo~bEZz{plT}>Ipztl1XoJ@oU1k4x z1BQSKZSa4;8fWP9VQEJ7dSUEhQ-eG!x+I>GN)?Tvat%D zLy6cLpAU&c+*K{13sC*q)h8R+8Zk)wdaFqv=9>Q5)d5h{AJ+cSXH!RppmQZdRfeI@3_;)|I)EV!z^yG zMNM{Nxus_LtNAq1_8f{vVj%&_I@1WhNizG z8evSh7t}RkshKADWhA7Mlr$wsH^h;JMz1GB@%yC^ zFq4n(V;sbxVIh4JW9mNIN)9g=>?BQ!oODLhqyaix(ovHzVGwU|>QuYBk6`uDhqU2K zQ&VGgmd_VL17Em=S02*~P>>^qXuM3Z)E*HuX_|yGd&L=iy6o*EWfdA1k80b??Dqg= zq`MQms@}svtV8ggV~vedO1FPwpUD?Q*?m3LHX3Bos$WJE?zvpzSc-JsFDK^P_HgNQ zxWh)O*se20nh8A|XU);ZNfn>Udycz^4Vt6nYsJYp9KH}|f`?Kqa^1$nHQ}X&e}Apn z4-P%p-{%mL|D=HOBuIr-6%UJ$U|78NKG1U)DelMFT`u{ARUnc4 zdZr4Z2Yi9&6%$J>;#EjhnHHsukWmARRdC9DPy#_p#s;+!rcJR7tCR4jQ=Q3J- zb71b>XpSRquczEa-*f3dwg8K-q3aAsK>`Xx@YcWvt!iN#lZq5&5@F!!W5WSNqKg)U z97X`YBAD!YD!{+VGBew#FDe)`glKqnNqN10Af<82Gf>BnEF9lKx(- znf?y^IVf^CJdBJ>PsdgUvS3D@d2Sa{EO4!tYav^#N$%LC@-Jl1xU$cRo=b<>`OS^S ziFpNcTbQVQR1DbY`VblmnvFk!A&w5&#b4{|2*qT$h~dN1EUqNm?+mobG0cAunwl%&5!qRNJRako53+<<&bXKI{ikJpS#4}) zsHQ-J(|5-u9b4f}j4N4)t|bG6AJ-65PI{ZURT$I#BsIxm^j>G-`pERgm+94%fsN_) zX@6E}@?z-YTNDl9>_f>eDeP79S9@&ravGaO>-= z2qd8N%5~5*dn^2QEqDMguj-Pqw$|yD^B~7$cxozQV#JUnn< zbQtehTVFH$O`%YGW(`2W%L-ce1a>-YB)h!Mt6{i=zeL=tpF5eOrQ zg)$-#QJLcykQbTz! z&w76@|8ThwTv^X^-&fiDv+p`2K7ZyGA$92w2NurM;@D&p;9E^H;1+Pr_bGRtRHymEhtN5>2ujH9u`8hqj zbj z604++SYq5`2DT{lAqH>r{mqW9zdK^yXD)!H-mQIrhmMY|Dwqc~y~D;=NH|f1oWdx6 zCqJO+;c>&*HnW&|N~>kr?OS7jejK-T{`iAx-}M=Hi;jFXJ80 zcBn~NPjW3PHLM)&wIutxNvjJVq)F|n7hkb;B!LO0dt&euGR^@#ic4!SK*1a07w9MP z>Lv?cxLYrqME}Ix+a!cForl*5F7Sw^f(?TjRPMg`1GiFSj88KhZF!+xH#Np%0Vq8v zXOl^bCc6oT6!JytM6!+5IWetjl63?p$iPco%5a0I<%rC4vWmYar!J(7P6g&xVe_Xv zK~v%3S2$H(H7ICB#d37^e{wD`W)m>d;(CfEx2e9$@ci6tM_^D86{G0KLHQAwY`={< zzx8XJr?E~f7CXBXi+M`aJx_nKwiUdy>^30PA24hf<2hTUY%owtQ!D*R0UwNMKE%N$ z^a=*Q_-!9jX#5melOD4EPhN{=+KMa36qU!H{k$KNq2;Hh%Fc&Gh0RTM`J1o)Ob@Y( z)w9!UfMq{Uydix^D*ZA!-o>Sl;=cTm%k)&{=I=DMK<}-n3gocbT3)=mQ^Td(!To?J z$2AC87#}^m{DQLbpT763$wm%_cMi&T1NoO{-@d|9N zg6(a{+5?rNPB)@`>8TH;__e}!+NGM}g|9W!;OSzK!J@2hW4qGt{hk8(d6hda6d#X zYpur-jDCGT9R8+d@^Z^5ih#1X;fjZawCwy)`~WStD)1EIn?Hp~O0x`3`M?k+C`5B@ zPio)V_bMPE>&oHGKJ(1>+%xv=)BUv?f$1KM-R!c?+1c5KhK62aWbQX8uh+g1SzWZ$;5G)$!*%!03*W_Hoi6uE4a90yU&VmKw|Oc{SA+HOM9ag@8Y%~y}2hU#bIOl`;h%fjf7Zi-PeY$S9`x!S*R+>dB8Ja66= zvj0Pcm*UX?IG@G&Kz3}FuC6{Yi->r6Ward$0%<;iI)3%=ddK=`;+auVZkJY1aWb)d z@^ZH^67j18)cUM8(*PVMDY-0jUUXt!z)CYED_spq;x3dWLN9pl|LS^2dIdp_gpuAx zTp-8vB3dU|D1?F4KF9OMBv3Yd%@A)el*N@U&9{1InPo{Lt>exbURYoqr zB?q>ZYt@?WRK{Ju9(um8N*4Aq@-B7t+se0^)stH)H&X12jU%6XRPS{r)p z+TzT&mGHwSZcfmGqC#FA*_qJPu$rED`OrU0S4|()M67=rH(#F<0D|F4@deZ0kS09Jm zk1572ypxwoh6Pn+G(Fn`ITEoCC6>dhr20^(K0#&Y^Zg#YtvZVW?K+*xz-Y_3CDesw{m z4yG!oC#2QGy_7yMwf5=SOaHk@Q%_}b0H-DVnCTfeFM}9-vK4v|!ffj`dSNl*Bw#k{ zNs{!Of<@{K5${8B))bFnD(t8st-sT+Sss(95Gk0oXjJro>)esrS%=16Wr@4_vDJV2 z*VC=rOks%NKGLn+)bM4>J)v14+O#p(LF-trxm@SxepaCC{Oa7`s&O2Ll|J1ECD#F< z9*<2GRm)~d=a-S1$C z&``mr5v|6FpY#eAZMDQ00Sj5K$k3WL<<~$AY@?91;o+{@g;Nu=;2^zM8dTvt6Fu}2 zPu$pCHqS3sGSKGh8o?Yu82!kU+(6HFQO9%k1^ec^fHs}SXg9R94OnoiAO7FHFut*A z(z~#lI`&NWddi#N*BO%Wroq8gwKSINo0NH1*Pk_R#-yTb<;vAGuG=1M!wn6GFU^GW z%Q{Y56ELQDy!&+{+RhJuQ2AmEc27{x2A`e-`R9KozkkEgek%QGVrRYJhL1X2=1x_= zcT(%H@BhKY8+I3aGSwPdx&=)#y`!m9Ler+z`MH-el{d+IbE=?j(<>`2EEYRZ5#j~? zzNkg$z9N^tWV>-DUv!T7i5$*~lpD9iM54kZ0+U1)G$Rpw(S(C|H10k_BiKr)-1zBQ zMj#q|NW$m*DY>^UKAyW{Ao`+|Dptcb)*OIpw<*>1y`DPe+4%*2TXK>1`|ry`1-J)* zNq`iIsoA0p!B#D%SB^JqMI>^tr zK+V;|JG_*`UQVxQH4F%swH^r!U;BGBYAz(|>!7~b>dLG=yrs($|9+d@U!2U=Cw|pn zD>Wp+Hdp}%eIj~407jZgF+VYTEM^+ndKv^pRf8IcrK&j&<&_i}*d!l`0@Y6vlBXfR zvWe|B;R~9Am8YL3I zC{v%LUBa(?kQUh1lEhru!TS>j(?U0d7UlB`Il9)tYSk=AtKx!g*h z{0gbn>zZlH5gZrxc2~Ov&>?AhFoMgOh=3?p*U_<=XPiZks;*9W!MKP|nCT5Hg^ zr6t5yu;N%AN%WBXGTSzm1{hgD@z6ob<(IP(T7)F;n46OkZcr!a5s3!m@&N z6)Y#OoytuLucrJkO{wTCfxDB78mhPok0NT1WSAB^35@R5NxBw5(rLcBl=yvklnE8$ zQB8ru_J95AQbbD)G8Nw~Leui5rZ{SZS*CgTHG4>jEi5;kk1&7KPW23XfM!azk_K2D zYEa0bHdbH%jxO4Ce^j?1U&*>VLE%-(>TfwTapl9n$NJ-|aVl}9Zc*Pt+q``fdL1TZ zp)abO%9x3UlXP@ckPYz2z(sr$67=TtocMk*Viy>*mY$PR zrDIz=X<^i$e5#H^d6qy=!vXCdUB3-k)Q*0!OEDUWU%&4Tf||N(mf>-T0vjGqGz#22 z2K1_|5Us~R@tqs{QdWuQK#NKc{<1*ZhD^-K{1fBUUVL?{+d^5{b15|orNQ;5<73_G z3@p?w8&4;IyUZ#H=?%#B&4+On^}&9{SVh+j&GB@0QaG_Zl$rw)?8a0{ui*MY>x34P z8di>x^!mYF4Y#u8tB&l#^He)Q7foDUd3Rr7*@1+%{2kK6JEs#u7C0|5>^-n-k25$G z`KGx!p@KFs8jgR+^n%8w&f!I}KTWX9DV7PQH6hQR6p|a%A?4Y+&g*`*k6fB7?2AYx zqPll`4;~S(!ZS9p_DL+Xl(nx-nwxJEm|Xh5kWGF5ZK#q{xWi|vGchb zqj9O&EHtRL6*xIZk7b%2&5WA)l5W~mwV=gcc9?FPw%-?RTmW;LQpSs1B9Z8zrxEVn zMH_8F|LENxB7sW|%6kQNtRk9dgOMMg&g?cC&5&dii@_QhnVjq((1r#IX%YgbsOp(% z6HbHTr!Rs~d`oSj7sT^ND0KNWsBiVzaxILCB5@Gl;8(> z`&>~{RytbS{M|Anc7#pl%c`pWopYZ%>maVEn#8CYmQPMyyB2;(JJ3HvG}`EsvOnDl ziBWjfX*{~iW7AP=Z{mfpWAJNwo1IZ!Fx#n-W4Srtjlg-*!d9lcS&;lMm!C2*wFSFx z0>w7i`@4=R2FFy-mqYFQS@wtcS;;xea^+yv)WElf)^Gh(3}Q^nTe?$|xy*$JR}Vj`Sra>Ww54urmg+SNJ|KnK(fZ7uZo%YWS0NeH zphivTw^BAy?y{Bbm@e0&tp%`QYL;LQsY9{~_;hBRQYQ;RxRvF{`tY@k3aBHbyvt8m`r#)O18-k#OR``P3%dyQVH5k zxU^jd5qV$nuurY?yj_r}SZC?>cQub;6SBDSi8T1s#2-2W^OYt0sKuvn=r?c6be^w1 z`PzT!pV@Zi;P*)o1zwt^+pj}b75CTwwaFX#waIsVk}!Z@Ap%{!|AEeMe2ZvY~EZ3lgM}puio&6uz=ffN=~- z98r;BWMhRhq3Sf(Wk`&hDnBk5+8E52Ma_-&7mPtoE3H}xY4S+GVq(gcS7nfP`SR8& z377vv-FM^KQ~^I(@%>pwaERAQZ3}fPgXNROKb2FyE`7#ZFg|MkxYr23%bO9sYc6C8 zk_G-fKt?8H{{=7j2PtCP=r4qjpP2{FQo$_^dEa~j@mH=65_kp}+-|7nv}8r1k!2^X z81X{Kr0s1s#uGO)94Ln$ok_cXXlH(UVtn0V+sK49aN{Xde*=on^`h3({NA~D! zd*s?|%eifJ*UKPhjgV7?`>R#Y#v0x1N0G`Za&vv#Dp(*Re1%-;FnJi*VrY#a3K~8I z)F29d97EjEozrl8Ro-SKB;%0}V+SbLjcmPk#~4`1y}bi_W>!Lb)Xd1eMDyi;#SNOt zrpj?F##HW^>|gVDWL4(s&=bIRvp>k8@Yq0u;KbMP9{bUfNtO1|j_b9xMH$NYWq(2&M8;0C9zUCPP*uzdM&A=RUWdnViH)}XtnB~CUdVEKwY z-J~vJ7}qAGg~YM?L!3C5-Mq^x?{FgY@b>MarcKf>294}TL>py|yNmu&Ul$jmwx@_a zJIto5D;+2n8sdU6yQf3knEy<2X>iQzP=m^DCiMn1>ro$Yc)8~#WX5@ieE!tg5bvNe zXDIDqY_Q)A1+_TV8jVLUJ^}|7Os{~RjayGfMI}N#4-kSEyM%~^y0MU+8teXKSX8st ztQEBc;W5ocTTHd1Ux(}uTBvc0oF7rHYuc!4QiB@U2Se)cb_3*}H*Chz53x#%M_y>7 zxS+>^&d`YalY$19@9QFVrRMLG->tA_V-Vy?nVO>7sk1qnfy~*W){0isud#@Kv;%?O z{o=3u4p$jJxzt67N`oeeOvF$iD=8XYau>M{xB zU@`a`1E*CTAl)QhL&Lre3=P8I3I&rj1bEbCl3^rXzwKec>zeIKF6be(h?X zn^a3B4q!5)qP1_~YxNS7z@hSKGvV6T^z4xAEtX`a!vl9=Wif=4FO+?EtW+(mnik-s z)zeisOfQ1Y-{_Tv!OV^$MnX<}vLbsZBaowJDKfdNnl`9wq_Y8^cFmBCzu7xxS{~2Y z7I>!biR-|dqz#}K1ny|SkTAJO_}s?{++=+>o>K*kd*^}@cFk?Un_}>1b0q96g3{IU zO6%8dv!`Z{?&T6P)_2p%6eaC2bIZKinLp?6p z$YWEVO79-I#hGxk%*^w8G*xnHGUGzV>#V=d=>*B2d|~&e{a1ymcll?l9^yqApAClo ztk;bGAV9si=gz+1iO$`Q68XA``%+HrP{p^9j7FYdHH_+n*Q28H-lXCJ+Zv=&_kQJd z=MH0}k(yx0be_LcsRI*g$+dS0-si+2f1TpXAn^nyffxeC_Zn3t@$7ARQ7Bo@#I zY`nUP_4aBPLc^2(!qBqL#e^5o#%W1jR&tUaYw{vQt0`Le)bT8W_qnofp0=jumo-tn zK;jvG0!J!fI-<$1Ea2}Ps6$wFq*lV9= z_bfi?om8N6H`i21@Ppkl=Yns~ZubU3CCi4SkfYODp;jc;gOH#THz$Q8$1+m#m4l7K zc9rK0@e#9&;zS>%H>0m=@u(puQRuD>ob$IO&uu7{_W z@R^Cp9&Lsgik+_*2X#5a8jWr6b)#kLmW6V{uU$i1U=T-xEWux``1%&~IuYqoGA!5;!Y%+gfulYtX{FQJspsc?D57dQ$Kf} zZv7_{3FHhKR~``p;3z+$KR0x))kn;4&@6N_PiUF?p?jcX_Vec@$QLar)4mpx8pjf7 z0st(+DtN)uEqA$CpR(KA=5l(>R!~Lv{OApXld^~P4aWU1BTGv=`CApq7OwNs#w|qn z0UY{esOw0X?I~)Dnd@uzQQzJLyY6^>y|B9MWY(?^g#V`nkor6s_Q`Y*IqO+pt)l6a z_xxOb-Zx(yT`$O`QuU}JdXSx8P9=?*Q<+;?N%O04%FTV|L)pq4+@Q!-zz`R;foH%# zGhJ_7vs~FKU*y>hYEF`cdjBp(_Ulb>xH6raUB&DF^smN+yo{P%9^@axB{%Qu?S|4| zb*?cp;;OLj?%jP2FN*Kh4ruhMIuz?j48k|mvBNj0qTL8M2jay9%O4eD$TSz<$+9k5 zK994H3*v+r-rTG6)bf*Lc8jLRPC-NPL2K6&swCCqbuGu4PG2XU=f;Y%J{WA|SKGg? zczuwlozrq#*NLb4kKzMoPgRBH3omEPuMOz`W=^muW|HJ}nR^~MK1fc!(!BY~fv|kj zrhoGdyUfx~P?jPfsX6v;%)w_OsmoUK$rO2#Vf^G1K)FD}j-|NL@) zc0@m;Y$AIWZ}D_)&;hUTDmV$;y@VLTTk@g;Y}qj3NgHrQ?iR7bG1!KUJs>2_;WHdQ zTm1ZWJWjN}n%mF5q=wioW9~n$UL5GTlL%tbE{9s#NY!-Bt>eYugViRNWVS8j>k&{4 z!885o+V#A$^9M8Y3$+Sl*C7Yu9w`6ASLeUh-^sR{Hh&pvgGoycdcF}73(MC}2$?=S!j3E*!uYABntd3O`xLXx1JWfM1 zoNk|z;FI%neqc{}Iu-+)J>SNv74^i=%Svv5xJWRQ!&`ZAlhY32NRs07;_gBO^wZ*- zj=D(CVU;JJ9yZM5!u%tSW$H|NgzsEtybLYt@@(no7|ot+ZTKK@RQa`moT>+?eo5%q z2G>~qhIHp*K=DSOD%MHiY@Mjrx!!dxCCer7WwrCji;vIVXPhiPLEil8WcSx|tYQAy z6BfnF=wYtv{Yf$rNh@ad;P)9&Qji$Km|qognCQKyE8cA1;PlF(;;r1Hc-|@NYo#^X zgt?Z377WkFFU%^;%V)nHKeB!|ddPL_62p4||I4ID&Ev|6u%sC!MK&n;+rW{fhD87L zw%G7DiLsajHYbD8Z>Zga;b!GbY|Yb$J(VhFt%F zd-~YYV#7uA^?UkjE2C~N*N3J)1?a2^v$dj_z~Vv#OTu*oS%1v@zKuTAy%@(FOlG}2 z{*PAC-55O$jY=EadBD4=l>hR$;@IWd3TdxD~B^7x%W`{4`l+4qGP$8K`zU31hN7&+pYAK5y`aO zN5Sf+Pm{&_(e<`1y)RX&Hg*AB;HUuGrti@ zQ!8%573Jz0;oY6iTC;B+Y-FGnq1Q@kIh8ZAUxJ;lv3jj3Z{=m3#X#qK)@@v&`2r{}Rp`=@0Ga?5zh82%dpBWLkP|KAcE z!K>F9mcsIG+e=N#4m$YD`;2>P)l!Zj30`z?`*GFyTxqC-IDLGre|<1}y&-Dtv$4;8 zxtfIS!=?xAI{LEzbpE;d*WIR~lAku6v2T_MB59H?)d5N*=#$1IL+{3oDJn)t5|{j|`UHP_VBMu^2jIdG_O_1C zDaF(mRkNzHAd@Yn4{zCA?qG9Ue>Hd#yK4a#4mOM&R**fw#F^XQXS@9$o zdKy7cUq0o;+xb)?aE5oM;^SKG|DW2m4`jUMdtL$i0B7;lAhRK<-Ceu*adWXkn&Ix1{LkFRbaGWL{QMB}jhM_oYx z>uSp`lr2pMuP(_%QS+ZxXLXu_BO-dPEetJjJ*sMIn1u&qA?cBGzw}Rx<>Qk|r^Bdt zLJyfD=+qAAbZ;{x5{;-ZOh}T3LFz*%u7%0t>ynM+*gxr&_r<(EVrBKMro}Y>4c35e z6wvn0NtC|3x#%wUT!%%HG5=4N^`@WCx9+8S-Sbyqw=faD&qR8@5Q~X7&8DX5!Dq}X zP5cxC%m-_Tbjm6g14Yie>U%Vt4H`ueAW8d|DqRXCg1ZrIdmn&eVdhA^hDJ&pi*r~i z?Uz34uc`(8r`GyY{q=kHX5r__Uu?{l{w1mxe-RpM^}vzNQqwu#iX_4Avl;Q>3K9hLiy^_vRO&Nipi2cooRJGEpsJOCa;dLaQ&d_4{(r^gBZ} zEUFP4bsI&+T|swGQ9L*ge{F=2V#Qo9if0v{p)XReHyqLQ=x<6bnXCDB;Fg8&Y5s8m zh@M^B_$&z!ug5FB?8y6@;iR9tGunHmiG2{4I z>-&(QhWRH{N|wu-jA!pq!!T`b`lBzm^@I_BIqRQKvMcxvZA-y4rjEY{>$Dnh-hA5d zYM|Lq^Y(7@elp_R`5^0LZ2vA;`pO%#FNcgm2XcMGOI%z)F)a<|0${Ye$FrVuO%Yi7baD+j=H@DTKVH2L;DL-90NaZ zstX~P@DKRAiSs(VA6zx-KY>A@Ht2ge%zAYf;yhh8iM%;WscIf{L`m;bHgI?>M|-ULj}Q1h37iX^&&te3 zU%Kjh^gD^bVSG}Ks=!p~UJFxj@wAIfKXv^;1?`SE8qyMs+JAwCzSofN&!91dVwklY9 z=f=31jW=)P!;j5weiFRB)W-+y4#07)lXBGe3?y{v4CPfMMzlEw zJUICn#(TV7=5h+`M8Fut)E_dqrod%ihq)oiFW%<$-7gFK0l!DaU9);0oJ4>V9vO`N z_H=LU^%pBmZtL?O`_~6z5=VQVy_tZ?i3D(lg3MzsnU9>3Kt2bH+t@1}8Z$~rLlR1Z zr?j}EZc&~)unR}BwJudqzfHiAM>1s4-1GN}FsOS53_D%1C3j9Jr`p2oDZU7f)jpaC zYmGsn#l-rjm0v84Bb>6zhQ_Ka37kd4@d>r>`tOt^Py_T%x%495KM)!oEsJz3@B;xbuP z80A=NXb*Y1-M4frdP2*!c6H|O65dinu1R&-bmX(uT@qaeY`8?1&Qy?cC|j-|KiO} zEN!C#h=3bob$SZ$PfqP`zSMgc8|w3ht3W7Dr8fL&r=w8pwD9AFt#-+O9f;&M%_ETG`(w`cblA z*_Yyt9-l{pT-F-StDyoWsS5ejm#uOA^OP`utXVPwdfjzIt8xaN|Dk9vW5Cac{EC%*O&+2bbTUo?Zi-P#^xgB zgD5ZKq$1CIy$i7G2%XOEc&O%aMzZvrkFAlvCJ~tCF4R2ke0Z?YFN_nBur$f*`cW6Uf*g6=PS1*{0R6#>nMcC{qPSL1%DlojU*=4{&w-Zv zH_U*Y0%mY=N%i1%g*i9CPM^Ynk7c@dm3x9BCfG!IxvA3hjgbr^E5i8il$JGvH@%fA|zaz zrCkxRV<2O*#kgG(=vn%jl*1f(K+85Atzo6@O}DZt0N$YdB_jFU!A7%2LQ;PFL&;nv zOLA|IJ#8E^nry6mA0aB1c2|Vf(TrBE6*+qH&vxBz0&_E=Vp^gJ$A9PHTky@MCwD77 zM;kbmRPXl%bxVEJmy7mm>H5=!vR*sN(TPBwS4Ea#nf(K2ubz@q0dJ^}e{R+}b^ZJU z=V*>2mCqf`bEFD}xEFJjzovS;0sViL1w1eVKQVxbNcDubVe0^Tg z&UJYfH$G2y-OW5Nmag6lIu_I0bg8=k(X`R#&iSuh-zM;uuP_D>D~*t7i>A?n)PNW->v z@~k+$JZ(~@)fc|naNNJunC=hpL825uR96|W5S~)!nfKpI0sN;&X2!iIDoH?<^iF{_TX6$7XM~^ z@!mToa=Sm}JO6lxzNsPBz0OkYj@aqA@yBB&^T~SKRg3RvMK0HWUX=wo_Lt5%4ZB4y zueq&HI;@M$m$c7JN6kr9q97g|s?LTWEjufbGf%eAX8-u{Y}EP}pD>9D^|P8{QoRt{ zj4+#aY24_1m}O{9ZKf^%mP$~NQ=>#Pe3dMGDP$wmbE{(Dw~#-@)M<2Mv;oLS5zvKP zdM+O+7vN%DsA}$8h&YPokG}m-x^w<&H?&Ys4Yc<1%`dl(%?~Ak?eAUsv>0eW=1Xd>~UKe zdJ0F6%}TP0`3k`TL+O65>tuWlsS6pfK}cE%^i}B$NJ3Gp+sGb3-BgmiFl0i5+F)=h z38MB?0F0A}Z7{Z-LC)%w3+eCTo@jR+Mln!Kiz7GB<M7-ryjw+hdTHCgDgU>ZZujnmM>p)@FD>H4HX&$c|1L*@oKliE-lv@fLe(v zTO3C_KCd-z?lxbaSgO2AvGlTj(1@#DsVZD=U0<5syf`%54synPZFvyudbuqZ=fOZH z^w#m+_`tTl?d-{~BXi>>`j5>^s`Gq(?`CC*hCk8-%(DP`FC$o5$4-K7z*Da1ofG*t z#}rPfvL_w*5BbBD1;*O`3g2pydYfDWxz3$s{DQ7r9cwQ1;y2yN$oA(Cfn@B1@1coH z|1S$=My! zL?pb=&<#7odV2Ce)zID~LpvS&--pQjqjwz>hq!hH@9*<}%4LW$o&oLQ=>3xiym==d z1|=cQjrGQqBmxoSfYC72zCy52KZ+1o$Vv>svTkv`=UNj6$hO@uEGH|n=E2Ej$@P>k!cwRu%DN&!c#MJy2|U6OeQbO=b==H?Z}%xKpV4O67P2t@IU~Q_RQqdqNI$JB zV|LEu)4OQ4r`_%=MW;dLVx7ZK$6G#Oa_vOVJTaE)KlS~k)L$nEC*}D-JNVsxa@LkOMi8!Y<#+Jzg@W!-Ek{&-lhEXGyZMirT+wS z)hsC`JGJEmL%Ng`0gk*N$7su9Qa55N=%aZVP(HQ^`y`e78QqvVo3y)Vju5L3*`;Xh zpVd*^9vYQ$n{L%egiRdCTWzY#0hoJMw_EK$y42*BQ|z-4#`F{Tln?B))qo9HV@8AZ z^yz@0%hAaj>y3T)gO``4^B<_=#?-#?!~6K>5;}jv(829}|22tp1Lbt! z#?|d=)+0rBLiUO7uq`)!tBZBUFmWdjyr9szW)s9PbXqb!H%DADx7M>wt9Ef_Y4u)J zx#U`yv{2GLU-^T6+o~w@<)KIYfJBd6xC2{`2q`(0ROe|5P>gGlQRTm_XV$J>krW6Z zewI?Surm$NQ??9a2nj#nOP!SMR4egn<^CUDK>of}p^5&QMri)kaO5E$o*KqZ^w9)c zv8u*Q6v2^Ne;k+a1OyhT9?+h5i7jB2{!CjnjqwH`QT-u(Phb|p9;oq$b6wx=dlIil zo4W>yqu{lhg4-xb^H$s#ofr)ZDJmg=uRg;uQHiCXIi$~m8_OZ*PD*Z@i_FDvRX z=L2Y4*TOD7ty71npR#E}VP{*&sF0V4Sfk@7Lm!oppO$qxl|)oK&qwH+lIvzHZxisM z_fEb@VV5r`Q=!KSLCPm9r-|_J^gYZI4eN@bK1KMq>*H^_R62GYbkc~6@Yh3GquHi5 zR;q*_ecNu^atfZ-gTlK@G(0Ry zSy)&Q6}Om9D=#eYYF1WG`0m|%?N<=MKs8XlKEJ-afJA=1mzgm=MZaiGS$!KSfbg4> zT_T-m0x%9}<7&P7{8Y-J-Surr|J}3W2i42NsijJ`F2tqaN zrkMjJmy09O)77f=VY_YH-Lw4$taNW%IBk{icDUR=iTF?pA6F`cp3l?u zZsT*AC}U+~3sw4zsv6q1@digehM>qL+|rQ4Vzh2Rkrazk-`I?xxCBL5jB0QZ1=WrJ zG#U)Z|MK2=q`^}*mOfomvplOG`8Z7y%wl=xCo}bYI|VLH-BI&bulp;(6zUaQrC6_D zxN%9%FI--($Q>u(XnYsz*KRcXL7h#}JbB=EpEkau&I1;{vo-I!0ke4{VhvZbXlF73 zOr1t>xW6m@)QDV4LJs-3Hr-Uqn!rBhZOz)>Bg+GBDE`Om=aoJU8|NNsj69s#)!`yA z9z|a}{HT5ONY2W9SnK%v_r?QU_lvQ>wvspa1$K0oNXl6^TA<#)Lx<(qp>6{(nepNYO5WPf!9GitVVVRR>&PoTSWB}RSi=u8Q6EcACpNN3M7~)2T3*;0gxX)RaOP)f z7mN6G1S&=939=EZHB^YbV9YvqT9QB4M{B%`l~Y4$$EcxAh25;!HJdhGk~R&(}=0r@ya&HEmf-iehQf7)`m?#6$_ z^j(Bx0`tb@6BcK4gbG|_#}5q~er%|sKZ%Xrjd$dU4yf)y7?n)7Ki#UU&78~2Q&_mJuj#1ys)f$AYB#E@9I>AA_q;-lqGr z9M1#R^eo>nI}3cII1go~YJKC8Ud4IOzuY$kTj9DFq%gJVtepHF8{+i<#if=_9$|9% z+#k?t)DGkLqmX0kBPl30(qOVpEW7K0?a$&0Y`p~Fwe23j9oLoMcZGHKHktYEB*`be zmRHb@#w-5PDY*N;Qh%emo@8}(sbQPF`PzW#7n{fCVVD=5)_<-&-hr+Q`Ci^5-^1e> zcJNZ5xJ6*v6A~;WY?$rTHEQ9a=$hDjXp6T+CyS98wc_MYZL1P9|Aeo0@NlbSEFc8!%4~(lP`}e=x3-%vnHs6a18xrG-j$@+t zw0)mLD@t2BHJam7OXzmLK?LY1cxr|uCjQ!TAm7BOGOP^bOwhkj&wjx`K11KZwg zbtt@sm<;8>G<-xY6QbXIt6U-M#?vvsj8HC;xJAv)*=R*xhEq7mCA2*MeUJo4`jHA> z%;RfcQh;Rwk>+0yL7;wVh}Q!uhU_$5?J3}KUK8cG76P6}|0u5HLulfuR}4+tk40AM zSf}fkP6wq@H-x!twf=}XI(iBAN#t}?gNGKdiq;J={vv^wLvWJQcmyY^t!%z8?c}g! z+SyLa`@bU^N0{*jv74gV3Om_O2VQ)7XfmXxAouE~VilkC;LKjn5wpUBqvoOhccThU z?S1oa>~wk@iz#;Q0tl2Vb47wmo#ekBoiWZ5RNsZQHw?1_%y-W7w|)Z6vAAZ!&U%wx zNLZPz;1|6#&vVp}JA0oF`;>nO5J_F6WXZps{4xiCF_eK~&+fS&1z{|*HDI2zr=Fmg z#F;jTCfP>YBkCBK`4NE$i)o_G(FbH;?xo+XJ zBWqw`S(%BGMeZ_f9NLUf%ci^9r)Eno;t6;XU4CXWMc@g)<%dgFW8n3D2}avi}E zzB~M!?QHZ7>6B}3rTFj#?y~}ZL_Z!)*TCGO54pF*6Jns*vo;`mSV1OU3;<7q#6HOc zI)T_0$WAJ)EEIE{QSd8C<4KQ(^9Iv z%ZYrY=sV56jbVUu*4tS(I;w`9K{Q~Dg@bhgFaJEn#l1v6l1{)M+6ff|juHMpb5>|Ea@G`#X zsHn?7a`B&~?vaM!?VLE#^3t?xyD8=5?f90WtJSW=l3dS3!%AK40IZX2&99{eTc%U? zFg}^04L}wGoFM_EW;*EW@X2YCUI>1II5i3ge;|r&Dt1R2o&soHmd)-PWjvNT1B8Iq zZ7i>wkUjEF>TyQy{Jl~ou-o(slx~vBEfNgrrMjstdAbx5>H|%B`e$|9q|E=CUrXTF!7m}C~_x`E#tIt;# zCVEsxk3Q@Cygc@GF%s5P(ed$yZ42%2f%e?l_OAbB#8TAD>jcFom55(pw28n-jxkxq zwC--xOdI^grHltkNE91hZw(Te*n~C+==OUsS#bOKZqC?Q6BUqeF_hV3#-|W$PVNtN zIMc?7DL!NuJlAc;o~MRLz{8Bzj>b~h_)>I3aF9#kHhGUzWSnJ^8p-z6r5qYp36vvH zWfA3KKOE{-BPkb5mGS%;__s^pj{^rcHOxqsz_9ViqcfoKM_o31Wbtu| zAD(ghEnARBCD-$W=&xLN=EDl<&p^e*0Wj>^Z)!k`z5O? zH&pyaXlNaD@wK3JDnX%}R9Q2FnnddqKhWG%VM#%;EwF5>f;2 zoI+fl#q7vp+6A7Gh=Zz~pJ6UY(IXiW?{tsHZ5MG}t2EyfhDIH3^W~64!$C!QoyCN# zILIs$CIZmjc|h|k_UR`CW}La$V7z@rzxL(2*80-L#IXEMg`>{7Sw11-#Wag@C%@|t zY~SRa*U&qct8*hF$!_EQ-m&Tr0o3wyQoYg-`8+$mZjU-m&ncF*qIPS~OG^XWq%Suu zF)`2_K&GoQgj_Y=Fj?G5krZ8N*t7W9eG`VxrNfr0uF=xWBG^u)YjrNYymn36r5~~U z#eOY(2n>A0_no+o`N6@4h_QAv9K{;_Wn)e9(4Kq^r^dTrsZpv+8rIOX#i-EHDlh)3 zmq#9EvC_z3-=aE%hz^(1B8dGECQQ&KHwhsN7f}J}WkWpL;vYKERxX8_yX7WIP9kI} zBjV6r2MT7tk!_=E1WY|Er$xD)8Iq-`NJ*QoOEcV#fSX3z!#|Hpe1nqk_r>|JW!P;P zO(uzyqZw9=qW|*9zmdw5Ar968iG?I|JtvdS`hqEb!Evo~xyw)1Cd&(VYK3^JKcC86 z``dnW$cKD ztxWwi`tp48^@@Vbh&dmLv0P&-&RZ5*0d%o280H|k4?GaRV+qNm{oQ^CIW1VSwhhKs zqdr~1dbedWm#o}7a?A1|A^Hlz`xe8?n)KNA4a69vBl{g)iWjR9O*JkoX`v)gy$`O* z=lg_0bT5^Y;Q@ghuyJSPLlUZRH~dEpiGNge(cmzv8_M)hnl@CY=rbEmo8kOZ`X?_0 zh>9Ct*ppViN*nZ}7Uu43Yd2q;iNS1mm{;ciT7lVI#nCe$+P=`JcAFQ~%#YJZm3F%) zu`Q+_e;0?uVCcUFmr1BnW45c(i__gGdDXW8bv_#OA|(b1Pm%wIiuJ6^q%i@B|)|YR>R_CIYQ_R;^Hv2DZ`@6ibKU_A}DjVA&F1@oJoo&wtNuGY^k6^Os57jvieJ@JB+)qeZ8oy)EvF+<;R<(tta{MW_%Z5}&kYjN*c!iS;1>3YD8P*OEOyv$=o9ih&+ksfBZ#)|}6;JT9 z1sx`c8h+-{JQC#bQYDcfEA%&ck{?#yGWB)l;=tc`47ngr#Lx#-Z2w8Lg86SSwvNlvw2h7h120`;9ibp*!q^yRDrooC`_FH=MNcqwXPY7MLc`qyQ(W}h z^Z6&pO)p#*KrG!|P!?ixt3@r%1Iy*wBBkzj0U>TXwW85=PdF|2OXnXzBv)fR9l<=A z;vsqb!kS3<9H?Rs&QzP>ne2}7u0owhXZASN7byj#cWh)2L06E{WW$wYfQjeQovf_* zBCPuV64E$DJJP6I>`5qP>japZ(v4n$us=hxwf;D@BIy64>Fnc~-v9sq9&0$c?$p_$ zET#)l%tWq+E1L$1%AYrpQ$s7tKW{5!NUbN3Iid z?f3M(-F|?(DG|GxUzpDfgY zrm#DyhazE8K|Fs3=-ooIvP9rOk0oHe4WFN0hNR1tFL#{=O{5WPs;KrMR^<1dcnW>K z^I_=w2+!Q=YxCdUdqymeu8fCUfWGNr(D&`-VQtqAX2uu|BF{bdn#Ps8%U}T=-d`2D z42FnXS^&<2r&tH>i}uc;M<%aWzlEWM0;L;f#56jg!uh;vDZsnsRV~g?qQOm7+`_Ea<541!@*GowGEU^pbq=;n1AxC*D_fYVdx5xt^-0VtDxyMOn7!^5b}SeFV%T=}MYXSM2*zDN(RIae z6(5grV+aWos@6g?h+%}3Jm7Bqs#vohinx;-58TM5{P%j~nJ)s!)LQx4gg!1=Tf^Pb z3Rh3c?tp9L^7pTz0Ju%*7(;7k(qINumx}X9v%I?D$BvM`!SKu1@9XIN?im~!8aXpK z=6ieESL{GMJv>w$@gm((Xk2IKgFH90xNXGDqnP^h^^Ul?%^2F**2FN$|0llJj+JAn zq2_=qL+H6J3y|#w`8WcsB#AoO9pxbYA+zeSLA00>2?f6AEfC;t3YI!SMdwCnhC<%!jW&nlivx1yHb!)D{eBSzlxy`&$$^&Ww*aD>s* zou#v)zLE0NqTG#N2&D72`xMgd@~~G*?YZuDWlchlJ$1)>)w~|1v>2kh12uvSN$Zs! z|3gJjfdcPhE5(oyK!8yQAYqHL{{=T+-ylr*LbD5SgQ6ljWRY%P)e65iFbKlrl z#@6okwJ7Q6-D%0R?F2}yzKIKd`h%@uhc<4MEFWplT>a=ut&EzF$`gWF$WB=-Aab*! zODA$S!Pc$?^$2ohw}Z3*MN(QEU$M}B8h6428N`~}<>~H&a!FDUB@%HEd8#u;X$-$4xBA`@87f8dl0L}CgtdM_U5_~sdnA}<>zzPIRGgnRN8m2zxsL9O1P(o zUs6jFT0c*Z%tO`jlpxc5K>->bRDCoW|B&@5e{fq6t#>=_##f5SL}#iVZnyZAdKJqB zYuh>G^C5^E#CyfoSGQxROS15qJ@#5kQmPRW#Q0eB1uT3(6Xdf~H>R*)=Ifnm$mjZz z`9m*v=z|-duc<@4aB5?df2%3+B!n8VRPNll*{jf2k6MZwetb4sEKhy znovjH=Iwnb!eF4~lx}J^#VE*_&`=-@W*7RO?yQ=?`5pj>2pk}iW1#o|hZab^35RWO zLsU>Hzv5;r&da+6!Y~*;yi52Qf-y5R)XokRlM9t*C_GNZR4p)LjvYSzR++e>-t!o()B7Y`f8fV)T2yEigCob!Nf6qnW5C?`^5 zD`NN4Lfefp&7-!eQRp?!wqHO1bg92UX#C`Kw5B%#(ByKXPc{zUwyz;+5EKc3IFum& zp^8ID=fd2c)s(0i*Hh+qFjKi z`9~A&`KPsLJzTMnQ6pDlV$H$JPh!w2YG_qCj0!>qwY|DLCf3@=mWEzMoFEAVC9^$Y z0vE@G*?lGpO-16+bprRQ@sZ`vGvbuJ)z@c2BoT98omPI6EcP~bBX?2QnqH~p>Lm*e zWe!??z)I_icSYWKSFHe!4J~SSgS812;(~zb++TDVk7&zlAnSyM{4Tf7rw{#S65Y6o zvd#F<%x#$!WiW>(^eKE1;BW zH^TG-N>jv`BsnQm+KyzLDe7Z-(~uAcL2kLOI;1VR66HVJHF(jQlnrBQADRYgkky^^ zH2|t1%;M=%LM1==+>+D5!4CZ|uSr|QQXQFDcpfa4M;p~3AjR_KwfRn$sCJN)w%|=0 zH<^xSn)f?~A_{hI;1CD%+ty*EF>l#W7>h z&Dd);&im6-5k{tCw&{K`w;T?3gy?x=dZzDWO3WWFRuuGC&tJ2-h=5cl247C6j)euwnKrPGk}2zJ z*1{1X6T$WdGv~6641xZMY)fM9(kAq54Z3YKQ;C^7qUIIWA4*R3&8=Wu*>6=-Xx+PY z8pFyeomh0swU?;*Y8($OC}mVeT@4R^$-TEFNeisDV^^xo&Jm2TYURFU#Op3g!W~PB zwbr85p_#I`Wrrtf;`4ntEk;}?ZF%p!|H(GXV_6mdAc_M{;Y)RQ7@rl$nhZ^nnUPfu ziw^F&ShSVqg*iw{TulKX9AIZiG4&e;8dyxTZN3_Eb%rc|Nq_q4NYu<;_(0h^Iz9Yw z+htkhN~8xMA_|>&zZ<2BzJlWGxa3bQ^)M@-`083be-`!CJTjAX7#`d7Y)_FB$;T$c$WXos!dANu=4_kT2PaHD+d z5GI-mU!)J-+dP|QOgwU1eyjFxJUTaZm&Qj;91ho<;NSDd!+Y1q4mCq}N8u8K*f{V7 zcgKM@#@9hYpgZs%9u9o?@LB%r1kDYTS6|5o7nFvUjU})XzJ24f6Es(5rvXbm9DbobO4?De z`YpR%E1%-bg^@((n22ve2(4f$bZYn5X-NEEeC0{GqbBb8-@Xxd7M8!~+lU12dvbuR zNpKL*dSDFlfm5%9Gh=<+7IPUv$>6OqfMvSCNnq1#eKfCH!Na%BU%q!cG7ttLFgTN_ z96YJNWIf_wdTIB?w^{!vpTRczEbX~LkuFNr+WJXN;1<@OY63Bj2xU3 zYgviBcNfWdvnV(xOu`Wm7-MTcZeW2_Hx9XJ`AE&6fKS<<2ZV$Ci)0>?MTnV7H?ySy zE`Sg_bz}b{FBux^`FODF7P-LNX*$fax$Z)g_EmX|yT5P2!h)nOIH&86mWqnSvGDA1 ziXVG^bmc|#Q1-tQ)u`~Trd&gs6ss9Tk=C|<;dzyRq=@J?L0d zJB)0W0laoIUVu&z>bw#HiE;ziqf-JYQN~%@y}u+Vk|oDJuB_}a_HxkndQwikV`MDH zil{!lvALy)xnslPj2k>eY@C`;_#eyOmS>}Lr}Q67Ts}*_m$_8CN5=3_M+fQ>70j!m z<|GyIQPahq%5&50)pJu$k&H(ba!GISj?pDPhBBy=9wTmkQD+?ZJf0QH)(|8JU!sPlcNiXhoQUYq50S72oY%Ga%1-eNoU*!_gwRC# zo!~I{<+I8;v+AJ__k#BIfr>=;c1x04E!7M+-8215CYXpg`R_fKm%i@zG}s9DXktu@ z(fD}eBOi2#H60xT9;#&glJq{mfuLwwhY_fX0_5YEz$dx!hA4;j-Hp z<={a<_Piens9t#RWj7k(<+^2~efr<<&GM=|Yv{@dtTnj$rL?uoIxbRmv;QuF06f>$ z`jqW<6d6Oji@+r4!p!G7Z(Bncl%eV-r8GcXi`BL%nCKv+V;}#C*J?9;&);jYg1nii zik$iSOQy_dew4J>vy3)8Rv{&vdwJFR`^rjB_x5Id#YIX$e1}Ox;n~u`wDJ7$4#^fA z_gv-DEX;yCAxdTbh*pF=i{|1&aWMTp9)4bU>TI^r zU!6ktp90zJCL2v6Dx~b48d?2@E{n}6>8kQ9NPUssrgl@qU3e$}qjRypVz;)mREv6k zd-F?$=7VPtJ7tUJqplJq4NOx49zU*WPuz8z{d2xv3=SqoaNPBBfDa6?OZXmvxQe!B(Kz^6njy{%VFTa{ zwl`c{6gW6)*|G`)3Meki3k)9`HYRLKZ3vR4_Qauj3<}0Y!IhDVup)gA>WH++$>E{Q z)vSt(o%bK+8Ts6vnwy-g{gHiM4re>bidA6+7e2Ge?c~ytxKFZ*JqTfHJIM}yO}zZv zAwmp+`T_fIAO%Rt`ToIW<(+a{7&QcAaP}ktk5+L-7Kf{)a(-20ee_Dsr(l>sI2-KF zrHeRTR2o}8+Mws^^RtnQgLyya&a%z=CGE`OqOPr}TH%wjtPOvR?3T4|VXG1J#giyu zc!zTtE%u(ihMLZ+ngm4Q2~&N@RG36y)&V!C$~VW|AUKrbB6aJO_~rTM@kQsV7Y4tw z&%E_qmW$eW?X{-PbZGTTh4c=@nZR(mABUlv0=m9BpnDt|B`>Noo~ z_MJ;7@wU_)t-}8JbMfNR?AM0{z=FQD*JAa*&v$fPxBhq}+xH(T-A+dMtIcBMi?jJD z{(sM2w5y3r$4MSNjO*2@Q)j*o%XMdFc_`PFXl&d45&zC#*1`%IV{N>23*h74*#Axk zcWBGvk`x|2EwL6Fh;0)H7dUL$simIbp6T<~dNrSHe&6YE$(Ee}shF7NmTRj^5Kv=b zp4kTOnd!y;rP1ZOLu!zl8Q=0jSW$6a%e*?uLMpv;Ct#)ZDf7snuXup-qKi)vkWO!8 zYl7`w`<0zbbc?(!$V-s_{Bw+9;#DYdwqsb$;S4}T|UoEn8okS#BRU(=9uhN>B^_v{;1;C%Tb|nZ)fARmM6ojcJB)MVg1uv zt}Yh?qVA`qIYhPJ8@*Cv!T=i;jJv5C{hv3O6)DMr@c8*uRe|&BkM^o1ATO?k zm$tNkvaf3xoSzcZnMHq=ZRnBu4~_)+rowvs=y>_L5O)L%)>ABwpxd*Z<9%huZGFvs z*z>?)Cecm(Qst?owHJ5+>^kg|upHfBhw#7`}?HE8%Xu;MR}#O9RAd(^JE^$y>kdWmI3C z4|H`I;M-GzT)R4k?-}^D84dMTJdI!nn;TvDJSHx)T>Sy=tccmYk;}Pkq=+d_)7?dE zAKDPjcY9yT7cxD0EC2d>e6|v{bP>P*k)`wsVYIsDl|9|7RttJE28Uxd$g#D9&@a>( zzFtm~p~4|;(zoLq*$gH-qJKZoqAO;)+<-6Z$>S;AppCo^;q+*bS%pL0xEK1BK8dDR zY#P7|qkbXJIOdYA%>AGm430+Qp4ey5>gqk}T-xV8VoeiP>4S*(dD5>#kgM#uiO2wF zy-W6rK0;npl-ODxm%JoTR3v};!P>A*!&dFAXx&|mLpZ^X62)y;#9vMxu8kc)U4&Gg6@1DilI}ab%bUCcd$Lpos&xTmrGmKH0MpHLUPN0Y8u z^p{paptIa$b8dSIedg-zF%OP_vDbj7h*;E2ZuDn}c7|o@R(uKewU$9!#i7Wlm%ru7 zSilymAOS?#D??)F6!=avfVrf zr)?G6!h2p}ncn8-zUj!`px3$w)X5lQ;MROD)ZgnF{vEbpnPFzjbBj@{3$1saY+q{x zdWegHjB_uaua4epY1CRR9LYYB)DxycG|r_R&{;F#tbH$RmQjO6E;W|X;}$?b{rwtb z92~SP4b<6L4}wl_L~%b-T2l?&-JwivgXsBk8T}l49EwZzJlG5>#0Jg9sx?}GAd%rZ zZAi1Uuvnh!80q@HGJX_eJnk7Dcre}JVx{}mpjX@B^(Lg~#c*@C*Rb(Qb#RjC;p8?T zDu_H@hbD@najejgYYR?tpoJVkPq|nuj-KpZ3qb+FG{Sv8bp(T#h{Mq7z<9|R)SX7_49p8Ao}8;XPV6_DUjgTq(Qh(%G4i}Y!lyvDl zrrQ~6e~zgF4DN0RK57gWA-1r0N+Q_JvoE- z($$Lfut}z~lG7uV-`-Z}I6G6+T-1sABs)6}WU3ZsnXWfPxFZ6)?Ti>TUw3EQ*)9l! zw97fAdlP|@N)o5yaD0K}`bb3dzJ|X|nMdkD=g)$1d)C1pA;~y20kXdzmlC|$MH7db zThf9zs+o{9NshzkK2Nj*znN~=|>KU!L?6U%f0xMP?a}$67Ix&SFafvoh zG`561d6)~90r@+wLDgoSLTBGLW*5DM70a+zMbWJ2GBk9KD;IyvI?k&ZPoWpSR^w2; z9~?LOc%r~!xqkMS>Xp$e2XPclE$Fl69PfW>lw$g=qafov z)!KrAf8uX^(`-$t?|W zb7`RX?7k+J?hoi^iv1k~D0c)h1-Do?i$idWJCg}m?relyP4%0wJ4XlN2rI_iBr;gA z=!l7hb_`0UVb#GFFidX^6;;u-vQ+TJ*O-9TxjA%bS|Y)jAX+q4wPtvE<2eO;oK)JK zoW#&KK-TK@nQxtf9{_-{tAG0&WqL5M$1yuO>(l`-7?H)5rShum1jw=NUtLxgKw88oCKU(lmlnCyrdD5-cL@Q2-*Fyrs zm9pd_eyfGA{UJ<_ zTIe&j=#vXDL8t?vT!BH-g&s(upeIIjV^DRc{d{c%2JVRQT{MHZ@K(n;>NEuc?9Moi zy#0k^f-BiVc)VOO!Hb&D$&@~Ly6Gj`)IO!so@elc)=XF3`GS2y@6RmLTt!p+J%HD7 zjcXD33bm3GM8q1cIT?2Ys`vCA$O-|j8 z#<_6}a53tJj14YAI(!tw#3}~!MV6NGa_sXpaUX1oRwpO3;~hRkER2=)lOF^LyI?Dn zU^u?Sd2F8J}Sdt=g3bqBGO2Ndrv zFteUcR_1-#jYVn?&}g;|+jOvMv`M{~1mJd}5iY3FuJ-O|J~=_qk}7Bf(n>a&D9a4~ zoPb!ESuA~$c>DAV9VQ|?obvV}(xSTO6;YQD_RG}|z4uC1-gqPY&0E2`*!m+NP^?cL z4Q)Sklc&JBk(f}pMGdD&^>DMBL%Mm8g4E3Q@!iUAxWCw)`|B*~(Uq+UBC&08eaT~ikLkUJ!mel@J?1ta~!GrJT1Jl*df@n zd`*kG^eJ1~<07iuFDnw9;m7`*Mc}Fx-SMiBo|`s(Xj~W4d5;}ilR)J#DwEjwQRkjG zg&4GIrId}Aht^CCmmbiFzRK6&f^V5eH^M7~Yq~&>%M38K+>qS(Q z*iC=wACkuw?ik*sQTf$!Wy~ejJf(x)k}aA&dwtIstCsquliM;s_i278O8N2Y2X|>k z^ja4-qT`z~KH)Ud8|2FIkT=Bo7S@n_?4TdUDmIiye*ab+a4z!uNaOyfrKvlspT@+Q zqT2~AG|ZD3o+$9(-t1qBY_2x0INfPag%XCuP}arJ47KlmNh_w?{>5zezWv~&^F(@0 z6&P@)=NUB(i7NZDpMi&oTU)pPOZ_YE%1Janv@nJwCN-;jPC8l~#eP+OmTnLdvUSb=D< z_jEHrK;%__CB4Sr%mAub?>YaYa|Z%J3nnDaJtaH|5nML3T6%?8Ph#X&*L?uU9+8AJ zY(zmnj@>RlaQtb9?{dLvZdCCezY!Pw(0xIkz;>XJ`S4SVk8j(zk+%YJMi87r!u;LM zMH4Ba|J6cJK;JJt&yz0RhFmGs**(9w7}ft)%QNt7F+l;4y}S$ zHsJ%|a*G@c!q+OehLE(mFv24JN$CS)ZT+6xR9hmJU5+YXocC$nrC?SQNKVbsL(~{~ zt^5bUNDZ8FntIJ##Xt`p1D8~o(h%|P8WYfHY5PV5W7!?{R-14HVm_@*QAS9viddao zSnhzw=smYD;_5!7ux9AXR6Mz7u3$ZeF`y5XD z8E7-d7W>@xh#vGPp4*ectl-?!Yp&8CnvM_xb#3phfK!{jgPKqKJYXatjKepqn<>Q? z-CiFhf)(r82s|qfyi;h0n&=+wL(_t1f}u3tpk~nN2?KXg6SIO{B===6ZigNZrMp#?@I()#IhPfEu2(NTbT z#i!E9VL51=ZhMY^e((6xU6f=5M^8B$NNLr>aUHsn=^CJSZ8!pQ>jouD8PcoU@EQ3!a$ctFbH5B#y6AU`?wX~y4NX_>bDEZY z7UB4cz(`4}-xdpl9Oz01en~me(IyYgcnjNA`wdZ{tR>hN(bxL2yQe&m45ARfw$0x6 zN|<4k9&FIc)KJ-zZvk-Qsme&HLQjF9uibUroLEdhZ|5@-F&05b=aV#_|IjUtn87jD zTVy)I&2rIVynUp6c1WZ;xjYhoAvdc}qlP}l1DuBf7N3e+v|vc-sf)(mC0$nT7Nmxa zUb6pH#wKXgAbvc38G`!+SiI_l1mtDWF-_7Wbyu+(+_tH9O~QN7cj8$@|-) z%Jj_BIDM_-0yvaOXq>eSLp`zB_8yPfT$b?{p(PSb%!81zoxYEd7HLpLAY zye*oF`*rMrp1WL7?>&_m1;-xN|L`q;$NWl}nMtW$n03iKxcGEnxufIrJD>HSKq3nn z5vJ!e2;p;6Qt@KusXe1PDdM;1nH0oid)^jTr;nJerUBoMPp3`bblXtw#$06@>Xqm zJ9~a^kK0LwOTsj7`_9GR5ug?tB4KU2D#{wDhRSgi0WgCDTY$ENocXSlU}Fc4lCCs7 z(cQMYuQ8vi0aX+OB5dTI?ATb0M$ieo!xlnzL7w z))C^<%cE6DEgF<#Z6`#}u17}t*_kDmzT}S;_PWtW8IlPV=78ck=&#)WA4YhBjNg{ilG3{RIh4CLLb?9^+BuPi;F4zqPBRJ{ZFq9 z*<405#tN_FX4ep1PvKx@otx=(@n#3%Ex<8#D>U;6&96t`N>o+D zU+BjCD?lCJn9vtCsZ+v;^Qu>(HhZ@{2g zURG4!lBYCpH*MTWG2{iWvr-SC+4o94)TuHsfAYMkM$oNoJ8E}E#;aL4N;SMt;WOsV zVdN#P380OJ&?n%Do;4!$s z#G^=pL`xlj#cPrPh7spA$=Y4_5=GTO)&|@^Ho{?t&lo(w6)cN3PxWFzg2UL$#%E^9t#s_y|YL7qEM^rcB>&y09ZxWj~ z1NhvaN!5QBe|O)f^LR%2Qh#WUJPl5AXItT>eInkMCPHjI_Vd)#pL}Rw%7LdPj5xDr zW9@rbN?nuwDLuDeIFyFAvQO?IKC$=iFD^}B87Qy_vXHYElbQ%kI6~-5gX&$k{l&BO zHSsE1aNSdc154HLrH63lO3X3!8w8Q!s|yCkzp0NVaJJ+f**;qCi;H(%S0P=O#b@t! z$deXL;B{V^kek&`Z6u2$TnE$I+nq#$k}i3Yj6#j@3;$wXQWIm}k>3`drG)ONF#(dG zAxpmZ0uBd!NFrBGL&yLyTIaLt;Z;jN7M9^FhZe^-k9>~z6vE06-K4v^2Y`bWY?X+2 ze@Y+0Q#c0cRVowxxVdk+d&ein5sqSL9aRYUO(_g?lE&p9n}#snbMi^wIsuyUYBnJ$!nEIY=wU= zG+}am0?%kX=3^)9+GIz%{V40i%AynGH*H8UI^yeC`o-kiwE`}!X^(51Vhp#8&(;0; zcwn***{+AeI{_ssS^ovvRadm9SxD>Qq3*K){zO#NK&!&i@Z(0(*>wu=gell^*a+5z zfI`dTjfw7<*jgJ+EPk{Fe<5M6sgUk~xs0dIBj-?@Z7)t??E7Zt=a!bnm*b^cTO+T2 zNO7`Q9k^BC*Ve@Ap}7h!+b<2SyS^QzUTCfQD+9(QVuAA0TrS_ftJY9)MFx!;pt1l< z3qz$+MGQ0f6bw#^PeIY%YVS-IOsT2Vf=Y+YuC6z!m~m!gmwQC z|1x|%^fb>P7F(Q=0YS0TBl}}3fi$rYcz|xwBM#a2L>d{j`u0IYRKWv0_r5yP%R;f$ z6KG9sR1A~z-2EU~)~1T>TNg5scfRfI&Y7d?xXWcBH9UF>-PJ^qe3I|#-KIC@-2!=@ za>&VrPcs#Liz)p}o7f$&QCaM_G<)gpn9hE>H_1TzGpA=kU9pCS;C~+$-3pu4M}|6l zwc=mwSuXj(t%Wt0N?lTFAt0nG2k&_lBX`j~VFeGL?kzS6Ttnx>NtUb(Qz8sB9Hhg) z5fxa)e~l$5s^f3US|cxwo~hR+AS6}-uhq)uT^a_u6GlwZzhQFtU08%xdKB==yq+*Q zD{Y;%fl9MUZR|56AG;s)ZM&MS>;|kdxYZuBeJ|Pu4>!u$F(c2tQOV{TN9Byz=bg>fEPR zt<1j4)F4hR3{a;|_>^?DjY#INELdjj;o(|HuEJ($9!okG)vd`0bEeC2$e0Y)S?#+t z4zeIX3eEgJ{sAlrchUA-pQQit4sR#-r0#On>wXT*T*|t&3HW#61Z88YwM?No_^w}b z%^N;QK?7=ax>c{U8>67A))NK>?H(Q%m5ZK(qsiK{8ADc0#VNYWX#f(CPOd^FshJ?t z4MG}3o5dpF3%7PNX^~xdJ(L-7Q3I{Gf5Axsl94K#29ujVLJN^^n$fewp5{f3g$u zQY}bv%}81*`l$@`3}Exrdb(SLXSm9|S@<4xcisLDKQj zFW&SQ8^~XHvLo)%pD2yV#wcmMtjZ1H(HwHpv)8X%9!l-frpHUewFNuZznNwmF@UXT zdcI8d)tUW*o&8LJl9ek?*YWhkKQe>n*Q;Jj9kXpE+$GGU{k{YF`O+LlbsAvLl3r z{LLS`{`A)dlD?kRIP1q~$9%~|kU0N|U9vihL)#IeF5YJcOrCpRiW_H&8&6)+QLm|* zkQ^hDlWk8N{f%SG^}qY~3GK3o%nq$g&&aFNE0Wo97Kh(}zkD#=kNsleW(pmqIl}fK zIr~M(L#`PSE>F&m!Ju3we6bk#1(93u&Dg^=&E**~Khl04tH%hQ<^CN%?aS6H;%{v` zzoY2=4CpR#_^J`p3Tu1*W-{kMMvx5H0}r0M$$%@}%}~7LSPY>F$a`gr`By%k;rX|l z>Y6$#Ug{Ti^SS6pe8N~z8&mdX79ZKl3*Pp8!adYQDVcA_%_z1f^8h5+fvp>7iU-r4 z=e{k^K)Ta!P_;gABtqu4WltloN2 zRZf}Y-@y!hb34{Iw9$HpWc-nMtb6$R7P*jKfAP&&WWHV@Qe88~1_Z8n@Dr2%AXq^l z5RiRUU!rdQcl_|pMZh;tw5a*>QOZ_)x_Qrd26AKRpYy?6wQW>k2J)h4%Z{QghlCwM@t9CN zuRy*DYajyZ>J#TJ4XxTT!&iGVB*hX*aadbMkT8Jz@%FnN!8?-2Nq;ETXe4LxPw1-I zru9f>>6wVwU#>&T*)0^6r}2W5<35kf{1)iibDveWi33J5$IG$q%}{`N_R6ULN*G z8QI>4_@TA>If}nIMKt~LY~RYKGSM}qLN;CB zp_5}DtOM;13rQ)8oVA~@TzSKkA?POIcXFM%*(2!x4n$`W3%t(}UtVs+n?6j#J@)K$3l>P-YLN$tN33FfzY$qoB;G&Tw^3^J}@ zI(%N5J0toQGLVt}7eMprA$2#bSwLjO@^;kaGC76=mJgSN!Vv@cDm6j5eJM zDVs06xYOx<HU0CK1}(CHtWOr_8tIy zRe4C6{j(t_KS+B}Rwve}Cfx8>NBz|ESFGx#9l{Ojs4?V1qt_^2>CG_Bqic1=rGNa> zrb>nc--zIT3w^Ew;)CzVyGE_3)p2RHI3p7u^DFle>aPDG-^MSwPq(Jj8vT0ubYc

    $O-;g`fYe9~v|V?KXYuM?Mm`s%82dH-i{|12^qsjeIGVChOUfu0yr zayTw2yWswtc1FiNDwZTs8-%8Mp48UDfB7}Mg!5BQkQq6#81Dshs(*b53Vx8QA^Zgl0#3;O{3aszWa3}eWZsWf`xkWHVN(Rb8#=3+2duG#YR-4 z)|s<{&qauYOmc7qUqgy;0<<6~C*#vcxx}gZ2ZPPD$@wYK%_gKE=5Omr_^a^ZfTC9%+!h<-0ULlRG21Y)(P=$_ODQ#Q`9N zr6)Ha`opKRCW#R}b~Wd{6{B>mQajHr<+sW$1}s1#2t@?PfvZtK;x>D?BQ){6#%O&wpS)+<)2WgZGtKln}%h4_YvSJjBe z`Fz^wZc&NtG|m;{K{9%-7Ogssw63Ou8NK+Dte>C^O(7T|4-6cX8| z<|$+A9PhSRX03-!9wpZ&A~&A)^C@v?xc;P`KuK-hz&$X!sy^wYbdHek11 zrY%%^|Aj>O}%f&X)+4$ss(af0d@yu(WtVE$D zqjRHe^S$(9-Z(iqsU9sP@QzBOf$2dT@a&mrrr=#I@U=8p2-qSs2!DL`UtR;XZ9SEu z?`f1?h5&ukqTlw+M!J-xzfT;h`;CR!$ySKo2Aed>6SsD{vl9gw9lZjQ1AN|b?P5{0 z=^f5ex(Ty-7V=)g`5i?e#sgrh zGIR^|=!Z$OO=Fy-*#eGNnwxJe|DHfGL!L(YLmAoH%(kRbp{eIv9~1xZ25u)f2dozh zg<(C{sZCD~51Yrwn}7d;qM#ztJ23DMxhSKP=cti1=I1Bn%2!cpp|@O^%<0IKh@!W& z-qYx7yYz4}+>>a0V8O=Ba=PanFp3R47)Wq>wq;$*N{sHcu&)(T`}n=w$lh>(RTE)w z$u4??mUN^CRi=1)s_1*R%;u^4d%}m#;MFrpi=0IBw8ok#r;T)M6n&qCf`t@T-hKG< zKiGvV?VXTCyUr6(z$NWmVhoGF3SlNj469mc^}9|;Il$`JCx-@G>dd8$|hL>Xm(BB|@M1hPWmg0RhL1J79dE6&S*lE)N zlM-tdpYk%6I-2{D!pf1Kf0++#;lkPc@x4`v^r|Vl@*Q3tr)2N83}SqZ)hsrIX&adI zX?eim8pORp<{Q674A42)dd0SqIcdVV90XG-Vp!D^Hj$k^W~2zx1A+oPEpK=@UZg+s zmiB+mY=<1-`tKM)(<4aqufBb+Y?1+YmNG3YIJjhEY>MB~iGz?@C>Iau;kJn;-5KAW zZT{^tj=R|fQ7__{bx%lVQ&dpcI66H({<>O&_gmGQ@ARc}L7^cCdkB-zONi~unmYgE znsQ&A9YwMiJWST$jC`1en913M+-68Rxo9H+Cp@=bF!#^$<>O_E+5dzE-$T81VOU7~ zgh6^>VnM^_uBQ;jKZ(bX;e_aN`U z5-^es)Ok);a}ot=Ca;1oA|fd-8TI*$NIAYz?;dYF@SXOZZ+`l!nLXYS(}xnrgj71p zWqR$5>lgsqKv1N8tW{NP^h@Huc@W$OIeI1N1a}-nY{N-Hp_2aB-=gphF+JUktZfs_ z`8|Agwrv3~oSv$gFqDuSycKhtY2~ z6a&0B*DI$UxMRDcqNLj8V>atge$`j9qFw2}`<1V~(~hEXO|B)jf7pujdP_)>7ZLkY zDo8)n5^+zfH#gdUl$bzAyY=c%!uy7|`h9GJeS^0|scK)px$Pk%lWOGigdWKei^c&xE*_u^KMVMw-95P$@Rg? zElb7E6U{Ywp4{gBPFqbTqK?o|$vSiHy50hRA-RD!JFj z;r&G$f%*3OpF?@-u(7}zqfk}8)n z{r1+>8~2ZAWWr)MSkg>Q%^F~dWj!iXKg1sX+jRshD{q?jPBdfMp|rI0O%fKHZOF6( z*|{~wgCuzs1scn%yThoYm-%{``4>MZk4o}-#iV&3&efy~*9`H!q3YX+e!M>(-Y734 zFSWIFJbWb|CouE87IR_VuH5v~ed*c&e-B3+e^3%F4(BmC{dw+R9yym=Fxt*#Bkc3PBEBFC3;`FdG(_7;vrl^?f(0 zzu{oFREY9T!0A9jB4tUKYxd;{&tbS2m#n8+jWw$hT*^%(-ylZ1|2UUSde#_tc6JE- zo#o2LBXr~O@y^*i+i~`wToF(CyHuf^5M#N8ZH7$6dN&+v-H-0E&HGV4Hd!}FTt?sQ zIEg-VUxudBXjwh#5_hS~mTUdg#^J@5`BJ~de{;u1uKnoVTN+=^>|frQAN0j!iM3jd zRr~T^g-DXPL<4e;R>o=u9T<$LAk)AN7du2mr&&iFgqKCdwhG?CyICjyB|>QW6Tqs& zw}kG_$eKAd86f z<$QKM7Qx4RY+3E??s>R056Qq-MOg(?q2;d#cF4o@=ie~zu|`Hm^Anf-GVinuGco*u z3?d;nG>DzEXyR1`ebB)q=>W*^V0x(4WsPX<8$B7fjeZ=N(4-vs3ggj_$s>1i1e zKbc+$_u*?`gPjG10qnp)2i_{Ed2tWg9(WY63&D@8xFwrmwuRu{B~F9HFQ^LeljW%R zLWTf6{(}g&BDu*$CtSaHd!J1Krh9v4Dt){zioWMl;sDmG)@&Nbjn0D&n=vLgFOpW9 z$^LD&nzrH9cAjO9P->f;&kQzeHA2QBWl>R4kfY7W71Xea^;gIgrjN2X{WITYy}jMR zW?^QQJCx_Nt$5mhR>TG3f;t{(b+%IDT1!99(c=@pW1$n`A%yW+B%ZneGd2XHg&XXG z#DQxwQiEBCOmRH8QzxR4^Y|(>ccn`IYG_tng;zFdi#QdpH%NX$s6=-Mq-3OY?KXCZ<9#cLCIQ+`T#m#U28(AW4~* zAu$>C@So1i%+!|5C8|f^)36bm=vbmjP-H^bA3 z|GK@!(a7j@z1wF8ok{VW#3eJdfta_}%8X@oaz7y0gQW8EBFjp8!LmaDgUX7hR7$XZ zsz`Kob1O414F|%|s7cvrV8cv~QPS0V${iDD)kjOC8vvV{D!Clb870y60dXZZs~{k9 zHqx?b>nB}v7=^C97*Q30{C1~G_g5lHou40wzYxW}&@jXnVx|W-8xB%?BD|AuT@N41 z=eGB^K#183CRYo_PhuHnru7Q7higU74L;kj7|yGy@JaTdYqz9tM!@_MzC$Vwc&PBh zwK8f##%q?Se1OZ=Kv@Ty|JK@!3srf^sC_o_?9JH>Zb{ef1&^+H`kmrcrSC!PIrO@O z5eDqdoEj2jY9C(^6a=^I%&15qBk8ZS61gi8TEDd`=D(p&!269!3O%fA8_La|CsZze zUT`Be=$w!$JM{(XmqA|4e5zE50cCe|ZLNfel$5fbe;oZhPFb&Phmi_;Z-)$`;AWQW zK0gCtOyV-PzLS-H4z&yl@$LZd+}rdLv4zwlYGoa=Jh=?*jqrF<5_Io!@;4U_62k#n z0YE=J5|;hJ_=$+YZoRUzTyp?fC8w;LAYt~M2f;#|ae>Lb(<+o)t9Mm*CA`a;)bYGF zCC(%+K0UDccA$IqOg!msB1RQ$KA{M@2UcRpX>4@=}OxqqFWk$QrsLRUj@BFE(X zTY9xQ6yk_R~TkrJP_Nd!sdF$7{U3tL4-Y0Y(*sNW??$4i`v|w2p zZTvhur6@2Vi|&EdO2N(P3hDhNr6Wm|nAf?L%gg#%b}sTVW6pQoXATZ_-KCt1#rw_d zF#-Oy6FodTnn*K>Y6oE>Bl7L7UsX+0bv`?*(?{hHX96s@Hi+DKrdz~<#d<*}Rb%f%L8(Q=l=@u3+1j#aX-(jiHBw8dfxD?c)@oI)8xG=QG{vvOjc+sCp zs+I&>J;j4x3A@ja4trBNAbFIbY)qFop{s7SCU)UA?aap3T45i}jB@S)cPJ^AQ}uNE z>{zc6Y*0SZ>7MBjpuVoNjM_V1UnO5>S$jz>q^CzoFPHV%yB=k>i#d2Co7pFIatL%Z z(T7?;+Gy4e{~RAn>7mvK=6P+=7i^SwcXtgHKjkOL-mUGr+RoR7y{pC1mPo6{%;Zg) z4N9(N>luKBYBIy-BJMTfNhpnGG@zRQ*K;7eIy7k2;P{?H;*WR&#)!ah?s!Jc@4l*& zqT*BFc0p)H^J#E0WeeJ3U1bBkAvtF@Bs=7!&0*r3=uZt|YM2`ibz<#{MMXlD3=BL< z%jr3&cGu?qKmuyu;Q<4zM~TJldvx64426Bwf9=GK9AT3df|Hwogw|d2Vvps;Uffc5 zem`sA{@<>adD7bM^zodxiO{Vqq)C!zU*wEVjCzll7jYow6;RFAw`U3CSf*faAM;3{ z&aTz|RPJ=>=UXc)Tkp3GIgkAo8R-^(uhtSqqjJxc`B@@%o1MKSbk+g18V6y$2(~b2D7xN|G9Dc5Cx;wlUq`u_6!HWVB={|rh1=+mCR4I$nwdya1dHR6#DqI~;e zT?x&>r?6A?LfRhh3HF%~0ys{9_&c843aJ%({amZy5>m2M?@8VW4S7r-D?|;YoOsc<;B8 zt3t{YS+Lq$1MBFW6>cDWzt^`<*O|zB3hHls20&w%>_dlZoGQP=dqpT5rOlkflbrh+ z0!|O}GXr=3^sd-poGVl`zO3F5u6}yCNg&50%s{IcehIR5nM60Kt(eg?0qPr*03jXE zrplD}JKXn{LZ_#vhg%k5R>Mha6;IdMZZ8Q*u78Uv_|lY2TN5hB~3Y%b7K^Z&E} z%`6|d^N^hcQ8XOQQ2>15K|GttGHdF^3REZ|OsSQWh@Pnv=ML4GU^D24SKKSn0xSap z-$OU~BFLT~++x`|eDp58y@0U4@!6x!hEG4tIg3y!tZ;54SX2ZN%DiDvaBaBW@!`EJ z1gElUG?Iqmm+9|`31f!IV9HO3kH|0$#pqz zou6_(T%QoA7-UkOr(~pH;`@;zkw{4DeuC=-{{%iozbE)N3C94K-a6EEu0t*grE`Iw6@VFHSWlR3YWh*ziLYp)|ZkqbDyo(d_ zRN9eOVP^9rz42(=;&jf^cKPqxqR7Yeo|=*0%neX#@iM@oPQHTW$5qkD^AgJ zx*_&m@OCRt0`Kx@CAxR9*HMV|*6^RLeLjhm^#fhIeBFppJ=!DrNr#Hw9F>vYww1y8 zY^j&4>n^qC>jLx%;|@0$(A`C9&;5?Kj-PwfoAV#8+m%PG%x-5B>__P}9-JnGM~$oA z*Awm=J)!2^K~=Y0e8Cq<5p@0%wNhtiklcNi_!qJ_jJN__s*dd&_sA-Y%+MsG(!x_g zgHaxh@s+T;OX=e^8_fxL(A+a~?fxb*2+cH0KJ59qI_v9yRaR2F+!cI$11iQ#meyPC z-0OoZ3w0T3;jTBKKE!aL9x}LYGdRyNDU* zt!IF2R^#4g^;$-9#WPmJi30eV&Yu6Z7|>3s(sJSPppYPT?mf*$3X?kHGw#ToT6l3IWGk`@dXlzodCO>Y)BmzsNBun#!sLpg`~7 zc<4pb@)0XWyW(#W_X4;7toJwW{|203bpsYj!bl_Veu%t=I~vybku>-TS1chrO_0W< zco4X-`E@_1FU}1NoPxH26&9E>llGX3L@^2s;NgJOYrr`!aiI%-EnWoDaqG`ClQ)-5 z@rv;8kHo~q8D7P@O*w^ug0j+30=5B&p7Ib8wa7L)d&pc-XY8*5R(;zUMYKcpE3i~qdS;Zzbim*5}gbW^3Kmd^g znh2e#ik0mU(&@8>5ULD?aSS%aQ#YF4hDcux{#8ZmBEQK6`|wp$TpiV-`r5qnc|+RA z{tk~g?*(eCf3>NUF7ygil$4!{g)Qv$G-fA*5%!(+9P0 z34%6ejGhoF&9NZ3v&jEzs<>xw#*5HG@li)eeD}q_djIa<@sNfzJ`yE^KA&1_UZOG* zfUS%)o3TSI$K>EJ!%M-Te^%3iindS5Pln^RYW2NL@DqvOw*j;-J1!(%=Ee0;5egM# z=so+B{dp=jd2dS;Sa?8rURhbm%L}OppVsqs4w&In+<<5ebRhl@c+IzJGZylw?aHt1!;aF$!%R9;5B&uGP`S@P!2pvt?m+(fWZocmfI|+*HbRt{aX-qvkR$Gae1Qh4}jzn z=&OU~E;sRFvG)E}7l>fI_tsWgLaoK-M7$dp`4dQ#E`Pl7 zskBlhGqnW0@$<6mCX&fTlpy$bC%0etrJMfmeWvybRw;^GC5-Uk| zQZwIs%P>s)VK#kNN}zL;pHkON1gA zDpXjt()upFc!_xWpwz$9?6*idfooMt^Z7buVy{ENy1CyZ+2q3};F(7kp&K@@7pLp- z4j%Y9ccfl4poqF^M@&X2Ymw2AuEVqb?Y7nfs+N`YN{fJVQOlK;fyeo0(V{1PnnKMIs$UY6p&y@X=$3Tm zD!mfTX
    %*m^}(>xH;meVb}bLYt!=4`3)sN-ylDsWjkaCPbMFGJ)0ONR;FJhlL6 zWM?ev$4?h5j*Z1rQg8XcyT^{`=y=nxKNqDWCo_re&oAV>QhZ+?2T$06!#$`~U z%GBSmnqi$9kN3dHqILG4{IIXD&$_{_eyUDh_Dg48WDW&? zr=rhaZ(Aw0uv_hw3`v!%=#a&~Pn<2P3-60VyJAv&n9z+*&VHO(NHNtB2-kt9t; zw+QU+$z5;UK{tM3IqXI4{M{ZLwsQ-3R_3W_TznDZdDwSHI+EUwX)EULA05y|&ht5o|~&NuON?ZZE9l`z>w_ur*}ToZLtQt5mn5%X)# z+8G{E<2kj)X4A$x3@7@gM4xNw8>(46S=ZKC6`%WiEYklH`^+}N*($Se8IQSP?E&VDSTWrv!Q;jk$~|d|3W#5zeRVYTUii&?kue z3&n~O#B%YdFdXy*>^~vQ=JwrD3DR(1h(Gi5_H(altW4`qmCCc^AfmG?KBWYqxOo^e z)Tk;h{$*1;5A{pJLe34Rdk6gxw$Qs;S#2N@FBD9v#1$ z$o<;2)REj*uC{~f4J#{)g3rE7pqJ*?P3abJg7pZ5T3TLCVfuxTDJ(?rO~w^M4`)e# zSIZGY-Xp6GjVgmt(O_A(QK_CqV}QS>&zJGN+b#pZEYiPmCA{FDmY!j}ux7~66)W{Wk704UhJWI<|mq)LV6h5w*T zdr*38iifALdiDA1qOiI&c!v)~udKft(20P;8=cr{;?@UOJ4rd+X8f!{oFZ46hy>xO z4)JGe0uvQj2Ptq_GMbs0#ijKx>kh)`;9C2Buk^G)lJ>^B5CL*i1D}=6v_ak2N`ruo z2!emB5?*V^OBzi4 z(BUwLOcJ)ZuMWfFiq)DSDHJ`tnb??MZ;uC=VlbFAQnKcs5*IWz8CO^}VK59-I!=V= z8*a5YHQHvpy{H*`)F7;)n0}`_*0yZCgH2(z1~s;qV-2jRJ3M7wIqNk-ZB258j+i`4 zK(jwWD{DnA_({DUm`vX~@M{paXjSsc)T@C`<-oxX1uft7r%Ft5NLG4Ku#0B9cbSP| zpxdAEB;nIP3>I~MZZ#8oC;A{o9eq0)&e-)+!mRk<&VOx?HoqbGQU+e6`1I;V=)O`X zm76}A0X?sRtb)A5gm-`^lk$U7rzOYZkm-Z<18$wv`(eqcD-PfDi0hSw^pPAQM2H_g ze7P$oyaGh+h$wwQ6(+4n-7B>t%8ZBR$aM!wouC=SEu5Xp3lRj7*tbI2aG7vjQ`gR4 zL05>VBa{d!g4hwEvvEmHuXqW#O=Zk`i&W2EIEqGU1oS4}oNba?I+F4ySk@({3 zM{lOX-jQZa>2ee~x6;qcznT%HHC5~sUk*Bih>}sDz;U5zQV>q=mRMGq4;RYMK zN34x(OZxC-(H8=h(kH{c-|S`4h?wTmY16a}vy#fiozjNGoxoiN#Y610ugh^Kiz~$m z{Z^Kf#vR)-#%yDURJFoKjA6kP2rYiF*gden5RAW`UQ0B%{`8mjv~2->VWL50?&|`_ z54ZD#;?nZQ&meg;Kk$_IY|X_B*NaI)X*?UzMZI&VH(NG<$#_c9qsy+vcNBd7e43`n z3^Qj=5PcAQPxQ7OIZ++R{C@$_5ToxQz1A>q;s z$K4iwzjbc}{H^-p@@H>taV3RfJ!dxE#2_NP*0*d($AG9M@6Y;*@s;E8`FW+<>Y5Ts z#j$C*2@46cqq$v8aWs@Ki;RpCUqx9tN0pr8{bqvy$JCiXL%qN8|2y_1TVhn!WXl>6 zvLv#UNG2&;DpB@r?8Xv8(U`JEvegjPlzqLnWJ{75Ye@Ee-~P|^`~T1R-*eAB=bn2{ z&3wQ5JfG+Nyr0)w^K7O0=Xm=BWuF7YQf8+EwQ;+De$VvQ)oBbck1zf44RXd7B|1m= z`gp0)K4o4vlq%4F*Ou?&?v|!`)_38X&2krn`;64V@ZM6kLRCG_$yNEu@}mZ8X8rdJ zHE}48#|$WxN76wWLGz5Ei_$78BoUUi^@%nc<;jML!lAX35J@SU0$r9DnB$7{O0Bqc zqj=rk%^|5-wID@vZ!2_WDIr z6H8jPZ)eW88=_Ag7tQ?@k`yg`eYT2z+)loUi6D8amX-uA4F7Fjbp2b_(a}zSkkEZI zw8H)l@6;>ChY#NEdhsw_C@|>xd2>Lu5q%L61*HTO|2Ue=C;w|YVuVK0g#P`b8je@6 zc0X2;dI~3Uj3&dsU^(P?_f6T4en%lW0Nh#6>c22SNfNRy5dml?M58j^;7{gYUi0FE z5%SLPf{Qa2dtd2g7Wzcx;G|A=iBQGptFnSiwGhjaHD&I&4NJy=gj$`j@^|+nd9ld| z;+$-8)2bU7A=Cr|&JN1Z7aC-%#WKF7!10? zG=QhmfIgsmdK6lLhwlKx2`(yB+(iK`yp-~X0j7xrQ|FX|m=8ub%xFS%RTnnEB{}_asPy`U)7eX`ZDivt|LuC;Vf^qomFFpub z^P4Ek=O4AFto1X3#U3?YrM{zkF^QJuQny@Na*peIufvOr0A$01tn>8XDNAvPTKX~BBVfJ+t1ViZIV1n~45}7ZpXS)c3Sixrn zgFCiDDAu4y6k8rmT)is3LcBVdFaL)kA<%4c|Tew$y)PB*L$S$Fwxw zIBNcezWsLvtj&8?Dh#Ur8Id|t_DXrqblIl=)ErT2!%fLb%GQI@_Za+H-pqeE5Kuli zcJn%Ukcn^%eTRv&_<~w_+3s($srv3FmsPd5yH}uD@NKkl)Td#28A?_!w81Cu*+Sai zoRnC$(A%HNlgTgjeAhN=DI%cXl3i(Hg0Ym8RI+f|%c|YQ`Q5d;-Iw<9Wkq_yVnuBZ zQRw5A=FAPh!dU-efH)+M=Bfk#niktF@wFlAs84TFVZ|2U(p~+!hR19QEeUwr5ITL;_ zl2Vz{@Z4!R4I^#tICg7|^O9dKR8^P{Sax`MbvcB4F&oDSV(19wm(-c2H7?s8zM;wB zqgr2d$3Y;%Z#JTg$EK_AZn!lP9CD7Img!i(<)J)-E``lM3gO|=N;!v_0xC;>Sq}aA zeyYB?{dG$Fhtv}^tkyMck{a@dwnnDL+B}pEEZBpM1D=DTK;jOcaK5rXnZDm^bANvw z%yv%KQ<%cg&*`!Amz>COSqaZDKo$JT>h>Z@KEEr)dndKSHtir1x>Xh7r!Ur{Oz3ki zdgH|Tv8T<8;nQTk+#UT4-@%uLyt6YrvyzwQF0D-f==q^|!alUjQHJ8vFl(%=ctc$l1gDbCQC09xC?39xnN$F#IeH#qosc?nO} zv836M44(PvsK8TQ?Ol%FwD~}~0sKW~avLev(7@$)cW;W#Pv~}(O=Xbd!BPi?o;_m{ zLcShyla|=6^V8|$hEgw z&kzgZ<;b}qm2*{9m5`miqjO(T(T{ZR@U@TM6x!TAeo+eA{7oLOy`qwGrSH$wSUw4T z$|k=3Vfr}9N!C7v6y0?jE!=jO#3PZF>K}r?=O@KGE9gdR)HPahf^LlR)BK<6c+la|B`xFYCCJ|=(kyzSz?*jUO*e>Xu~M( zN$PbdCTDbHbLh!dz)GP2#8ls8uvZ~O=S@3T1#C`ESiP)JEqrZ<(BPgvy9hV>$oWX2 zs!=%4u`%-ucmxzNOT@z8|YS9rT`ZM988q=)U_fvW=#k3hB#bZR)EVIfqVDojNv&5i7L z23&bO(CYr zUf97yA}!C}5u}VBjXXIEbUpM|mHN4J{wsew-INqbx(7Sm+9~xM#=}lq5LsR6yKP%J z$S4z?(w6fTP!MQX0YEq)fgx5`ALQvFb1P?s0DaU6Ie3-;_@h)f-QPS-qA`?xG}@3X zyE$h5Fr$aF+f@(0dnjiwK+ILI!^MvfLkh!~HgKreWtF7@3VlCx!M zs@1z~0WKDSERF}7xmegg-z^qjX-iYrz5Q!agiTLo7J>-FyKwI$jSIBJ{lNvD~QR~*c5`65S(Oj%~ zMh;u3E%f9QdIUF^p_ET`goy1UA&{Va;p z!n8RISiu*wE`dJFJKfEu(pI}I)jPdl)Bx$K!Ar%+fqap8VUp*}XA)~~*smh7#=lRy zA9SxLWhG@}L&_sG^e#x^*fQpqeJkgdan^6`bziixUeL9bHM=@F7uLMLv%cRHw51dD zu{g1CYg#wO)35Y}!R&xm;>5@DUj~i-P0?ZVyTjYLBG7}Y1-b1YKO7WfA9#K?V;TRM z7ZaUm^UCj~L7yS7+EP?UT6I$U{qktrzoyZf?OR@l-*7ow2JKDl^aQPhhPn8-?zXik zV$OJdvb)Y^$Kth~YasXVSS?+Baqj(m@_oZ}4_VM6e$2ivm)mZ$+D|L5R#viDt<0Y5 z?j28Ao+d@N=#kMowY9w0y#2i1#l2YO>9}xsSYv)pGsGe-6*4+Lj2)A{Z_2eic^A8H zt?~n=JKAF-dxJ1I>RfbvFq*!bSN(=br946`TUyO;Zv`Z^!FD4>5v~dAsIDY~TqfJ6 z8vh9*UC2k>IBl95du$bP{#;f<_y}BgsT#oOp zNNE>#lzaSPZ5lZ`&KQ_WG)Ev_ceSq&BRe`x+}GArT5y|6R;FvCmW>MN#3xWU6v z07f9hTFdpiJ`8Ch6+_~FaKz?g+(%P_`NQ_oqWFTR|L*A;jBM*Oyn1X3|M}^@Fh>5G z{v&1%f(7g1aTw(UQzBqsew_?SIE1k|ym#SGqTfH0E>xi2NH|oo5Emd+=^YA#^Bf>>UMKIZ zrjXKu7Q64K2L<>9j4~o$!2PrC!GcQ~;T7vYe8}bL0#7cqVKtW+Qrr77GedLX!qaiT zt3V*sZ?epZG7&j}fq4QH3plT0*iJkFOWf4_mjPOLDyHexwKj4*{3urWy08725uBKs z6Uu|^7d%oIc>)~Gue?wGyXm7RRsSa?+GP2aG^vCL#So95fG3p68WMO!59UR`hjhSj z0J0kt9?HagF^z&37^ZkHEX7Sk9M38L+W$M5slyVRu-q;RbRY=UOqKTt$L1R#kPj?9a+roAX{HOWN_-jN!0Z#r$00ZJUGmR-RM^e0TZ~`xrl*}03>@#o zi?IsfQQG|HLoZmeQC|pEx%WlUG$&*2SYbf#npl1KV@`{9R&@TDn)6RbCWVv}bcAzb z%0IprIqFLit*k616PAIM=)Ku30j$KmbMq8d;y{OzYy0C%7w^Jf1LbAqe~U_QcpPM5 z-8sa2dRS1PG4cSla9T|m3eWcO?g4>dRvSB1QO1X3<>Y}`;#Xqp*Zhk5U9Hqao0C>)_*h{SkUvRIKq=LD4{tpS$bkc>F}rO78wnZ5@mH#&BkI-YJ$0 z`=g#_;^gls8TO6MHzJ7k#2aT!ds7-p6PccjiYpsVx#T9 zU8j>WyVgtMDs~<^saZU`#=I7^*`1Ji^~}q#?gy(AeCqpi>%32{xtI2z3s_t#8+e*? z#31Bt2TXZm*VaVuZi=rL8V((A%`J|7T6wCaC0cn4W>C+oB*=R$q-DeEJ!QWGpNPL| z{bgVNh#YBd?zL0Mdv}`n=F_Y#$1&+gCp+$+C`-3`iM>7;v@){V@SxQEs+XIauYX0* z`d=9@pCD&tmDJr8E-2 zyL5@%v^6M>j%zYxPEW^O%y3G!{UP7xf9`2;_5ePN zyT4K-idyJAdn@>ri>h}Q>c)Ln)%WZ6XTjXSCwURW^J>vf{z_)iJopw@hX1p}TIyYT3!N-_EO^lz(bB}v&=H{OI~ zO?O8LyvR?KXuPp?1zZcQ2>G@Q9K<=S7ob^*V-lzVj~$S221n+6>A^hUS~sBg-y;+~ zqRFrWS!Vxfu+tq!fP6_w{e-n1aNa?t4y-Rh0R+3jF(FwBEC8W9m2D`{et)zsw6gA2 zv|m$1MDdzVrmq5b6U2RIcUa7+!uk_V_r&?rVR2JLeNWS!o!?W@(&+&^lMwZHZu%ov z?SS?KLan!P>MR|;Rge~sx2Dm!J)F&Ph#@YY_(1m9kXq_Mc|b{Zb-J-&l0;0Cfkh7n z6a1QjE$i3y)cy{j&1Pf$_EN%k&zA@B9}zRJmuYEg0c%UWd5X>ux|(twB(Gj=_yRk0 z6Sq(}C%|wA(*f0i07ayHnFo=_9fbcTOxJ}dLN`$Ejtd^FMeR{M;v+n^bTv*eY56{| zm?Ct$DOw0C;(z+V+#toWv8z(d(qwS?nJ1&|MPnx0U|WGOlLn4F)+d7e->FzNX*e_q z=X(_giX6+U=BI7V^-Igj^u0QaB zPPA*CAXbK-{{S@}dS=ACj!6uycLU)^>-h|FcXxZ7>m9P{FUP9;iS-_YeylWatctaqP&TjlTWqq#r6`+#I3f{oP_9$o<*&3f-?#`KYV`E|zV0E%BkU475zx>pMk|B6mODsD|tnp1%i<0yoQs(aF zx|;943WRm9EoPWp>5%R#()J?2J#=n9Mm&bt7emWXo0I9P%Hytf{<7%TX@j{UIy(3% zkFK3!%+`Hv*4%5+L*}#{T`VDrha>B$Br^%^w@yZ9-W;3pKF_3q6XdvkgcUhF{MA~P zgZ~<>kVY{3A#RR19y3-prZ9#QKW71Ds`KZ+{rnrEA})vy!(U}I@tt>@GmZ>yO;NaC zsB`$3A!{q@0?yZ=c+&?B18gSUOU)6%5K-7D6yU9KNEz!7)kJkIERxpr}HfvNt7BtvfFXQ%RJ zFR4DzjMNHYpqB_niT<)&;kvJcUmH1ZjAB0N$%$p>wqV?> zs+M;l4Op_!)Rc6!%QK~6FlNlQx1evWuiGyv_p7Mf^~R?8fkOhjOTE*C@3VEizMj1? zw&Yb|wwBo~!@#xfy4XQ-N~_}Z8W?+vOHIW;*tn2FG8^9MS+wP3nwx0uZmr~hnqKGY zPx;X{K3-auDj2wr4Fu5R1G1XW;_KwgR|>CNRh_k14>+tjRB0SJYJ1t| zUhACWGrOxW#a!B`B*!_MK$lYMKQZUmVo-h4vMqk#W~+2z0nktT|Lk=HEp-_bRqo!x zr>Xh`Z2$bd*14Ed?(6PaV1$WJdZNR?d5}ts4nbAos5Ch5hF@-B#vQrWmw#!f^J`14 z^Ilu^-t2tfdO7SerTZ^pKA>%m+_8uiUcGycyZZ^PbB~_TIHUF)Z5VZ&evc;@?7KPw zHyxDUDfZ012|fa6=ou$X{a{yx6zwk9Gj$s%-_DHSJLkJGn47+D6C|smu6jzFJR>D# z>!%HX0WMCX6xxeN>cwA5n<`D*BKgRrJ2tiT`o{YiA(iufN^DOAHm~%&_@40E_8fpa zVT>Lro6K#lf`%dk?6-*480td^T*s-ufndid-_QRz*a;a%AY@<|Q9O&hf`Eh3LloB> zqQ?Y(lux?ig0o<#vO`ygqeftqF7WLxDm%X|??oE~`{4%Tg+&R#%f2dNLu`3+%|-VMV?FaKd`)2c!B-Z?ItP%tEB z`*ZCc$zGAXwzKrRJEiO8a`g0Sku)>a@^0t4{+9a}}7I~ke8=ixn3dR!?{p$e?8PjF3t6ViWV?8X|HR&OL z^cnO9wm*v;+aVnR{QF*A7Ut&p0LJxFNxEz!w+W=-pp!HrpQv^JJA_B;60~kZ3k4ho zitQRNHNu0Jfo&ck1oMfA|(GL zv~+jn8g5smUlwk&v$3Vr5h10h@)R?Mj1?b|#zf<(zO|*LrJ0r2(<%rJD$$G>BE-DF z48T0fqeX@UZgW zIyytKM{xaxcPw7wHaTsQ&GFhytf4hWW%NLE*_F49p8T}Wc{$sDujcGFn08bJt}U%j zHmnw{hVbA8PS+C&c<51KV^;q_unO>8aaly7?pgpJHFHj;bAZc!IiG6a%EIpC-3m)9 z^`K3-dbdQAoK*ui7UmW`Ofa(C{pjh%NYC!eB51?mv|@6)i zNxead@mUAwC?5Ln3@xk6A|1Zc5ls>Cn^^<-qJ_rBQUOEG#RHq0K4RGg7Xgt7sm1sL zQ&W$&`%q8Hn{0)C<@MZ$p-Qj%hDgwkO7;5oa`WJ-@4=h;j~h^{mS`mL{9NLdrp(SP zLe;b~tTwa$mzBhjE$!@Sk>IW%M_*W=nAa`ttSFn^Jb0Nsi~m?`Q-eD{GiSUuW30Nj zw50G~Rp(8zsqwko=v~yu-)JxA8?f|1 znfFPGx3@>$bWw+8#nD(1v8P4kf|l94r`Fx8hsIOq~OrYe*EuD{7Vr?RVzS!1txg|Cz@GQB!r0m>!0S#}f)7!BG z5ou$6;dr_0p6#V81C`tJNBS;~Pfp%@e4f{wTcc;4ne#&w=be@Q3sJIE3?EL*$xvd< zIIV4ig_~P784!Q^f6F8w+S%cbRR|n_1Hb+de!~F2z)V>>p&pc}dkP|p%ZV_4(Cb`b z+0U%rN}F9zPXXa?Zha-n!H98Oc9lz4(23aADQ4y*HP`OJ*sp=-=6r)+LURo65^O^L zcO^<7YkKw1?+5VSJD^3*l}@X+cX#a+U~Xli)~i5ih$9}<2shkCvyGmGlka$~}!`4lgJVkxE^0$p(0*V$P*TPCHAQY&BwP|uMJ zIelSNl)>gxpMHf|G{}^Q-=%xN>U9YFdw6^ z@x&V55WZupmL-wVvbRJccekyVr{{Bep>f?%qipcR!IImb6+)Js3jV8#?on9MqQ*n% zJe?GGE?_xlwyb}him6thYG88F>~HMY;>xKR1a!r-6MKCtrLx0-nYz$=UhHHegS2cTF)F&@ zHIZ0G6zu)+_N~oaU)8)$=2h}Ud{+ys1hp4j?;$&q@6jJRP2zBbv}Ab$UWE5ft5S-Y zuI$8d$seAQ9of?pq~1M;mAZNLz4lR^;#ih}-POsIRbL*-8?7gNa;z<5!a8H(MuJn{6c5P{Vym#~Nxxo36 z6El)7m0I~*)A!16ma70Kgj6LBcA39F1+Ho7+bNoIB?LG@h#=;kSfj6pr`P6KL*D*& z`tC-<=J-6of9|~RcH^l*-+6Jrlt#Mo^b858Rqf<=+<&6&8T#|Lr@Oso?Z{qzF|XJ& zX`e%j^W?>#M9+k2!n*T3c0j=-b2@MQ?8U5wt`4B@o9>Hz;d-44sD0|s*X2KsNu0_lM+z3$`bv$-+o+8&VmvEO{+d%(iq#omSoKCWtS zf4^(^E{2keLmg?aPT2mqtA2ed#TvH{Aj4ozz z*ZP+mup$W`4@w~%VQ#KIn~NRlKC4Uq%6SE*7Cf>KZ7`S*Z-Llsua-_d4ojz%PQ{M< zx70TVZDhB1xY7eRYU^M>-+=7sCsOCHHov{s+q{gv)4n}fY=_z4xo~4GXk$20>o(4N6=)`}>N|n=-iv||JCtR@5;5X*lV}Kx|fG)vD z3lY!eLaw1gPL#_s+={7&HSjF3&*2pJ2}O6@+S>LwY=t5k?9^D1e=`^0&hf*>J@iMw zuG5r#<875|k}Jd8UA)HGq!Xc|Q#^Nk@aU7N#W#AK$ihVwc&Irw`A3YJtNMz-yXn6( zd0%~hY#GLUzyAm#bBUsHlscDS&c3JbAqYMKv^7#u^IWfVg0-~zM!$NMr}z6H5AU-_ z&jk1BiT&`jz+f1J1{npuwesM%s>TnUKrzr+cR}vVbVA`3%e0EX&8@MO85@$lX^JEo zIgtdn;0x8^@E{|y{uN17K-!4Qoa&n$O7EwA3MsfiCRD;s}bU2#=*diwO~pJgAP zJbEMj$?d@M0lY-Et~fP*4w%vy%$$=7L%`6bB_6`2|DgPntVs{zd2$ilpp{<|hkHr) zAyU=c{5UVKxJl4<^-ke{ARU!FQgaNC#M5vg2RA5viVGH@5`vEoE^^S;sF9)z`cyT+ zLdkkmQ2&uJ2q&Mr@?H0k3#D&^^5X$oSBU_a;;4=eD|Rwb|Eo^HbjOFoom}8$(g`iT zK(U@b{jIEke5*BZqmJ*2&XcV8_;|-5Jw^e7v9W$cMALNJpSI~9$DVfuh3CsoKyWF{ z!?HPadTTWrKn=5riEpkSFm3T9V?Bvc=dc0#Z@s0P2cUP=WAX<&IGu6ltvG8sxV?xm zC+GNh@7KcZVY+NuS#Elp7ond^!w6DmYSYosq3Q5QA~&whtMcYMAk4))TS8}+cX6;H zilj-8vcxvnu9l%YrihXEBEOrh_x{|UYAI!vZuL%)Tx8ngDcEX*(S~1g5N=U`REq5s zqAa!|{gw8~6!5H3Z~70oBy0>oQVJX-ca;a7ih*&&_hhPVYiqG?8=6QG3@oC-pEL0fz(!;GK1h9IZa}mI87*<#|-NYEH0D7XmG+< z|IIO$^B)*L$X>#Y95a5=dh`H_>fqMrvO`->64YAPSPyd`f?66lTug;j%gNi&>4YWv z`dDkzzoUy33`0ckK=u;u_dOq}dHw2lI(n7Y%BpT!RF#&Tt%eSqUZ?mEHr86RSUaJx zz5QxM0kM14mSlOsYrWF%`pFp@hk_UPa|`dsPnNv>?Hxm$E8Yb+;>L3N&P<2;UN1}F z1U8oW>5Dvr^h>{FFDw?U$as+z!ZbeGCwJPJV4mxzyB83NgL;^l&WzOM2g@%m%$1Z4 zf`O^u$s#-HidJk4CbIVTUF9pa!UpHkp3V=bp$!Eu+>~17+u7b2TQ0qrt%LA9Rpl)%_5I$i=<&%ZWqL0Q z^(XPlKm59$bx$sHb>xy7M1LY>`19JG73OJHJbZKA!7ZyxHh#O?khc0zb2n(OPMzu+ zc@5@DH)B%XJ{qm7Y#8~yzex((TWx;eI~`}+(~>O>xH^|~0mr`Cl)QsE#H1_N20)3j zeO0bip)G>b$jp0{Xtr1}P|)qHXqqt3$Ftj}zELN&oxZmrU6hp_l~FKdYogfpCe5(1 zc9`5wBT|85f5Zc^0vjUL8=J8~YpXhbtG})HCpxU2PGp*$(UX^Jy-)h$U1_PV>Z7Fc ztK8GWdt&2@DS3K%SvadJFFNnL%B=MV)2*GIhOXwjuS4*dp3h0DL3{r5)%;rb6l8m6-~ z8u(xpkZ342Fgi+a@QOfHGvFFZEw@1Te@zU)R(n>j;Y``*^o{^ix7O(}a5tL~x>{dR zdB04wNi;NYAH4*?r7!!eCgS#1A!x}^UkFkl|bf5#` zlSX*JhJH7OvS#B;PiZo~AvmXha%I)+tM~(Wqounh>Lo$zyW3dX(VQ#&?gnl-P@f9Q?m&rH=wx_wD-RR&)zmX7(T|ri&4qCLkUP6N>Lu1{z9OQQd2D2 z{Ezqf{?{N4o;RiprDVT>a*7;9hJlz~0d)!6bV#q{w(U{m+ac!nCs1(Dh(^pW!-3te z>b)==O26*jPNCzzVaEYE$=uSCQzzybu6&3q2Az!{{D_{`d6P2Fho@h{3PzTrA0Tn7 z5=`^~wheEgmC{!V&>$3DX80re92a_oQOs8gO)%DE$R?z^$8@&piwRv4o8#3Kh4=`D z48kD9#+TDU<_HFpjfQ;MF8L?rxh72nArSrCfv+kNrg3_LS>|p14HPdx_NwMDi5)kW zC^XH(v@3zOiHE62G>e}wVkO4-A>VWy1ekOAC(nU zu3#{p0aj-|12#`DoYkLIQa4Ig!QjFxNAgt+ACFYk>fU0pny<(Dh8G5NKY?r3_MSD* z!glp?UGFDu)3-!%05XP!ade_ZS2TxCam}(OG0KLs>egM6smF1!=Jgjn3ool(Rd!a8 zrHzxJeg#AB0I_=mUiR|5(wweU^g=fdp~oy!1#lkT2u&`+j<=(|IEJHInS%9m_8L3o zgCBxh4;?x%$7^H!P^>uyObNc=XSwZ%^NgVT;j! zZjfWw7;>Z}n66fipTO(#iR@JVf|Wkpnm3)C5iTh4pSS=OoAYCF{)&8erxAj8$Z^bb9HS*DkHRW&7MB-tc0Xr+3eFKB&!r*hNd zN5Z*u!}GwXGU#&XaeRJ}xsjMGzgQm22m46@YvUvqHUG<-uwdM7!O)*>z&7Jcc2=}- z0(Zl$C&y~qzJ)F9)z#f8f92*2&T@zn>PPmj$9uGHE%udQshDCTl; z=Cv63^{z`>Rx2fUJW=jb5zVeBy-{S5CdFwPcZo}rmA^#a(lRZ`Wj?KC$zNrDyMVj#m9qmRvNUwXG>BlKkM8W|Daz+ zn_DmLB9}FrV3L4H)p;yJcTi~HQaL2proAlK9|)Ql0y2d;BPV4GCPIoyo%;g+g6kLL>Y_L+x~ky zK66{WHi7GdmEsLt)jLzQq4XjXxzhzL*&GYjMPHO4(+4zeS4{Nn&t|3uFGDOWq&uYg znr$HDPbW{!nVj}^3adYeV!cE7QJ{cCRoEZJTl6HEF`PHXU|>BQ<{26c!CB>XC82P} z9S8CYWrZH}sJW+ z1;{~o;{�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�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%0Db8mAW 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�_@&f14ESdtCW*hHEW4p1(a(ZIVLkH=BH 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⁣lLS#wx%9J`hs9`|hK& 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 literal 0 HcmV?d00001 diff --git a/cv/distiller/CWD/mmcv/docs/en/_static/community/2.png b/cv/distiller/CWD/mmcv/docs/en/_static/community/2.png new file mode 100644 index 0000000000000000000000000000000000000000..76e21def858b2f9392a90999d741cb653e766ae5 GIT binary patch literal 66595 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