# pytorch-network-slimming **Repository Path**: ptklx/pytorch-network-slimming ## Basic Information - **Project Name**: pytorch-network-slimming - **Description**: network slimming for pytorch models, support user defined models with Linear/Conv(groups=1)/BN - **Primary Language**: Python - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-11-09 - **Last Updated**: 2021-03-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # PyTorch Network Slimming This repo implements the following paper in [PyTorch](https://pytorch.org): [**Learning Efficient Convolutional Networks Through Network Slimming**](http://openaccess.thecvf.com/content_iccv_2017/html/Liu_Learning_Efficient_Convolutional_ICCV_2017_paper.html) Different with most other popular network slimming repos, this implementation enables training & pruning models in hand with a few lines of new codes. Writing codes specifically for pruning is not required. Moreover, the pruned model can be further improved and deployed with toolkits supporting ONNX. An example of further acceleration with OpenVINO is included. BN layers are automatically identified by 1) parse the traced graph by [TorchScript](https://pytorch.org/docs/stable/jit.html), and 2) identify **prunable BN layers** which only have Convolution(groups=1)/Linear in preceding & succeeding layers. Example of a **prunable BN**: conv/linear --> ... --> BN --> ... --> conv/linear | ... | --> relu --> ... --> conv/linear | | --> ... --> maxpool --> ... --> conv/linear Note that without coding for patches, such as [channel_selection](https://github.com/Eric-mingjie/network-slimming/blob/master/models/channel_selection.py), the prunable BNs for some network architectures (ResNet/DenseNet/...) will be less than the [official implementation](https://github.com/Eric-mingjie/network-slimming). For more details please refer to source code. It is supposed to support user defined models with Convolution(groups=1)/Linear and BN layers. The package is tested with the [CIFAR-100](https://www.cs.toronto.edu/~kriz/cifar.html) examples in this repo, and an in-house [Conv3d](https://pytorch.org/docs/stable/nn.html#conv3d) based model for video classification. \* ***DataParalell*** is not supported ## Results on CIFAR-100 ### Accuracy (%) | | Original | L1 on BN | PR=0.3 | PR=0.5 | PR=0.7 | PR=0.3 (TFS) | PR=0.5 (TFS) | PR=0.7 (TFS) | | :------------------------ | :------: | :------: | :----: | :----: | :----: | :----------: | :----------: | :----------: | | ResNet-18 | 78.90 | 78.21 | 78.60 | 78.02 | 74.97 | 78.31 | 76.84 | 73.93 | | ResNet-18 (L1 on all BNs) | 78.90 | 78.51 | 79.07 | 77.58 | 75.30 | 78.29 | 76.77 | 74.26 | | VGG-11 | 71.04 | 70.66 | 71.69 | 69.16 | 58.95 | 70.74 | 68.50 | 61.13 | | simplified VGG-11 | 71.72 | 71.62 | 71.55 | 68.80 | F | 70.58 | 67.37 | 52.87 | | DenseNet-63 | 78.34 | 78.06 | 78.11 | 77.76 | 76.33 | 78.12 | 77.65 | 76.01 | ### Params (M) | | Original | PR=0.3 | PR=0.5 | PR=0.7 | | :------------------------ | :------: | :----: | :----: | :----: | | ResNet-18 | 10.70 | 7.91 | 6.44 | 4.56 | | ResNet-18 (L1 on all BNs) | 10.70 | 7.84 | 6.39 | 4.52 | | VGG-11 | 27.20 | 21.75 | 19.35 | 18.00 | | simplified VGG-11 | 8.85 | 4.63 | 2.09 | 0.54 | | DenseNet-63 | 2.19 | 1.63 | 1.32 | 0.93 | ### GFLOPS | | Original | PR=0.3 | PR=0.5 | PR=0.7 | | :------------------------ | :------: | :----: | :----: | :----: | | ResNet-18 | 0.52 | 0.32 | 0.21 | 0.12 | | ResNet-18 (L1 on all BNs) | 0.52 | 0.33 | 0.22 | 0.12 | | VGG-11 | 0.19 | 0.14 | 0.09 | 0.06 | | simplified VGG-11 | 0.16 | 0.06 | 0.03 | 0.01 | | DenseNet-63 | 0.30 | 0.18 | 0.12 | 0.07 | \* **F**: Failed to converge \* **PR**: Prune Ratio \* **TFS**: Train-from-scratch as proposed in Liu's later paper on ICLR 2019 [**Rethinking the Value of Network Pruning**](https://openreview.net/forum?id=rJlnB3C5Ym). ## Requirements Python >= 3.6 torch >= 1.1.0 torchvision >= 0.3.0 ## Usage 1. Import from [netslim](./netslim) in your training script ```python from netslim import update_bn ``` 2. Insert *updat_bn* between *loss.backward()* and *optimizer.step()*. The following is an example: *before* ```python ... loss.backward() optimizer.step() ... ``` *after* ```python ... loss.backward() update_bn(model) # or update_bn(model, s), specify s to control sparsity on BN optimizer.step() ... ``` \* ***update_bn*** puts L1 regularization on all BNs. Sparsity on prunable BNs only is also supported for networks with complex connections, such as ResNet. Check examples for more details. 3. Prune the model after training ```python from netslim import prune # For example, input_shape for CIFAR is (3, 32, 32) pruned_model = prune(model, input_shape, prune_ratio=0.5) ``` 4. Fine-tune & export model 5. Load the pruned model and have fun ``` from netslim import load_pruned_model model = MyModel() weights = torch.load("/path/to/pruned-weights.pth") pruned_model = load_pruned_model(model, weights) ... ``` ## Run CIFAR-100 examples ### ResNet-18 ```shell sh experiment-resnet.sh ``` ### VGG-11 ```shell sh experiment-vgg11.sh sh experiment-vgg11s.sh % simplified VGG-11 by replacing classifier with a Linear ``` ### DenseNet-63 ```shell sh experiment-densenet.sh ``` ### Train from scratch Run shell scripts end with "_tfs". For example, train pruned ResNet-18 after running L1 regularized training: ```shell sh experiment_resnet_tfs.sh ``` ### Load & test pruned model (ResNet-18 example) ```shell python test.py --arch resnet18 --resume_path output-resnet18-bn-pr05/ckpt_best.pth ``` ***-all-bn*** refers to L1 sparsity on all BN layers ## Inference with [OpenVINO](https://software.intel.com/en-us/openvino-toolkit) The efficiency of pruned model can be further improved by using OpenVINO, if you are working with Intel processors/accelerators. 1. Download OpenVINO from the official website [OpenVINO](https://software.intel.com/en-us/openvino-toolkit). 2. After installation, initialize the environment: ```shell source /opt/intel/openvino/bin/setupvars.sh ``` 3. Take simplified VGG-11 as an example, after finished running *experiment-vgg11s.sh*, convert pruned model to OpenVINO IR: ```shell python export2openvino.py --arch vgg11s --weights output-vgg11s-bn-pr05/ckpt_best.pth --outname vgg11s-pr05 python export2openvino.py --arch vgg11s --weights output-vgg11s-bn-pr05/ckpt_best.pth --outname vgg11s-pr05 --fp16 ``` 4. Test with CIFAR-100 ```shell python test-openvino.py vgg11s-FP32 python test-openvino.py vgg11s-FP16 ``` 5. Compare runtime ```shell python cpu-runtime-benchmark-vgg11s.py ``` On a desktop with Xeon 8160 CPU, the FPS results are: | PyTorch Full Model | PyTorch PR=0.5 | OpenVINO PR=0.5 FP32 | OpenVINO PR=0.5 FP16 | | :----------------: | :------------: | :------------------: | :------------------: | | 89.50 | 146.21 | 960.49 | 973.29 | ## Acknowledgement The implementation of ***udpate_bn*** is referred to [pytorch-slimming](https://github.com/foolwood/pytorch-slimming).