diff --git a/configs/yolov3_mobilenet_v3.yml b/configs/yolov3_mobilenet_v3.yml index 4463d6d27217a4d3567e73acbd9f7e58e6fcfbf2..223d14c4909998b6d76f54ff3b45d6d1badd9d1e 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 0000000000000000000000000000000000000000..5db74476887d9036940acba2907ba917f51a6c1c --- /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 6ab641480604e29e0b32b000b49d15d3bb311f46..e5fa524a36b72f360326e0829875a09ee98a5b0b 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 606b29e7cc76ac6538737acde2fce2bb99bfd241..2dc6ea720af7a90921fdfefe9c7f90d5aee83633 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()