From f891064adfa0483405b5cbcba617c343743f9cb3 Mon Sep 17 00:00:00 2001 From: Kaipeng Deng Date: Thu, 23 Apr 2020 12:22:44 +0800 Subject: [PATCH] add yolov3_mobilenet_v3 pruned model for mobile side (#532) --- configs/yolov3_mobilenet_v3.yml | 1 + docs/mobile_side/README.md | 33 +++++++++++++++++++ .../distill_pruned_model.py | 10 +++++- slim/prune/prune.py | 10 +++++- 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 docs/mobile_side/README.md diff --git a/configs/yolov3_mobilenet_v3.yml b/configs/yolov3_mobilenet_v3.yml index 4463d6d27..223d14c49 100644 --- a/configs/yolov3_mobilenet_v3.yml +++ b/configs/yolov3_mobilenet_v3.yml @@ -19,6 +19,7 @@ MobileNetV3: norm_decay: 0. model_name: large scale: 1. + extra_block_filters: [] feature_maps: [1, 2, 3, 4, 6] YOLOv3Head: diff --git a/docs/mobile_side/README.md b/docs/mobile_side/README.md new file mode 100644 index 000000000..5db744768 --- /dev/null +++ b/docs/mobile_side/README.md @@ -0,0 +1,33 @@ +# Practical Mobile-side detection method base on PaddleDetection + +Mobile-side models are provided base on following architecture: + +1. YOLOv3 +2. Cascade Faster RCNN +3. SSD + +## YOLOv3 mobile-side model + +Mobile-side model based on YOLOv3 is a pruned model of YOLOv3-MobileNetv3, we pruned the YOLO-head of YOLOv3-MobileNetv3 and distill the pruned model by YOLOv3-ResNet34, which has a higher mAP on COCO as 31.4(input shape as 320\*320). For pruning, configurations as as follows: + +1. pruning YOLO-head with following configuration and the FLOPS pruned ratios is 86%. + +``` +--pruned_params="yolo_block.0.0.0.conv.weights,yolo_block.0.0.1.conv.weights,yolo_block.0.1.0.conv.weights,yolo_block.0.1.1.conv.weights,yolo_block.0.2.conv.weights,yolo_block.0.tip.conv.weights,yolo_block.1.0.0.conv.weights,yolo_block.1.0.1.conv.weights,yolo_block.1.1.0.conv.weights,yolo_block.1.1.1.conv.weights,yolo_block.1.2.conv.weights,yolo_block.1.tip.conv.weights,yolo_block.2.0.0.conv.weights,yolo_block.2.0.1.conv.weights,yolo_block.2.1.0.conv.weights,yolo_block.2.1.1.conv.weights,yolo_block.2.2.conv.weights,yolo_block.2.tip.conv.weights" \ +--pruned_ratios="0.75,0.75,0.75,0.75,0.75,0.75,0.75,0.75,0.75,0.75,0.75,0.75,0.875,0.875,0.875,0.875,0.875,0.875" +``` + +2. pruning YOLO-head by [Filter Pruning via Geometric Median](https://arxiv.org/abs/1811.00250), use FPGM algorithm by setting: + +``` +--prune_criterion=geometry_median +``` + +### Model Zoo + +| Backbone | prune method | GFLOPs | Model size(MB) | input shape | teacher model | Box AP | SD845 latency | download | +| :----------------| :----------: | :-----------: | :------------: | :---------: | :-------------------: | :--------: | :-----------: |:-----------------------------------------------------: | +| MobileNetv3 | baseline | 4.93 | 90.23 | 320 | - | 27.1 | 319ms | [下载链接](https://paddlemodels.bj.bcebos.com/object_detection/yolov3_mobilenet_v3.pdparams) | +| MobileNetv3 | prune | 0.66(-86.57%) | 16.21(-82.03%) | 320 | YOLOv3-ResNet34(31.4) | 24.6(-2.5) | 91ms | [下载链接](https://paddlemodels.bj.bcebos.com/object_detection/yolov3_mobilenet_v3_mobilenetv3_prune75875_FPGM_distillby_r34.pdparams) | + +**NOTE:** `baseline` is the YOLOv3-MobileNetv3 base model, `prune` is the pruned model from YOLOv3-MobileNetv3 and pruned by configurations above, `Box AP` is test by `320*320` as input shape in both two models, and `latency` is test on Snapdragon845 with single thread. The pruned model is 2.5 times faster than the base model when the `Box AP` only decreased by 2.5. diff --git a/slim/extensions/distill_pruned_model/distill_pruned_model.py b/slim/extensions/distill_pruned_model/distill_pruned_model.py index 6ab641480..e5fa524a3 100644 --- a/slim/extensions/distill_pruned_model/distill_pruned_model.py +++ b/slim/extensions/distill_pruned_model/distill_pruned_model.py @@ -231,7 +231,9 @@ def main(): assert pruned_ratios > [0] * len(pruned_ratios) and pruned_ratios < [1] * len(pruned_ratios), \ "The elements of pruned ratios should be in range (0, 1)." - pruner = Pruner() + assert FLAGS.prune_criterion in ['l1_norm', 'geometry_median'], \ + "unsupported prune criterion {}".format(FLAGS.prune_criterion) + pruner = Pruner(criterion=FLAGS.prune_criterion) distill_prog = pruner.prune( fluid.default_main_program(), fluid.global_scope(), @@ -361,5 +363,11 @@ if __name__ == '__main__': type=str, help="The ratios pruned iteratively for each parameter when calculating sensitivities." ) + parser.add_argument( + "--prune_criterion", + default='l1_norm', + type=str, + help="criterion function type for channels sorting in pruning, can be set " \ + "as 'l1_norm' or 'geometry_median' currently, default 'l1_norm'") FLAGS = parser.parse_args() main() diff --git a/slim/prune/prune.py b/slim/prune/prune.py index 606b29e7c..2dc6ea720 100644 --- a/slim/prune/prune.py +++ b/slim/prune/prune.py @@ -187,7 +187,9 @@ def main(): pruned_ratios < [1] * len(pruned_ratios) ), "The elements of pruned ratios should be in range (0, 1)." - pruner = Pruner() + assert FLAGS.prune_criterion in ['l1_norm', 'geometry_median'], \ + "unsupported prune criterion {}".format(FLAGS.prune_criterion) + pruner = Pruner(criterion=FLAGS.prune_criterion) train_prog = pruner.prune( train_prog, fluid.global_scope(), @@ -388,5 +390,11 @@ if __name__ == '__main__': default=False, action='store_true', help="Whether to only print the parameters' names and shapes.") + parser.add_argument( + "--prune_criterion", + default='l1_norm', + type=str, + help="criterion function type for channels sorting in pruning, can be set " \ + "as 'l1_norm' or 'geometry_median' currently, default 'l1_norm'") FLAGS = parser.parse_args() main() -- GitLab