├── .dockerignore ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── admm.py ├── cfg ├── csdarknet53s-panet-spp.cfg ├── darknet_admm.yaml └── darknet_retrain.yaml ├── check_compression.py ├── data ├── coco.names ├── coco1.data ├── coco1.txt ├── coco16.data ├── coco16.txt ├── coco1cls.data ├── coco1cls.txt ├── coco2014.data ├── coco2017.data ├── coco64.data ├── coco64.txt ├── coco_paper.names ├── get_coco2014.sh ├── get_coco2017.sh └── samples │ ├── bus.jpg │ └── zidane.jpg ├── detect.py ├── figure ├── yolo_demo.jpg └── yolobilemap.png ├── model_pruned └── .gitkeep ├── model_retrained └── .gitkeep ├── models.py ├── prune_config ├── config_csdarknet53pan_avgv8.yaml ├── config_csdarknet53pan_slv8.yaml ├── config_csdarknet53pan_v10.yaml ├── config_csdarknet53pan_v14.yaml ├── config_csdarknet53pan_v2.yaml ├── config_csdarknet53pan_v4.yaml └── config_csdarknet53pan_v8.yaml ├── requirements.txt ├── runprune.sh ├── test.py ├── testers.py ├── train.py ├── utils ├── __init__.py ├── adabound.py ├── checkfile.py ├── cleanfile.py ├── datasets.py ├── evolve.sh ├── gcp.sh ├── google_utils.py ├── layers.py ├── parse_config.py ├── profile_local.py ├── torch_utils.py └── utils.py └── weights └── download_yolov3_weights.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | # Repo-specific DockerIgnore ------------------------------------------------------------------------------------------- 2 | # .git 3 | .cache 4 | .idea 5 | runs 6 | output 7 | coco 8 | storage.googleapis.com 9 | 10 | data/samples/* 11 | !data/samples/zidane.jpg 12 | !data/samples/bus.jpg 13 | **/results*.txt 14 | *.jpg 15 | 16 | # Neural Network weights ----------------------------------------------------------------------------------------------- 17 | **/*.weights 18 | # **/*.pt 19 | **/*.onnx 20 | **/*.mlmodel 21 | **/darknet53.conv.74 22 | **/yolov3-tiny.conv.15 23 | 24 | 25 | # Below Copied From .gitignore ----------------------------------------------------------------------------------------- 26 | # Below Copied From .gitignore ----------------------------------------------------------------------------------------- 27 | 28 | 29 | # GitHub Python GitIgnore ---------------------------------------------------------------------------------------------- 30 | # Byte-compiled / optimized / DLL files 31 | __pycache__/ 32 | *.py[cod] 33 | *$py.class 34 | 35 | # C extensions 36 | *.so 37 | 38 | # Distribution / packaging 39 | .Python 40 | env/ 41 | build/ 42 | develop-eggs/ 43 | dist/ 44 | downloads/ 45 | eggs/ 46 | .eggs/ 47 | lib/ 48 | lib64/ 49 | parts/ 50 | sdist/ 51 | var/ 52 | wheels/ 53 | *.egg-info/ 54 | .installed.cfg 55 | *.egg 56 | 57 | # PyInstaller 58 | # Usually these files are written by a python script from a template 59 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 60 | *.manifest 61 | *.spec 62 | 63 | # Installer logs 64 | pip-log.txt 65 | pip-delete-this-directory.txt 66 | 67 | # Unit test / coverage reports 68 | htmlcov/ 69 | .tox/ 70 | .coverage 71 | .coverage.* 72 | .cache 73 | nosetests.xml 74 | coverage.xml 75 | *.cover 76 | .hypothesis/ 77 | 78 | # Translations 79 | *.mo 80 | *.pot 81 | 82 | # Django stuff: 83 | *.log 84 | local_settings.py 85 | 86 | # Flask stuff: 87 | instance/ 88 | .webassets-cache 89 | 90 | # Scrapy stuff: 91 | .scrapy 92 | 93 | # Sphinx documentation 94 | docs/_build/ 95 | 96 | # PyBuilder 97 | target/ 98 | 99 | # Jupyter Notebook 100 | .ipynb_checkpoints 101 | 102 | # pyenv 103 | .python-version 104 | 105 | # celery beat schedule file 106 | celerybeat-schedule 107 | 108 | # SageMath parsed files 109 | *.sage.py 110 | 111 | # dotenv 112 | .env 113 | 114 | # virtualenv 115 | .venv 116 | venv/ 117 | ENV/ 118 | 119 | # Spyder project settings 120 | .spyderproject 121 | .spyproject 122 | 123 | # Rope project settings 124 | .ropeproject 125 | 126 | # mkdocs documentation 127 | /site 128 | 129 | # mypy 130 | .mypy_cache/ 131 | 132 | 133 | # https://github.com/github/gitignore/blob/master/Global/macOS.gitignore ----------------------------------------------- 134 | 135 | # General 136 | .DS_Store 137 | .AppleDouble 138 | .LSOverride 139 | 140 | # Icon must end with two \r 141 | Icon 142 | Icon? 143 | 144 | # Thumbnails 145 | ._* 146 | 147 | # Files that might appear in the root of a volume 148 | .DocumentRevisions-V100 149 | .fseventsd 150 | .Spotlight-V100 151 | .TemporaryItems 152 | .Trashes 153 | .VolumeIcon.icns 154 | .com.apple.timemachine.donotpresent 155 | 156 | # Directories potentially created on remote AFP share 157 | .AppleDB 158 | .AppleDesktop 159 | Network Trash Folder 160 | Temporary Items 161 | .apdisk 162 | 163 | 164 | # https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore 165 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 166 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 167 | 168 | # User-specific stuff: 169 | .idea/* 170 | .idea/**/workspace.xml 171 | .idea/**/tasks.xml 172 | .idea/dictionaries 173 | .html # Bokeh Plots 174 | .pg # TensorFlow Frozen Graphs 175 | .avi # videos 176 | 177 | # Sensitive or high-churn files: 178 | .idea/**/dataSources/ 179 | .idea/**/dataSources.ids 180 | .idea/**/dataSources.local.xml 181 | .idea/**/sqlDataSources.xml 182 | .idea/**/dynamic.xml 183 | .idea/**/uiDesigner.xml 184 | 185 | # Gradle: 186 | .idea/**/gradle.xml 187 | .idea/**/libraries 188 | 189 | # CMake 190 | cmake-build-debug/ 191 | cmake-build-release/ 192 | 193 | # Mongo Explorer plugin: 194 | .idea/**/mongoSettings.xml 195 | 196 | ## File-based project format: 197 | *.iws 198 | 199 | ## Plugin-specific files: 200 | 201 | # IntelliJ 202 | out/ 203 | 204 | # mpeltonen/sbt-idea plugin 205 | .idea_modules/ 206 | 207 | # JIRA plugin 208 | atlassian-ide-plugin.xml 209 | 210 | # Cursive Clojure plugin 211 | .idea/replstate.xml 212 | 213 | # Crashlytics plugin (for Android Studio and IntelliJ) 214 | com_crashlytics_export_strings.xml 215 | crashlytics.properties 216 | crashlytics-build.properties 217 | fabric.properties 218 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Repo-specific GitIgnore ---------------------------------------------------------------------------------------------- 2 | *.jpg 3 | *.jpeg 4 | *.png 5 | *.bmp 6 | *.tif 7 | *.tiff 8 | *.heic 9 | *.JPG 10 | *.JPEG 11 | *.PNG 12 | *.BMP 13 | *.TIF 14 | *.TIFF 15 | *.HEIC 16 | *.mp4 17 | *.mov 18 | *.MOV 19 | *.avi 20 | *.data 21 | *.json 22 | 23 | *.cfg 24 | !cfg/yolov3*.cfg 25 | 26 | storage.googleapis.com 27 | runs/* 28 | data/* 29 | !data/samples/zidane.jpg 30 | !data/samples/bus.jpg 31 | !data/coco.names 32 | !data/coco_paper.names 33 | !data/coco.data 34 | !data/coco_*.data 35 | !data/coco_*.txt 36 | !data/trainvalno5k.shapes 37 | !data/*.sh 38 | 39 | pycocotools/* 40 | results*.txt 41 | gcp_test*.sh 42 | 43 | # MATLAB GitIgnore ----------------------------------------------------------------------------------------------------- 44 | *.m~ 45 | *.mat 46 | !targets*.mat 47 | 48 | # Neural Network weights ----------------------------------------------------------------------------------------------- 49 | *.weights 50 | *.pt 51 | *.onnx 52 | *.mlmodel 53 | darknet53.conv.74 54 | yolov3-tiny.conv.15 55 | 56 | # GitHub Python GitIgnore ---------------------------------------------------------------------------------------------- 57 | # Byte-compiled / optimized / DLL files 58 | __pycache__/ 59 | *.py[cod] 60 | *$py.class 61 | 62 | # C extensions 63 | *.so 64 | 65 | # Distribution / packaging 66 | .Python 67 | env/ 68 | build/ 69 | develop-eggs/ 70 | dist/ 71 | downloads/ 72 | eggs/ 73 | .eggs/ 74 | lib/ 75 | lib64/ 76 | parts/ 77 | sdist/ 78 | var/ 79 | wheels/ 80 | *.egg-info/ 81 | .installed.cfg 82 | *.egg 83 | 84 | # PyInstaller 85 | # Usually these files are written by a python script from a template 86 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 87 | *.manifest 88 | *.spec 89 | 90 | # Installer logs 91 | pip-log.txt 92 | pip-delete-this-directory.txt 93 | 94 | # Unit test / coverage reports 95 | htmlcov/ 96 | .tox/ 97 | .coverage 98 | .coverage.* 99 | .cache 100 | nosetests.xml 101 | coverage.xml 102 | *.cover 103 | .hypothesis/ 104 | 105 | # Translations 106 | *.mo 107 | *.pot 108 | 109 | # Django stuff: 110 | *.log 111 | local_settings.py 112 | 113 | # Flask stuff: 114 | instance/ 115 | .webassets-cache 116 | 117 | # Scrapy stuff: 118 | .scrapy 119 | 120 | # Sphinx documentation 121 | docs/_build/ 122 | 123 | # PyBuilder 124 | target/ 125 | 126 | # Jupyter Notebook 127 | .ipynb_checkpoints 128 | 129 | # pyenv 130 | .python-version 131 | 132 | # celery beat schedule file 133 | celerybeat-schedule 134 | 135 | # SageMath parsed files 136 | *.sage.py 137 | 138 | # dotenv 139 | .env 140 | 141 | # virtualenv 142 | .venv 143 | venv/ 144 | ENV/ 145 | 146 | # Spyder project settings 147 | .spyderproject 148 | .spyproject 149 | 150 | # Rope project settings 151 | .ropeproject 152 | 153 | # mkdocs documentation 154 | /site 155 | 156 | # mypy 157 | .mypy_cache/ 158 | 159 | 160 | # https://github.com/github/gitignore/blob/master/Global/macOS.gitignore ----------------------------------------------- 161 | 162 | # General 163 | .DS_Store 164 | .AppleDouble 165 | .LSOverride 166 | 167 | # Icon must end with two \r 168 | Icon 169 | Icon? 170 | 171 | # Thumbnails 172 | ._* 173 | 174 | # Files that might appear in the root of a volume 175 | .DocumentRevisions-V100 176 | .fseventsd 177 | .Spotlight-V100 178 | .TemporaryItems 179 | .Trashes 180 | .VolumeIcon.icns 181 | .com.apple.timemachine.donotpresent 182 | 183 | # Directories potentially created on remote AFP share 184 | .AppleDB 185 | .AppleDesktop 186 | Network Trash Folder 187 | Temporary Items 188 | .apdisk 189 | 190 | 191 | # https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore 192 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 193 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 194 | 195 | # User-specific stuff: 196 | .idea/* 197 | .idea/**/workspace.xml 198 | .idea/**/tasks.xml 199 | .idea/dictionaries 200 | .html # Bokeh Plots 201 | .pg # TensorFlow Frozen Graphs 202 | .avi # videos 203 | 204 | # Sensitive or high-churn files: 205 | .idea/**/dataSources/ 206 | .idea/**/dataSources.ids 207 | .idea/**/dataSources.local.xml 208 | .idea/**/sqlDataSources.xml 209 | .idea/**/dynamic.xml 210 | .idea/**/uiDesigner.xml 211 | 212 | # Gradle: 213 | .idea/**/gradle.xml 214 | .idea/**/libraries 215 | 216 | # CMake 217 | cmake-build-debug/ 218 | cmake-build-release/ 219 | 220 | # Mongo Explorer plugin: 221 | .idea/**/mongoSettings.xml 222 | 223 | ## File-based project format: 224 | *.iws 225 | 226 | ## Plugin-specific files: 227 | 228 | # IntelliJ 229 | out/ 230 | 231 | # mpeltonen/sbt-idea plugin 232 | .idea_modules/ 233 | 234 | # JIRA plugin 235 | atlassian-ide-plugin.xml 236 | 237 | # Cursive Clojure plugin 238 | .idea/replstate.xml 239 | 240 | # Crashlytics plugin (for Android Studio and IntelliJ) 241 | com_crashlytics_export_strings.xml 242 | crashlytics.properties 243 | crashlytics-build.properties 244 | fabric.properties 245 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Start FROM Nvidia PyTorch image https://ngc.nvidia.com/catalog/containers/nvidia:pytorch 2 | FROM nvcr.io/nvidia/pytorch:20.03-py3 3 | 4 | # Install dependencies (pip or conda) 5 | RUN pip install -U gsutil thop 6 | #RUN pip install -U -r requirements.txt 7 | # RUN conda update -n base -c defaults conda 8 | # RUN conda install -y -c anaconda future numpy opencv matplotlib tqdm pillow 9 | # RUN conda install -y -c conda-forge scikit-image tensorboard pycocotools 10 | 11 | ## Install OpenCV with Gstreamer support 12 | #WORKDIR /usr/src 13 | #RUN pip uninstall -y opencv-python 14 | #RUN apt-get update 15 | #RUN apt-get install -y gstreamer1.0-tools gstreamer1.0-python3-dbg-plugin-loader libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev 16 | #RUN git clone https://github.com/opencv/opencv.git && cd opencv && git checkout 4.1.1 && mkdir build 17 | #RUN git clone https://github.com/opencv/opencv_contrib.git && cd opencv_contrib && git checkout 4.1.1 18 | #RUN cd opencv/build && cmake ../ \ 19 | # -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \ 20 | # -D BUILD_OPENCV_PYTHON3=ON \ 21 | # -D PYTHON3_EXECUTABLE=/opt/conda/bin/python \ 22 | # -D PYTHON3_INCLUDE_PATH=/opt/conda/include/python3.6m \ 23 | # -D PYTHON3_LIBRARIES=/opt/conda/lib/python3.6/site-packages \ 24 | # -D WITH_GSTREAMER=ON \ 25 | # -D WITH_FFMPEG=OFF \ 26 | # && make && make install && ldconfig 27 | #RUN cd /usr/local/lib/python3.6/site-packages/cv2/python-3.6/ && mv cv2.cpython-36m-x86_64-linux-gnu.so cv2.so 28 | #RUN cd /opt/conda/lib/python3.6/site-packages/ && ln -s /usr/local/lib/python3.6/site-packages/cv2/python-3.6/cv2.so cv2.so 29 | #RUN python3 -c "import cv2; print(cv2.getBuildInformation())" 30 | 31 | # Create working directory 32 | RUN mkdir -p /usr/src/app 33 | WORKDIR /usr/src/app 34 | 35 | # Copy contents 36 | COPY . /usr/src/app 37 | 38 | # Copy weights 39 | #RUN python3 -c "from models import *; \ 40 | #attempt_download('weights/yolov3.pt'); \ 41 | #attempt_download('weights/yolov3-spp.pt')" 42 | 43 | 44 | # --------------------------------------------------- Extras Below --------------------------------------------------- 45 | 46 | # Build and Push 47 | # t=yoloadmm && sudo docker build -t $t . 48 | 49 | # Run 50 | # t=yoloadmm && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host $t bash 51 | 52 | # Pull and Run with local directory access 53 | # t=yoloadmm && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash 54 | 55 | # Kill all 56 | # sudo docker kill "$(sudo docker ps -q)" 57 | 58 | # Kill all image-based 59 | # sudo docker kill $(sudo docker ps -a -q --filter ancestor=ultralytics/yolov3:v0) 60 | 61 | # Run bash for loop 62 | # sudo docker run --gpus all --ipc=host ultralytics/yolov3:v0 while true; do python3 train.py --evolve; done 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # YOLObile 4 | This is the implementation of [YOLObile: Real-Time Object Detection on Mobile Devices via Compression-Compilation Co-Design](https://arxiv.org/abs/2009.05697) using [ultralytics/yolov3](https://github.com/ultralytics/yolov3). Thanks to the original author. 5 | 6 | arXiv: [https://arxiv.org/abs/2009.05697](https://arxiv.org/abs/2009.05697) 7 | In Proceeding in AAAI 2021 8 | 9 | **For those who may be interested in the compiler code (How to deploy it onto Android?):** The compiler source code is associated with our collaborator at William & Mary, and has joint IP related stuff. **We have no plans to open source this part now.** Sorry for the inconvenience. 10 | 11 | **For IOS developer:** We only use Android platform to build and test the compiler because of the advantages of highly open source. We also believe the same techniques can be applied on Apple IOS platform, but we haven't tested it yet. 12 | 13 | ![Image of YOLObile](figure/yolo_demo.jpg) 14 | 15 | 16 | 17 | ## Introduction 18 | The rapid development and wide utilization of object detection techniques have aroused attention on both accuracy and speed of object detectors. However, the current state-of-the-art object detection works are either accuracy-oriented using a large model but leading to high latency 19 | or speed-oriented using a lightweight model but sacrificing accuracy. In this work, we propose YOLObile framework, a real-time object detection on mobile devices via compression-compilation co-design. A novel block-punched pruning scheme is proposed for any kernel size. To improve computational efficiency on mobile devices, a GPU-CPU collaborative scheme is adopted along with advanced compiler-assisted optimizations. Experimental results indicate that our pruning scheme achieves 14x compression rate of YOLOv4 with 49.0 mAP. 20 | Under our YOLObile framework, we achieve 17 FPS inference speed using GPU on Samsung Galaxy S20. 21 | By incorporating our proposed GPU-CPU collaborative scheme, the inference speed is increased to 19.1 FPS, and outperforms the original YOLOv4 by 5x speedup. 22 | 23 | ## Environments 24 | Python 3.7 or later with all `pip install -U -r requirements.txt` packages including `torch == 1.4`. Docker images come with all dependencies preinstalled. Docker requirements are: 25 | - Nvidia Driver >= 440.44 26 | - Docker Engine - CE >= 19.03 27 | 28 | ### Download Coco Dataset: (18 GB) 29 | ```shell script 30 | cd ../ && sh YOLObile/data/get_coco2014.sh 31 | ``` 32 | The default path for coco data folder is outside the project root folder. 33 | 34 | ``` shell script 35 | /Project 36 | /Project/YOLObile (Project root) 37 | /Project/coco (coco data) 38 | ``` 39 | 40 | ### Download Model Checkpoints: 41 | Google Drive: [Google Drive Download](https://drive.google.com/drive/folders/10FRZo9WC1vZA1w6xxysgjptQmbqk3Sz3?usp=sharing) 42 | 43 | Baidu Netdisk: [Baidu Netdisk Download](https://pan.baidu.com/s/1FMTOQF6ebH6OJWEAq9F0KQ) code: r3nk 44 | 45 | After downloads, please put the weight file under ./weights folder 46 | 47 | 48 | ## Docker build instructions 49 | 50 | ### 1. Install Docker and Nvidia-Docker 51 | 52 | Docker images come with all dependencies preinstalled, however Docker itself requires installation, and relies of nvidia driver installations in order to interact properly with local GPU resources. The requirements are: 53 | - Nvidia Driver >= 440.44 https://www.nvidia.com/Download/index.aspx 54 | - Nvidia-Docker https://github.com/NVIDIA/nvidia-docker 55 | - Docker Engine - CE >= 19.03 https://docs.docker.com/install/ 56 | 57 | ### 2. Build the project 58 | ```bash 59 | # Build and Push 60 | t=YOLObile && sudo docker build -t $t . 61 | ``` 62 | 63 | ### 3. Run Container 64 | ```bash 65 | # Pull and Run with local directory access 66 | t=YOLObile && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"your/cocodata/path:/usr/src/coco $t bash 67 | ``` 68 | 69 | ### 4. Run Commands 70 | Once the container is launched and you are inside it, you will have a terminal window in which you can run all regular bash commands, such as: 71 | - `ls .` 72 | - `ls ../coco` 73 | - `python train.py` 74 | - `python test.py` 75 | - `python detect.py` 76 | 77 | ## Configurations: 78 | 79 | **Train Options and Model Config:** 80 | ``` 81 | ./cfg/csdarknet53s-panet-spp.cfg (model configuration) 82 | ./cfg/darknet_admm.yaml (pruning configuration) 83 | ./cfg/darknet_retrain.yaml (retrain configuration) 84 | ``` 85 | 86 | **Weights:** 87 | ``` 88 | ./weights/yolov4dense.pt (dense model) 89 | ./weights/best8x-514.pt (pruned model) 90 | ``` 91 | 92 | **Prune Config** 93 | ``` 94 | ./prune_config/config_csdarknet53pan_v*.yaml 95 | ``` 96 | 97 | ## Training 98 | 99 | The training process includes two steps: 100 | 101 | **Pruning:** `python train.py --img-size 320 --batch-size 64 --device 0,1,2,3 --epoch 25 --admm-file darknet_admm --cfg cfg/csdarknet53s-panet-spp.cfg --weights weights/yolov4dense.pt --data data/coco2014.data` 102 | 103 | The pruning process does **NOT** support resume. 104 | 105 | **Masked Retrain:** `python train.py --img-size 320 --batch-size 64 --device 0,1,2,3 --epoch 280 --admm-file darknet_retrain --cfg cfg/csdarknet53s-panet-spp.cfg --weights weights/yolov4dense.pt --data data/coco2014.data --multi-scale`. 106 | 107 | The masked retrain process support resume. 108 | 109 | You can run the total process via `sh ./runprune.sh` 110 | 111 | 112 | 113 | ## Check model Weight Parameters & Flops: 114 | ```shell script 115 | python check_compression.py 116 | ``` 117 | ## Test model MAP: 118 | 119 | ```shell script 120 | python test.py --img-size 320 --batch-size 64 --device 0 --cfg cfg/csdarknet53s-panet-spp.cfg --weights weights/best8x-514.pt --data data/coco2014.data 121 | 122 | ``` 123 | ``` 124 | Class Images Targets P R mAP@0.5 F1: 100%|| 79/79 [00: 125 | all 5e+03 3.51e+04 0.501 0.544 0.508 0.512 126 | person 5e+03 1.05e+04 0.643 0.697 0.698 0.669 127 | bicycle 5e+03 313 0.464 0.409 0.388 0.435 128 | car 5e+03 1.64e+03 0.492 0.547 0.503 0.518 129 | motorcycle 5e+03 388 0.602 0.635 0.623 0.618 130 | airplane 5e+03 131 0.676 0.786 0.804 0.727 131 | bus 5e+03 259 0.67 0.788 0.792 0.724 132 | train 5e+03 212 0.731 0.797 0.805 0.763 133 | truck 5e+03 352 0.414 0.526 0.475 0.463 134 | toothbrush 5e+03 77 0.35 0.301 0.269 0.323 135 | Speed: 3.6/1.4/5.0 ms inference/NMS/total per 320x320 image at batch-size 64 136 | 137 | COCO mAP with pycocotools... 138 | loading annotations into memory... 139 | Done (t=3.87s) 140 | creating index... 141 | index created! 142 | Loading and preparing results... 143 | DONE (t=3.74s) 144 | creating index... 145 | index created! 146 | Running per image evaluation... 147 | Evaluate annotation type *bbox* 148 | DONE (t=83.06s). 149 | Accumulating evaluation results... 150 | DONE (t=9.39s). 151 | Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.334 152 | Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.514 153 | Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.350 154 | Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.117 155 | Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.374 156 | Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.519 157 | Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.295 158 | Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.466 159 | Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.504 160 | Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.240 161 | Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.583 162 | Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.727 163 | ``` 164 | 165 | ## FPS vs mAP on COCO dataset 166 | ![Image of YOLObile](figure/yolobilemap.png) 167 | 168 | 169 | ## Already Known Issues 170 | - The accuracy printed in retraining process is not accurate. Please run the test.py individually to check the accuracy. I raised this issue in the old versions of Ultralytics/YOLOv3 repository, and I am not sure if they had already solved yet. 171 | 172 | 173 | - When you use multi-card training(4 cards or more ), the training process may stop after a few hours without any errors printed. 174 | I suggest using docker instead if you use 4 cards or more. The docker build instructions can be found above. 175 | 176 | - Pytorch 1.5+ might have multi card issues 177 | 178 | ## Acknowledgements 179 | [https://github.com/ultralytics/yolov3](https://github.com/ultralytics/yolov3) 180 | 181 | [https://github.com/AlexeyAB/darknet](https://github.com/AlexeyAB/darknet) 182 | 183 | ## Contact Me 184 | Github: [https://github.com/nightsnack](https://github.com/nightsnack) 185 | 186 | Email : nightsnackc@gmail.com 187 | -------------------------------------------------------------------------------- /admm.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import torch 3 | import math 4 | import torch.nn as nn 5 | import torch.nn.functional as F 6 | from torch.optim.lr_scheduler import _LRScheduler 7 | import operator 8 | from numpy import linalg as LA 9 | import numpy as np 10 | import yaml 11 | import random 12 | # from testers import * 13 | 14 | 15 | class ADMM: 16 | def __init__(self, model, file_name, rho=0.001): 17 | self.ADMM_U = {} 18 | self.ADMM_Z = {} 19 | self.rho = rho 20 | self.rhos = {} 21 | 22 | self.init(file_name, model) 23 | 24 | def init(self, config, model): 25 | """ 26 | Args: 27 | config: configuration file that has settings for prune ratios, rhos 28 | called by ADMM constructor. config should be a .yaml file 29 | 30 | """ 31 | if not isinstance(config, str): 32 | raise Exception("filename must be a str") 33 | with open(config, "r") as stream: 34 | try: 35 | raw_dict = yaml.load(stream, Loader=yaml.FullLoader) 36 | self.prune_ratios = raw_dict['prune_ratios'] 37 | for k, v in self.prune_ratios.items(): 38 | self.rhos[k] = self.rho 39 | for (name, W) in model.module.named_parameters() if type( 40 | model) is nn.parallel.DistributedDataParallel else model.named_parameters(): 41 | if name not in self.prune_ratios: 42 | continue 43 | self.ADMM_U[name] = torch.zeros(W.shape).cuda() # add U 44 | self.ADMM_Z[name] = torch.Tensor(W.shape).cuda() # add Z 45 | # if(len(W.size()) == 4): 46 | # if name not in self.prune_ratios: 47 | # continue 48 | # self.ADMM_U[name] = torch.zeros(W.shape).cuda() # add U 49 | # self.ADMM_Z[name] = torch.Tensor(W.shape).cuda() # add Z 50 | 51 | 52 | except yaml.YAMLError as exc: 53 | print(exc) 54 | 55 | def adjust_rho(self, new_rho): 56 | self.rho = new_rho 57 | for k, v in self.prune_ratios.items(): 58 | self.rhos[k] = self.rho 59 | 60 | def random_pruning(args, weight, prune_ratio): 61 | weight = weight.cpu().detach().numpy() # convert cpu tensor to numpy 62 | 63 | if (args.sparsity_type == "filter"): 64 | shape = weight.shape 65 | weight2d = weight.reshape(shape[0], -1) 66 | shape2d = weight2d.shape 67 | indices = np.random.choice(shape2d[0], int(shape2d[0] * prune_ratio), replace=False) 68 | weight2d[indices, :] = 0 69 | weight = weight2d.reshape(shape) 70 | expand_above_threshold = np.zeros(shape2d, dtype=np.float32) 71 | for i in range(shape2d[0]): 72 | expand_above_threshold[i, :] = i not in indices 73 | weight = weight2d.reshape(shape) 74 | expand_above_threshold = expand_above_threshold.reshape(shape) 75 | return torch.from_numpy(expand_above_threshold).cuda(), torch.from_numpy(weight).cuda() 76 | else: 77 | raise Exception("not implemented yet") 78 | 79 | 80 | def L1_pruning(args, weight, prune_ratio): 81 | """ 82 | projected gradient descent for comparison 83 | 84 | """ 85 | percent = prune_ratio * 100 86 | weight = weight.cpu().detach().numpy() # convert cpu tensor to numpy 87 | shape = weight.shape 88 | weight2d = weight.reshape(shape[0], -1) 89 | shape2d = weight2d.shape 90 | row_l1_norm = LA.norm(weight2d, 1, axis=1) 91 | percentile = np.percentile(row_l1_norm, percent) 92 | under_threshold = row_l1_norm < percentile 93 | above_threshold = row_l1_norm > percentile 94 | weight2d[under_threshold, :] = 0 95 | above_threshold = above_threshold.astype(np.float32) 96 | expand_above_threshold = np.zeros(shape2d, dtype=np.float32) 97 | for i in range(shape2d[0]): 98 | expand_above_threshold[i, :] = above_threshold[i] 99 | weight = weight.reshape(shape) 100 | expand_above_threshold = expand_above_threshold.reshape(shape) 101 | return torch.from_numpy(expand_above_threshold).cuda(), torch.from_numpy(weight).cuda() 102 | 103 | 104 | def weight_pruning(args, weight, prune_ratio, cross_x=4, cross_f=1): 105 | """ 106 | weight pruning [irregular,column,filter] 107 | Args: 108 | weight (pytorch tensor): weight tensor, ordered by output_channel, intput_channel, kernel width and kernel height 109 | prune_ratio (float between 0-1): target sparsity of weights 110 | 111 | Returns: 112 | mask for nonzero weights used for retraining 113 | a pytorch tensor whose elements/column/row that have lowest l2 norms(equivalent to absolute weight here) are set to zero 114 | 115 | """ 116 | 117 | weight = weight.cpu().detach().numpy() # convert cpu tensor to numpy 118 | 119 | percent = prune_ratio * 100 120 | if (args.sparsity_type == "irregular"): 121 | weight_temp = np.abs(weight) # a buffer that holds weights with absolute values 122 | percentile = np.percentile(weight_temp, percent) # get a value for this percentitle 123 | under_threshold = weight_temp < percentile 124 | above_threshold = weight_temp > percentile 125 | above_threshold = above_threshold.astype( 126 | np.float32) # has to convert bool to float32 for numpy-tensor conversion 127 | weight[under_threshold] = 0 128 | return torch.from_numpy(above_threshold).cuda(), torch.from_numpy(weight).cuda() 129 | elif (args.sparsity_type == "column"): 130 | shape = weight.shape 131 | weight2d = weight.reshape(shape[0], -1) 132 | shape2d = weight2d.shape 133 | column_l2_norm = LA.norm(weight2d, 2, axis=0) 134 | percentile = np.percentile(column_l2_norm, percent) 135 | under_threshold = column_l2_norm < percentile 136 | above_threshold = column_l2_norm > percentile 137 | weight2d[:, under_threshold] = 0 138 | above_threshold = above_threshold.astype(np.float32) 139 | expand_above_threshold = np.zeros(shape2d, dtype=np.float32) 140 | for i in range(shape2d[1]): 141 | expand_above_threshold[:, i] = above_threshold[i] 142 | expand_above_threshold = expand_above_threshold.reshape(shape) 143 | weight = weight.reshape(shape) 144 | return torch.from_numpy(expand_above_threshold).cuda(), torch.from_numpy(weight).cuda() 145 | elif (args.sparsity_type == "filter"): 146 | shape = weight.shape 147 | weight2d = weight.reshape(shape[0], -1) 148 | shape2d = weight2d.shape 149 | row_l2_norm = LA.norm(weight2d, 2, axis=1) 150 | percentile = np.percentile(row_l2_norm, percent) 151 | under_threshold = row_l2_norm <= percentile 152 | above_threshold = row_l2_norm > percentile 153 | weight2d[under_threshold, :] = 0 154 | # weight2d[weight2d < 1e-40] = 0 155 | above_threshold = above_threshold.astype(np.float32) 156 | expand_above_threshold = np.zeros(shape2d, dtype=np.float32) 157 | for i in range(shape2d[0]): 158 | expand_above_threshold[i, :] = above_threshold[i] 159 | weight = weight.reshape(shape) 160 | expand_above_threshold = expand_above_threshold.reshape(shape) 161 | return torch.from_numpy(expand_above_threshold).cuda(), torch.from_numpy(weight).cuda() 162 | 163 | elif (args.sparsity_type == "block-punched"): # xuan shen 164 | shape = weight.shape 165 | weight2d = weight.reshape(shape[0], -1) 166 | shape2d = weight2d.shape 167 | # print(shape, shape2d) 168 | 169 | length_f = 8 # this is the block size, it could be 16 or 8 170 | num_channel_in_every_block = 4 171 | kernel_s1d = shape[2]*shape[3] 172 | length_x = kernel_s1d * num_channel_in_every_block # kernel size = 3 173 | 174 | if shape2d[0] % length_f != 0 or shape2d[1] % length_x != 0: 175 | print("the layer size is not divisible") 176 | # return torch.from_numpy(np.array([])).cuda(), torch.from_numpy(weight).cuda() 177 | raise SyntaxError("block_size error") 178 | 179 | cross_f = int(shape2d[0] / length_f) 180 | cross_x = int(shape2d[1] / length_x) 181 | 182 | # this function will not use the reorder method 183 | l2_norm_record = np.zeros((cross_f, cross_x * kernel_s1d)) 184 | for i in range(cross_f): 185 | for j in range(cross_x): 186 | block = weight2d[i * length_f: (i + 1) * length_f, j * length_x: (j + 1) * length_x] 187 | block_l2_norm = LA.norm(block, 2, axis=0) 188 | for k in range(kernel_s1d): 189 | for c in range(num_channel_in_every_block): 190 | l2_norm_record[i, j * kernel_s1d + k] += block_l2_norm[k + c * kernel_s1d] # there are 4 channels in every block 191 | 192 | percentile = np.percentile(l2_norm_record, percent) 193 | # under_threshold = l2_norm_record <= percentile 194 | above_threshold = l2_norm_record > percentile 195 | 196 | expand_above_threshold = np.zeros(shape2d, dtype=np.float32) 197 | temp_mat_inexpand_0 = np.zeros(length_f) 198 | temp_mat_inexpand_1 = np.ones(length_f) 199 | 200 | for i in range(cross_f): 201 | for j in range(cross_x): 202 | # block = weight2d[i*length_f : (i+1)*length_f, j*length_x : (j+1)*length_x] 203 | for k in range(kernel_s1d): 204 | if above_threshold[i, kernel_s1d * j + k]: 205 | for c in range(num_channel_in_every_block): 206 | expand_above_threshold[i * length_f: (i + 1) * length_f, 207 | j * length_x + k + kernel_s1d * c] = temp_mat_inexpand_1 208 | else: 209 | for c in range(num_channel_in_every_block): 210 | weight2d[i * length_f: (i + 1) * length_f, j * length_x + k + kernel_s1d * c] = temp_mat_inexpand_0 211 | 212 | weight = weight.reshape(shape) 213 | expand_above_threshold = expand_above_threshold.reshape(shape) 214 | return torch.from_numpy(expand_above_threshold).cuda(), torch.from_numpy(weight).cuda() 215 | #################################### 216 | elif (args.sparsity_type == "pattern"): 217 | print("pattern pruning...", weight.shape) 218 | shape = weight.shape 219 | 220 | pattern1 = [[0, 0], [0, 2], [2, 0], [2, 2]] 221 | pattern2 = [[0, 0], [0, 1], [2, 1], [2, 2]] 222 | pattern3 = [[0, 0], [0, 1], [2, 0], [2, 1]] 223 | pattern4 = [[0, 0], [0, 1], [1, 0], [1, 1]] 224 | 225 | pattern5 = [[0, 2], [1, 0], [1, 2], [2, 0]] 226 | pattern6 = [[0, 0], [1, 0], [1, 2], [2, 2]] 227 | pattern7 = [[0, 1], [0, 2], [2, 0], [2, 1]] 228 | pattern8 = [[0, 1], [0, 2], [2, 1], [2, 2]] 229 | 230 | pattern9 = [[1, 0], [1, 2], [2, 0], [2, 2]] 231 | pattern10 = [[0, 0], [0, 2], [1, 0], [1, 2]] 232 | pattern11 = [[1, 1], [1, 2], [2, 1], [2, 2]] 233 | pattern12 = [[1, 0], [1, 1], [2, 0], [2, 1]] 234 | pattern13 = [[0, 1], [0, 2], [1, 1], [1, 2]] 235 | 236 | patterns_dict = {1 : pattern1, 237 | 2 : pattern2, 238 | 3 : pattern3, 239 | 4 : pattern4, 240 | 5 : pattern5, 241 | 6 : pattern6, 242 | 7 : pattern7, 243 | 8 : pattern8, 244 | 9 : pattern9, 245 | 10 : pattern10, 246 | 11 : pattern11, 247 | 12 : pattern12, 248 | 13 : pattern13 249 | } 250 | 251 | for i in range(shape[0]): 252 | for j in range(shape[1]): 253 | current_kernel = weight[i, j, :, :].copy() 254 | temp_dict = {} # store each pattern's norm value on the same weight kernel 255 | for key, pattern in patterns_dict.items(): 256 | temp_kernel = current_kernel.copy() 257 | for index in pattern: 258 | temp_kernel[index[0], index[1]] = 0 259 | current_norm = LA.norm(temp_kernel) 260 | temp_dict[key] = current_norm 261 | best_pattern = max(temp_dict.items(), key=operator.itemgetter(1))[0] 262 | # print(best_pattern) 263 | for index in patterns_dict[best_pattern]: 264 | weight[i, j, index[0], index[1]] = 0 265 | non_zeros = weight != 0 266 | non_zeros = non_zeros.astype(np.float32) 267 | # zeros = weight == 0 268 | # zeros = zeros.astype(np.float32) 269 | return torch.from_numpy(non_zeros).cuda(), torch.from_numpy(weight).cuda() 270 | elif (args.sparsity_type == "random-pattern"): 271 | print("random_pattern pruning...", weight.shape) 272 | shape = weight.shape 273 | weight2d = weight.reshape(shape[0], -1) 274 | 275 | pattern1 = [0, 2, 6, 8] 276 | pattern2 = [0, 1, 7, 8] 277 | pattern3 = [0, 1, 6, 7] 278 | pattern4 = [0, 1, 3, 4] 279 | 280 | pattern5 = [2, 3, 5, 6] 281 | pattern6 = [0, 3, 5, 8] 282 | pattern7 = [1, 2, 6, 7] 283 | pattern8 = [1, 2, 7, 8] 284 | 285 | pattern9 = [3, 5, 6, 8] 286 | pattern10 = [0, 2, 3, 5] 287 | pattern11 = [4, 5, 7, 8] 288 | pattern12 = [3, 4, 6, 7] 289 | pattern13 = [1 ,2 ,4, 5] 290 | 291 | patterns_dict = {1: pattern1, 292 | 2: pattern2, 293 | 3: pattern3, 294 | 4: pattern4, 295 | 5: pattern5, 296 | 6: pattern6, 297 | 7: pattern7, 298 | 8: pattern8, 299 | 9: pattern9, 300 | 10: pattern10, 301 | 11: pattern11, 302 | 12: pattern12, 303 | 13: pattern13 304 | } 305 | 306 | for i in range(shape[0]): 307 | zero_idx = [] 308 | for j in range(shape[1]): 309 | pattern_j = np.array(patterns_dict[random.choice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13])]) 310 | zero_idx.append(pattern_j + 9 * j) 311 | zero_idx = np.array(zero_idx) 312 | zero_idx = zero_idx.reshape(1, -1) 313 | # print(zero_idx) 314 | weight2d[i][zero_idx] = 0 315 | 316 | non_zeros = weight != 0 317 | non_zeros = non_zeros.astype(np.float32) 318 | # zeros = weight == 0 319 | # zeros = zeros.astype(np.float32) 320 | return torch.from_numpy(non_zeros).cuda(), torch.from_numpy(weight).cuda() 321 | else: 322 | raise SyntaxError("Unknown sparsity type") 323 | 324 | 325 | def hard_prune(args, ADMM, model, option=None, cross_x=4, cross_f=1): 326 | """ 327 | hard_pruning, or direct masking 328 | Args: 329 | model: contains weight tensors in cuda 330 | 331 | """ 332 | 333 | print("hard pruning") 334 | for (name, W) in model.module.named_parameters() if type( 335 | model) is nn.parallel.DistributedDataParallel else model.named_parameters(): 336 | if name not in ADMM.prune_ratios: # ignore layers that do not have rho 337 | continue 338 | cuda_pruned_weights = None 339 | if option == None: 340 | _, cuda_pruned_weights = weight_pruning(args, W, ADMM.prune_ratios[name], cross_x, cross_f) # get sparse model in cuda 341 | 342 | elif option == "random": 343 | _, cuda_pruned_weights = random_pruning(args, W, ADMM.prune_ratios[name]) 344 | 345 | elif option == "l1": 346 | _, cuda_pruned_weights = L1_pruning(args, W, ADMM.prune_ratios[name]) 347 | else: 348 | raise Exception("not implmented yet") 349 | W.data = cuda_pruned_weights # replace the data field in variable 350 | 351 | 352 | 353 | def admm_initialization(args, ADMM, model, cross_x=4, cross_f=1): 354 | if not args.admm: 355 | return 356 | for i, (name, W) in enumerate(model.module.named_parameters() if type( 357 | model) is nn.parallel.DistributedDataParallel else model.named_parameters()): 358 | if name in ADMM.prune_ratios: 359 | _, updated_Z = weight_pruning(args, W, ADMM.prune_ratios[name], cross_x, cross_f) # Z(k+1) = W(k+1)+U(k) U(k) is zeros her 360 | ADMM.ADMM_Z[name] = updated_Z 361 | 362 | 363 | def z_u_update(args, ADMM, model, device, train_loader, optimizer, epoch, data, batch_idx, writer, cross_x=4, cross_f=1): 364 | if not args.admm: 365 | return 366 | 367 | if epoch != 1 and (epoch - 1) % args.admm_epochs == 0 and batch_idx == 0: 368 | for i, (name, W) in enumerate(model.module.named_parameters() if type( 369 | model) is nn.parallel.DistributedDataParallel else model.named_parameters()): 370 | if name not in ADMM.prune_ratios: 371 | continue 372 | Z_prev = None 373 | if (args. verbose): 374 | Z_prev = torch.Tensor(ADMM.ADMM_Z[name].cpu()).cuda() 375 | ADMM.ADMM_Z[name] = W + ADMM.ADMM_U[name] # Z(k+1) = W(k+1)+U[k] 376 | 377 | _, updated_Z = weight_pruning(args, ADMM.ADMM_Z[name], ADMM.prune_ratios[name], cross_x, cross_f) # equivalent to Euclidean Projection 378 | ADMM.ADMM_Z[name] = updated_Z 379 | if (args.verbose): 380 | if writer: 381 | writer.add_scalar('layer_{}_Wk1-Zk1'.format(name), torch.sqrt(torch.sum((W - ADMM.ADMM_Z[name]) ** 2)).item(), epoch) 382 | writer.add_scalar('layer_{}_Zk1-Zk'.format(name), torch.sqrt(torch.sum((ADMM.ADMM_Z[name] - Z_prev) ** 2)).item(), epoch) 383 | 384 | # print ("at layer {}. W(k+1)-Z(k+1): {}".format(name,torch.sqrt(torch.sum((W-ADMM.ADMM_Z[name])**2)).item())) 385 | # print ("at layer {}, Z(k+1)-Z(k): {}".format(name,torch.sqrt(torch.sum((ADMM.ADMM_Z[name]-Z_prev)**2)).item())) 386 | ADMM.ADMM_U[name] = W - ADMM.ADMM_Z[name] + ADMM.ADMM_U[name] # U(k+1) = W(k+1) - Z(k+1) +U(k) 387 | 388 | def append_admm_loss(args, ADMM, model, ce_loss): 389 | ''' 390 | append admm loss to cross_entropy loss 391 | Args: 392 | args: configuration parameters 393 | model: instance to the model class 394 | ce_loss: the cross entropy loss 395 | Returns: 396 | ce_loss(tensor scalar): original cross enropy loss 397 | admm_loss(dict, name->tensor scalar): a dictionary to show loss for each layer 398 | ret_loss(scalar): the mixed overall loss 399 | 400 | ''' 401 | admm_loss = {} 402 | 403 | if args.admm: 404 | 405 | for i, (name, W) in enumerate(model.module.named_parameters() if type( 406 | model) is nn.parallel.DistributedDataParallel else model.named_parameters()): ## initialize Z (for both weights and bias) 407 | if name not in ADMM.prune_ratios: 408 | continue 409 | 410 | admm_loss[name] = 0.5 * ADMM.rhos[name] * (torch.norm(W - ADMM.ADMM_Z[name] + ADMM.ADMM_U[name], p=2) ** 2) 411 | mixed_loss = 0 412 | mixed_loss += ce_loss 413 | for k, v in admm_loss.items(): 414 | mixed_loss += v 415 | return ce_loss, admm_loss, mixed_loss 416 | 417 | 418 | def admm_adjust_learning_rate(optimizer, epoch, args): 419 | """ (The pytorch learning rate scheduler) 420 | Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" 421 | """ 422 | For admm, the learning rate change is periodic. 423 | When epoch is dividable by admm_epoch, the learning rate is reset 424 | to the original one, and decay every 3 epoch (as the default 425 | admm epoch is 9) 426 | 427 | """ 428 | admm_epoch = args.admm_epochs 429 | lr = None 430 | if epoch % admm_epoch == 0: 431 | lr = args.lr 432 | else: 433 | admm_epoch_offset = epoch % admm_epoch 434 | 435 | admm_step = admm_epoch / 3 # roughly every 1/3 admm_epoch. 436 | 437 | lr = args.lr * (0.1 ** (admm_epoch_offset // admm_step)) 438 | 439 | for param_group in optimizer.param_groups: 440 | param_group['lr'] = lr 441 | 442 | 443 | 444 | class CrossEntropyLossMaybeSmooth(nn.CrossEntropyLoss): 445 | ''' Calculate cross entropy loss, apply label smoothing if needed. ''' 446 | 447 | def __init__(self, smooth_eps=0.0): 448 | super(CrossEntropyLossMaybeSmooth, self).__init__() 449 | self.smooth_eps = smooth_eps 450 | 451 | def forward(self, output, target, smooth=False): 452 | if not smooth: 453 | return F.cross_entropy(output, target) 454 | 455 | target = target.contiguous().view(-1) 456 | n_class = output.size(1) 457 | one_hot = torch.zeros_like(output).scatter(1, target.view(-1, 1), 1) 458 | smooth_one_hot = one_hot * (1 - self.smooth_eps) + (1 - one_hot) * self.smooth_eps / (n_class - 1) 459 | log_prb = F.log_softmax(output, dim=1) 460 | loss = -(smooth_one_hot * log_prb).sum(dim=1).mean() 461 | return loss 462 | 463 | 464 | def mixup_data(x, y, alpha=1.0): 465 | 466 | '''Compute the mixup data. Return mixed inputs, pairs of targets, and lambda''' 467 | if alpha > 0.0: 468 | lam = np.random.beta(alpha, alpha) 469 | else: 470 | lam = 1.0 471 | 472 | batch_size = x.size()[0] 473 | index = torch.randperm(batch_size).cuda() 474 | 475 | mixed_x = lam * x + (1 - lam) * x[index,:] 476 | y_a, y_b = y, y[index] 477 | return mixed_x, y_a, y_b, lam 478 | 479 | def mixup_criterion(criterion, pred, y_a, y_b, lam, smooth): 480 | return lam * criterion(pred, y_a, smooth=smooth) + \ 481 | (1 - lam) * criterion(pred, y_b, smooth=smooth) 482 | 483 | class GradualWarmupScheduler(_LRScheduler): 484 | """ Gradually warm-up(increasing) learning rate in optimizer. 485 | Proposed in 'Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour'. 486 | Args: 487 | optimizer (Optimizer): Wrapped optimizer. 488 | multiplier: target learning rate = base lr * multiplier 489 | total_iter: target learning rate is reached at total_iter, gradually 490 | after_scheduler: after target_epoch, use this scheduler(eg. ReduceLROnPlateau) 491 | """ 492 | 493 | def __init__(self, optimizer, multiplier, total_iter, after_scheduler=None): 494 | self.multiplier = multiplier 495 | if self.multiplier <= 1.: 496 | raise ValueError('multiplier should be greater than 1.') 497 | self.total_iter = total_iter 498 | self.after_scheduler = after_scheduler 499 | self.finished = False 500 | super().__init__(optimizer) 501 | 502 | def get_lr(self): 503 | if self.last_epoch > self.total_iter: 504 | if self.after_scheduler: 505 | if not self.finished: 506 | self.after_scheduler.base_lrs = [base_lr * self.multiplier for base_lr in self.base_lrs] 507 | self.finished = True 508 | return self.after_scheduler.get_lr() 509 | return [base_lr * self.multiplier for base_lr in self.base_lrs] 510 | 511 | return [base_lr * ((self.multiplier - 1.) * self.last_epoch / self.total_iter + 1.) for base_lr in self.base_lrs] 512 | 513 | def step(self, epoch=None): 514 | if self.finished and self.after_scheduler: 515 | return self.after_scheduler.step(epoch) 516 | else: 517 | return super(GradualWarmupScheduler, self).step(epoch) -------------------------------------------------------------------------------- /cfg/csdarknet53s-panet-spp.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | # Testing 3 | #batch=1 4 | #subdivisions=1 5 | # Training 6 | batch=64 7 | subdivisions=16 8 | width=416 9 | height=416 10 | channels=3 11 | momentum=0.9 12 | decay=0.0005 13 | angle=0 14 | saturation = 1.5 15 | exposure = 1.5 16 | hue=.1 17 | 18 | learning_rate=0.001 19 | burn_in=1000 20 | max_batches = 500500 21 | policy=steps 22 | steps=400000,450000 23 | scales=.1,.1 24 | 25 | #23:104x104 54:52x52 85:26x26 104:13x13 for 416 26 | 27 | 28 | 29 | [convolutional] 30 | batch_normalize=1 31 | filters=32 32 | size=3 33 | stride=1 34 | pad=1 35 | activation=leaky 36 | 37 | # Downsample 38 | 39 | [convolutional] 40 | batch_normalize=1 41 | filters=64 42 | size=3 43 | stride=2 44 | pad=1 45 | activation=leaky 46 | 47 | #[convolutional] 48 | #batch_normalize=1 49 | #filters=64 50 | #size=1 51 | #stride=1 52 | #pad=1 53 | #activation=leaky 54 | 55 | #[route] 56 | #layers = -2 57 | 58 | #[convolutional] 59 | #batch_normalize=1 60 | #filters=64 61 | #size=1 62 | #stride=1 63 | #pad=1 64 | #activation=leaky 65 | 66 | [convolutional] 67 | batch_normalize=1 68 | filters=32 69 | size=1 70 | stride=1 71 | pad=1 72 | activation=leaky 73 | 74 | [convolutional] 75 | batch_normalize=1 76 | filters=64 77 | size=3 78 | stride=1 79 | pad=1 80 | activation=leaky 81 | 82 | [shortcut] 83 | from=-3 84 | activation=linear 85 | 86 | #[convolutional] 87 | #batch_normalize=1 88 | #filters=64 89 | #size=1 90 | #stride=1 91 | #pad=1 92 | #activation=leaky 93 | 94 | #[route] 95 | #layers = -1,-7 96 | 97 | #[convolutional] 98 | #batch_normalize=1 99 | #filters=64 100 | #size=1 101 | #stride=1 102 | #pad=1 103 | #activation=leaky 104 | 105 | # Downsample 106 | 107 | [convolutional] 108 | batch_normalize=1 109 | filters=128 110 | size=3 111 | stride=2 112 | pad=1 113 | activation=leaky 114 | 115 | [convolutional] 116 | batch_normalize=1 117 | filters=64 118 | size=1 119 | stride=1 120 | pad=1 121 | activation=leaky 122 | 123 | [route] 124 | layers = -2 125 | 126 | [convolutional] 127 | batch_normalize=1 128 | filters=64 129 | size=1 130 | stride=1 131 | pad=1 132 | activation=leaky 133 | 134 | [convolutional] 135 | batch_normalize=1 136 | filters=64 137 | size=1 138 | stride=1 139 | pad=1 140 | activation=leaky 141 | 142 | [convolutional] 143 | batch_normalize=1 144 | filters=64 145 | size=3 146 | stride=1 147 | pad=1 148 | activation=leaky 149 | 150 | [shortcut] 151 | from=-3 152 | activation=linear 153 | 154 | [convolutional] 155 | batch_normalize=1 156 | filters=64 157 | size=1 158 | stride=1 159 | pad=1 160 | activation=leaky 161 | 162 | [convolutional] 163 | batch_normalize=1 164 | filters=64 165 | size=3 166 | stride=1 167 | pad=1 168 | activation=leaky 169 | 170 | [shortcut] 171 | from=-3 172 | activation=linear 173 | 174 | [convolutional] 175 | batch_normalize=1 176 | filters=64 177 | size=1 178 | stride=1 179 | pad=1 180 | activation=leaky 181 | 182 | [route] 183 | layers = -1,-10 184 | 185 | [convolutional] 186 | batch_normalize=1 187 | filters=128 188 | size=1 189 | stride=1 190 | pad=1 191 | activation=leaky 192 | 193 | # Downsample 194 | 195 | [convolutional] 196 | batch_normalize=1 197 | filters=256 198 | size=3 199 | stride=2 200 | pad=1 201 | activation=leaky 202 | 203 | [convolutional] 204 | batch_normalize=1 205 | filters=128 206 | size=1 207 | stride=1 208 | pad=1 209 | activation=leaky 210 | 211 | [route] 212 | layers = -2 213 | 214 | [convolutional] 215 | batch_normalize=1 216 | filters=128 217 | size=1 218 | stride=1 219 | pad=1 220 | activation=leaky 221 | 222 | [convolutional] 223 | batch_normalize=1 224 | filters=128 225 | size=1 226 | stride=1 227 | pad=1 228 | activation=leaky 229 | 230 | [convolutional] 231 | batch_normalize=1 232 | filters=128 233 | size=3 234 | stride=1 235 | pad=1 236 | activation=leaky 237 | 238 | [shortcut] 239 | from=-3 240 | activation=linear 241 | 242 | [convolutional] 243 | batch_normalize=1 244 | filters=128 245 | size=1 246 | stride=1 247 | pad=1 248 | activation=leaky 249 | 250 | [convolutional] 251 | batch_normalize=1 252 | filters=128 253 | size=3 254 | stride=1 255 | pad=1 256 | activation=leaky 257 | 258 | [shortcut] 259 | from=-3 260 | activation=linear 261 | 262 | [convolutional] 263 | batch_normalize=1 264 | filters=128 265 | size=1 266 | stride=1 267 | pad=1 268 | activation=leaky 269 | 270 | [convolutional] 271 | batch_normalize=1 272 | filters=128 273 | size=3 274 | stride=1 275 | pad=1 276 | activation=leaky 277 | 278 | [shortcut] 279 | from=-3 280 | activation=linear 281 | 282 | [convolutional] 283 | batch_normalize=1 284 | filters=128 285 | size=1 286 | stride=1 287 | pad=1 288 | activation=leaky 289 | 290 | [convolutional] 291 | batch_normalize=1 292 | filters=128 293 | size=3 294 | stride=1 295 | pad=1 296 | activation=leaky 297 | 298 | [shortcut] 299 | from=-3 300 | activation=linear 301 | 302 | 303 | [convolutional] 304 | batch_normalize=1 305 | filters=128 306 | size=1 307 | stride=1 308 | pad=1 309 | activation=leaky 310 | 311 | [convolutional] 312 | batch_normalize=1 313 | filters=128 314 | size=3 315 | stride=1 316 | pad=1 317 | activation=leaky 318 | 319 | [shortcut] 320 | from=-3 321 | activation=linear 322 | 323 | [convolutional] 324 | batch_normalize=1 325 | filters=128 326 | size=1 327 | stride=1 328 | pad=1 329 | activation=leaky 330 | 331 | [convolutional] 332 | batch_normalize=1 333 | filters=128 334 | size=3 335 | stride=1 336 | pad=1 337 | activation=leaky 338 | 339 | [shortcut] 340 | from=-3 341 | activation=linear 342 | 343 | [convolutional] 344 | batch_normalize=1 345 | filters=128 346 | size=1 347 | stride=1 348 | pad=1 349 | activation=leaky 350 | 351 | [convolutional] 352 | batch_normalize=1 353 | filters=128 354 | size=3 355 | stride=1 356 | pad=1 357 | activation=leaky 358 | 359 | [shortcut] 360 | from=-3 361 | activation=linear 362 | 363 | [convolutional] 364 | batch_normalize=1 365 | filters=128 366 | size=1 367 | stride=1 368 | pad=1 369 | activation=leaky 370 | 371 | [convolutional] 372 | batch_normalize=1 373 | filters=128 374 | size=3 375 | stride=1 376 | pad=1 377 | activation=leaky 378 | 379 | [shortcut] 380 | from=-3 381 | activation=linear 382 | 383 | [convolutional] 384 | batch_normalize=1 385 | filters=128 386 | size=1 387 | stride=1 388 | pad=1 389 | activation=leaky 390 | 391 | [route] 392 | layers = -1,-28 393 | 394 | [convolutional] 395 | batch_normalize=1 396 | filters=256 397 | size=1 398 | stride=1 399 | pad=1 400 | activation=leaky 401 | 402 | # Downsample 403 | 404 | [convolutional] 405 | batch_normalize=1 406 | filters=512 407 | size=3 408 | stride=2 409 | pad=1 410 | activation=leaky 411 | 412 | [convolutional] 413 | batch_normalize=1 414 | filters=256 415 | size=1 416 | stride=1 417 | pad=1 418 | activation=leaky 419 | 420 | [route] 421 | layers = -2 422 | 423 | [convolutional] 424 | batch_normalize=1 425 | filters=256 426 | size=1 427 | stride=1 428 | pad=1 429 | activation=leaky 430 | 431 | [convolutional] 432 | batch_normalize=1 433 | filters=256 434 | size=1 435 | stride=1 436 | pad=1 437 | activation=leaky 438 | 439 | [convolutional] 440 | batch_normalize=1 441 | filters=256 442 | size=3 443 | stride=1 444 | pad=1 445 | activation=leaky 446 | 447 | [shortcut] 448 | from=-3 449 | activation=linear 450 | 451 | 452 | [convolutional] 453 | batch_normalize=1 454 | filters=256 455 | size=1 456 | stride=1 457 | pad=1 458 | activation=leaky 459 | 460 | [convolutional] 461 | batch_normalize=1 462 | filters=256 463 | size=3 464 | stride=1 465 | pad=1 466 | activation=leaky 467 | 468 | [shortcut] 469 | from=-3 470 | activation=linear 471 | 472 | 473 | [convolutional] 474 | batch_normalize=1 475 | filters=256 476 | size=1 477 | stride=1 478 | pad=1 479 | activation=leaky 480 | 481 | [convolutional] 482 | batch_normalize=1 483 | filters=256 484 | size=3 485 | stride=1 486 | pad=1 487 | activation=leaky 488 | 489 | [shortcut] 490 | from=-3 491 | activation=linear 492 | 493 | 494 | [convolutional] 495 | batch_normalize=1 496 | filters=256 497 | size=1 498 | stride=1 499 | pad=1 500 | activation=leaky 501 | 502 | [convolutional] 503 | batch_normalize=1 504 | filters=256 505 | size=3 506 | stride=1 507 | pad=1 508 | activation=leaky 509 | 510 | [shortcut] 511 | from=-3 512 | activation=linear 513 | 514 | 515 | [convolutional] 516 | batch_normalize=1 517 | filters=256 518 | size=1 519 | stride=1 520 | pad=1 521 | activation=leaky 522 | 523 | [convolutional] 524 | batch_normalize=1 525 | filters=256 526 | size=3 527 | stride=1 528 | pad=1 529 | activation=leaky 530 | 531 | [shortcut] 532 | from=-3 533 | activation=linear 534 | 535 | 536 | [convolutional] 537 | batch_normalize=1 538 | filters=256 539 | size=1 540 | stride=1 541 | pad=1 542 | activation=leaky 543 | 544 | [convolutional] 545 | batch_normalize=1 546 | filters=256 547 | size=3 548 | stride=1 549 | pad=1 550 | activation=leaky 551 | 552 | [shortcut] 553 | from=-3 554 | activation=linear 555 | 556 | 557 | [convolutional] 558 | batch_normalize=1 559 | filters=256 560 | size=1 561 | stride=1 562 | pad=1 563 | activation=leaky 564 | 565 | [convolutional] 566 | batch_normalize=1 567 | filters=256 568 | size=3 569 | stride=1 570 | pad=1 571 | activation=leaky 572 | 573 | [shortcut] 574 | from=-3 575 | activation=linear 576 | 577 | [convolutional] 578 | batch_normalize=1 579 | filters=256 580 | size=1 581 | stride=1 582 | pad=1 583 | activation=leaky 584 | 585 | [convolutional] 586 | batch_normalize=1 587 | filters=256 588 | size=3 589 | stride=1 590 | pad=1 591 | activation=leaky 592 | 593 | [shortcut] 594 | from=-3 595 | activation=linear 596 | 597 | [convolutional] 598 | batch_normalize=1 599 | filters=256 600 | size=1 601 | stride=1 602 | pad=1 603 | activation=leaky 604 | 605 | [route] 606 | layers = -1,-28 607 | 608 | [convolutional] 609 | batch_normalize=1 610 | filters=512 611 | size=1 612 | stride=1 613 | pad=1 614 | activation=leaky 615 | 616 | # Downsample 617 | 618 | [convolutional] 619 | batch_normalize=1 620 | filters=1024 621 | size=3 622 | stride=2 623 | pad=1 624 | activation=leaky 625 | 626 | [convolutional] 627 | batch_normalize=1 628 | filters=512 629 | size=1 630 | stride=1 631 | pad=1 632 | activation=leaky 633 | 634 | [route] 635 | layers = -2 636 | 637 | [convolutional] 638 | batch_normalize=1 639 | filters=512 640 | size=1 641 | stride=1 642 | pad=1 643 | activation=leaky 644 | 645 | [convolutional] 646 | batch_normalize=1 647 | filters=512 648 | size=1 649 | stride=1 650 | pad=1 651 | activation=leaky 652 | 653 | [convolutional] 654 | batch_normalize=1 655 | filters=512 656 | size=3 657 | stride=1 658 | pad=1 659 | activation=leaky 660 | 661 | [shortcut] 662 | from=-3 663 | activation=linear 664 | 665 | [convolutional] 666 | batch_normalize=1 667 | filters=512 668 | size=1 669 | stride=1 670 | pad=1 671 | activation=leaky 672 | 673 | [convolutional] 674 | batch_normalize=1 675 | filters=512 676 | size=3 677 | stride=1 678 | pad=1 679 | activation=leaky 680 | 681 | [shortcut] 682 | from=-3 683 | activation=linear 684 | 685 | [convolutional] 686 | batch_normalize=1 687 | filters=512 688 | size=1 689 | stride=1 690 | pad=1 691 | activation=leaky 692 | 693 | [convolutional] 694 | batch_normalize=1 695 | filters=512 696 | size=3 697 | stride=1 698 | pad=1 699 | activation=leaky 700 | 701 | [shortcut] 702 | from=-3 703 | activation=linear 704 | 705 | [convolutional] 706 | batch_normalize=1 707 | filters=512 708 | size=1 709 | stride=1 710 | pad=1 711 | activation=leaky 712 | 713 | [convolutional] 714 | batch_normalize=1 715 | filters=512 716 | size=3 717 | stride=1 718 | pad=1 719 | activation=leaky 720 | 721 | [shortcut] 722 | from=-3 723 | activation=linear 724 | 725 | [convolutional] 726 | batch_normalize=1 727 | filters=512 728 | size=1 729 | stride=1 730 | pad=1 731 | activation=leaky 732 | 733 | [route] 734 | layers = -1,-16 735 | 736 | [convolutional] 737 | batch_normalize=1 738 | filters=1024 739 | size=1 740 | stride=1 741 | pad=1 742 | activation=leaky 743 | 744 | ########################## 745 | 746 | [convolutional] 747 | batch_normalize=1 748 | filters=512 749 | size=1 750 | stride=1 751 | pad=1 752 | activation=leaky 753 | 754 | [convolutional] 755 | batch_normalize=1 756 | size=3 757 | stride=1 758 | pad=1 759 | filters=1024 760 | activation=leaky 761 | 762 | [convolutional] 763 | batch_normalize=1 764 | filters=512 765 | size=1 766 | stride=1 767 | pad=1 768 | activation=leaky 769 | 770 | ### SPP ### 771 | [maxpool] 772 | stride=1 773 | size=5 774 | 775 | [route] 776 | layers=-2 777 | 778 | [maxpool] 779 | stride=1 780 | size=9 781 | 782 | [route] 783 | layers=-4 784 | 785 | [maxpool] 786 | stride=1 787 | size=13 788 | 789 | [route] 790 | layers=-1,-3,-5,-6 791 | ### End SPP ### 792 | 793 | [convolutional] 794 | batch_normalize=1 795 | filters=512 796 | size=1 797 | stride=1 798 | pad=1 799 | activation=leaky 800 | 801 | [convolutional] 802 | batch_normalize=1 803 | size=3 804 | stride=1 805 | pad=1 806 | filters=1024 807 | activation=leaky 808 | 809 | [convolutional] 810 | batch_normalize=1 811 | filters=512 812 | size=1 813 | stride=1 814 | pad=1 815 | activation=leaky 816 | 817 | [convolutional] 818 | batch_normalize=1 819 | filters=256 820 | size=1 821 | stride=1 822 | pad=1 823 | activation=leaky 824 | 825 | [upsample] 826 | stride=2 827 | 828 | [route] 829 | layers = 79 830 | 831 | [convolutional] 832 | batch_normalize=1 833 | filters=256 834 | size=1 835 | stride=1 836 | pad=1 837 | activation=leaky 838 | 839 | [route] 840 | layers = -1, -3 841 | 842 | [convolutional] 843 | batch_normalize=1 844 | filters=256 845 | size=1 846 | stride=1 847 | pad=1 848 | activation=leaky 849 | 850 | [convolutional] 851 | batch_normalize=1 852 | size=3 853 | stride=1 854 | pad=1 855 | filters=512 856 | activation=leaky 857 | 858 | [convolutional] 859 | batch_normalize=1 860 | filters=256 861 | size=1 862 | stride=1 863 | pad=1 864 | activation=leaky 865 | 866 | [convolutional] 867 | batch_normalize=1 868 | size=3 869 | stride=1 870 | pad=1 871 | filters=512 872 | activation=leaky 873 | 874 | [convolutional] 875 | batch_normalize=1 876 | filters=256 877 | size=1 878 | stride=1 879 | pad=1 880 | activation=leaky 881 | 882 | [convolutional] 883 | batch_normalize=1 884 | filters=128 885 | size=1 886 | stride=1 887 | pad=1 888 | activation=leaky 889 | 890 | [upsample] 891 | stride=2 892 | 893 | [route] 894 | layers = 48 895 | 896 | [convolutional] 897 | batch_normalize=1 898 | filters=128 899 | size=1 900 | stride=1 901 | pad=1 902 | activation=leaky 903 | 904 | [route] 905 | layers = -1, -3 906 | 907 | [convolutional] 908 | batch_normalize=1 909 | filters=128 910 | size=1 911 | stride=1 912 | pad=1 913 | activation=leaky 914 | 915 | [convolutional] 916 | batch_normalize=1 917 | size=3 918 | stride=1 919 | pad=1 920 | filters=256 921 | activation=leaky 922 | 923 | [convolutional] 924 | batch_normalize=1 925 | filters=128 926 | size=1 927 | stride=1 928 | pad=1 929 | activation=leaky 930 | 931 | [convolutional] 932 | batch_normalize=1 933 | size=3 934 | stride=1 935 | pad=1 936 | filters=256 937 | activation=leaky 938 | 939 | [convolutional] 940 | batch_normalize=1 941 | filters=128 942 | size=1 943 | stride=1 944 | pad=1 945 | activation=leaky 946 | 947 | ########################## 948 | 949 | [convolutional] 950 | batch_normalize=1 951 | size=3 952 | stride=1 953 | pad=1 954 | filters=256 955 | activation=leaky 956 | 957 | [convolutional] 958 | size=1 959 | stride=1 960 | pad=1 961 | filters=255 962 | activation=linear 963 | 964 | 965 | [yolo] 966 | mask = 0,1,2 967 | anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 968 | classes=80 969 | num=9 970 | jitter=.3 971 | ignore_thresh = .7 972 | truth_thresh = 1 973 | random=1 974 | 975 | [route] 976 | layers = -4 977 | 978 | [convolutional] 979 | batch_normalize=1 980 | size=3 981 | stride=2 982 | pad=1 983 | filters=256 984 | activation=leaky 985 | 986 | [route] 987 | layers = -1, -16 988 | 989 | [convolutional] 990 | batch_normalize=1 991 | filters=256 992 | size=1 993 | stride=1 994 | pad=1 995 | activation=leaky 996 | 997 | [convolutional] 998 | batch_normalize=1 999 | size=3 1000 | stride=1 1001 | pad=1 1002 | filters=512 1003 | activation=leaky 1004 | 1005 | [convolutional] 1006 | batch_normalize=1 1007 | filters=256 1008 | size=1 1009 | stride=1 1010 | pad=1 1011 | activation=leaky 1012 | 1013 | [convolutional] 1014 | batch_normalize=1 1015 | size=3 1016 | stride=1 1017 | pad=1 1018 | filters=512 1019 | activation=leaky 1020 | 1021 | [convolutional] 1022 | batch_normalize=1 1023 | filters=256 1024 | size=1 1025 | stride=1 1026 | pad=1 1027 | activation=leaky 1028 | 1029 | [convolutional] 1030 | batch_normalize=1 1031 | size=3 1032 | stride=1 1033 | pad=1 1034 | filters=512 1035 | activation=leaky 1036 | 1037 | [convolutional] 1038 | size=1 1039 | stride=1 1040 | pad=1 1041 | filters=255 1042 | activation=linear 1043 | 1044 | 1045 | [yolo] 1046 | mask = 3,4,5 1047 | anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 1048 | classes=80 1049 | num=9 1050 | jitter=.3 1051 | ignore_thresh = .7 1052 | truth_thresh = 1 1053 | random=1 1054 | 1055 | [route] 1056 | layers = -4 1057 | 1058 | [convolutional] 1059 | batch_normalize=1 1060 | size=3 1061 | stride=2 1062 | pad=1 1063 | filters=512 1064 | activation=leaky 1065 | 1066 | [route] 1067 | layers = -1, -37 1068 | 1069 | [convolutional] 1070 | batch_normalize=1 1071 | filters=512 1072 | size=1 1073 | stride=1 1074 | pad=1 1075 | activation=leaky 1076 | 1077 | [convolutional] 1078 | batch_normalize=1 1079 | size=3 1080 | stride=1 1081 | pad=1 1082 | filters=1024 1083 | activation=leaky 1084 | 1085 | [convolutional] 1086 | batch_normalize=1 1087 | filters=512 1088 | size=1 1089 | stride=1 1090 | pad=1 1091 | activation=leaky 1092 | 1093 | [convolutional] 1094 | batch_normalize=1 1095 | size=3 1096 | stride=1 1097 | pad=1 1098 | filters=1024 1099 | activation=leaky 1100 | 1101 | [convolutional] 1102 | batch_normalize=1 1103 | filters=512 1104 | size=1 1105 | stride=1 1106 | pad=1 1107 | activation=leaky 1108 | 1109 | [convolutional] 1110 | batch_normalize=1 1111 | size=3 1112 | stride=1 1113 | pad=1 1114 | filters=1024 1115 | activation=leaky 1116 | 1117 | [convolutional] 1118 | size=1 1119 | stride=1 1120 | pad=1 1121 | filters=255 1122 | activation=linear 1123 | 1124 | 1125 | [yolo] 1126 | mask = 6,7,8 1127 | anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 1128 | classes=80 1129 | num=9 1130 | jitter=.3 1131 | ignore_thresh = .7 1132 | truth_thresh = 1 1133 | random=1 1134 | -------------------------------------------------------------------------------- /cfg/darknet_admm.yaml: -------------------------------------------------------------------------------- 1 | admm: 2 | True 3 | masked-retrain: 4 | False 5 | admm-epochs: 6 | # select weight positions based on ADMM every 6 epoches 7 | 6 8 | rho: 9 | #rho: 10 | 0.0001 11 | rho-num: 12 | #rho: order of magnitude (from 0.0001 x 1e-1 to 0.0001 x 1e-4) 13 | 4 14 | sparsity-type: 15 | # Prune Scheme 16 | block-punched 17 | config-file: 18 | config_csdarknet53pan_v2 19 | combine-progressive: 20 | # Progressive Pruning. 4x pruning load 2x pruned weight file 21 | False 22 | verbose: 23 | # Log 24 | True 25 | -------------------------------------------------------------------------------- /cfg/darknet_retrain.yaml: -------------------------------------------------------------------------------- 1 | admm: 2 | False 3 | masked-retrain: 4 | True 5 | admm-epochs: 6 | # select weight positions based on ADMM every 6 epoches 7 | 1 8 | rho: 9 | #rho: 10 | 0.0001 11 | rho-num: 12 | #rho: order of magnitude (from 0.0001 x 1e-1 to 0.0001 x 1e-4) 13 | 1 14 | sparsity-type: 15 | # Prune Scheme 16 | block-punched 17 | config-file: 18 | config_csdarknet53pan_v2 19 | combine-progressive: 20 | # Progressive Pruning. 4x pruning load 2x pruned weight file 21 | False 22 | verbose: 23 | # Log 24 | True 25 | -------------------------------------------------------------------------------- /check_compression.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | from models import Darknet 4 | from utils import torch_utils 5 | 6 | 7 | def test_sparsity(model): 8 | 9 | # --------------------- total sparsity -------------------- 10 | total_zeros = 0 11 | total_nonzeros = 0 12 | 13 | for name, weight in model.named_parameters(): 14 | if (len(weight.size()) == 4):# and "shortcut" not in name): # only consider conv layers 15 | zeros = np.sum(weight.cpu().detach().numpy() == 0) 16 | total_zeros += zeros 17 | non_zeros = np.sum(weight.cpu().detach().numpy() != 0) 18 | total_nonzeros += non_zeros 19 | 20 | comp_ratio = float((total_zeros + total_nonzeros)) / float(total_nonzeros) 21 | 22 | print("ONLY consider CONV layers: ") 23 | print("total number of zeros: {}, non-zeros: {}, zero sparsity is: {:.4f}".format( 24 | total_zeros, total_nonzeros, total_zeros / (total_zeros + total_nonzeros))) 25 | print("only consider conv layers, compression rate is: {:.4f}".format( 26 | (total_zeros + total_nonzeros) / total_nonzeros)) 27 | print("===========================================================================\n\n") 28 | return comp_ratio 29 | 30 | 31 | 32 | 33 | if __name__ == '__main__': 34 | print("Check Dense model: ") 35 | model = Darknet(cfg = 'cfg/csdarknet53s-panet-spp.cfg',img_size=(320,320)) 36 | n_po, macso = torch_utils.model_info(model, verbose=False) 37 | 38 | print("Check 8x prunned model: ") 39 | state_dict = torch.load('weights/best8x-514.pt') 40 | model.load_state_dict(state_dict["model"]) 41 | n_p8x, macs8x = model.prunedinfo() 42 | print("parameters compression rate: %g, flops compression rate: %g" % (n_po/n_p8x, macso/macs8x)) ##flops=2*macs 43 | test_sparsity(model) 44 | 45 | 46 | print("Check 14x prunned model: ") 47 | state_dict = torch.load('weights/best14x-49.pt') 48 | model.load_state_dict(state_dict["model"]) 49 | n_p14x, macs14x = model.prunedinfo() 50 | print("parameters compression rate: %g, flops compression rate: %g" % (n_po/n_p14x, macso/macs14x)) ##flops=2*macs 51 | test_sparsity(model) -------------------------------------------------------------------------------- /data/coco.names: -------------------------------------------------------------------------------- 1 | person 2 | bicycle 3 | car 4 | motorcycle 5 | airplane 6 | bus 7 | train 8 | truck 9 | boat 10 | traffic light 11 | fire hydrant 12 | stop sign 13 | parking meter 14 | bench 15 | bird 16 | cat 17 | dog 18 | horse 19 | sheep 20 | cow 21 | elephant 22 | bear 23 | zebra 24 | giraffe 25 | backpack 26 | umbrella 27 | handbag 28 | tie 29 | suitcase 30 | frisbee 31 | skis 32 | snowboard 33 | sports ball 34 | kite 35 | baseball bat 36 | baseball glove 37 | skateboard 38 | surfboard 39 | tennis racket 40 | bottle 41 | wine glass 42 | cup 43 | fork 44 | knife 45 | spoon 46 | bowl 47 | banana 48 | apple 49 | sandwich 50 | orange 51 | broccoli 52 | carrot 53 | hot dog 54 | pizza 55 | donut 56 | cake 57 | chair 58 | couch 59 | potted plant 60 | bed 61 | dining table 62 | toilet 63 | tv 64 | laptop 65 | mouse 66 | remote 67 | keyboard 68 | cell phone 69 | microwave 70 | oven 71 | toaster 72 | sink 73 | refrigerator 74 | book 75 | clock 76 | vase 77 | scissors 78 | teddy bear 79 | hair drier 80 | toothbrush 81 | -------------------------------------------------------------------------------- /data/coco1.data: -------------------------------------------------------------------------------- 1 | classes=80 2 | train=data/coco1.txt 3 | valid=data/coco1.txt 4 | names=data/coco.names 5 | -------------------------------------------------------------------------------- /data/coco1.txt: -------------------------------------------------------------------------------- 1 | ../coco/images/train2017/000000109622.jpg 2 | -------------------------------------------------------------------------------- /data/coco16.data: -------------------------------------------------------------------------------- 1 | classes=80 2 | train=data/coco16.txt 3 | valid=data/coco16.txt 4 | names=data/coco.names 5 | -------------------------------------------------------------------------------- /data/coco16.txt: -------------------------------------------------------------------------------- 1 | ../coco/images/train2017/000000109622.jpg 2 | ../coco/images/train2017/000000160694.jpg 3 | ../coco/images/train2017/000000308590.jpg 4 | ../coco/images/train2017/000000327573.jpg 5 | ../coco/images/train2017/000000062929.jpg 6 | ../coco/images/train2017/000000512793.jpg 7 | ../coco/images/train2017/000000371735.jpg 8 | ../coco/images/train2017/000000148118.jpg 9 | ../coco/images/train2017/000000309856.jpg 10 | ../coco/images/train2017/000000141882.jpg 11 | ../coco/images/train2017/000000318783.jpg 12 | ../coco/images/train2017/000000337760.jpg 13 | ../coco/images/train2017/000000298197.jpg 14 | ../coco/images/train2017/000000042421.jpg 15 | ../coco/images/train2017/000000328898.jpg 16 | ../coco/images/train2017/000000458856.jpg 17 | -------------------------------------------------------------------------------- /data/coco1cls.data: -------------------------------------------------------------------------------- 1 | classes=1 2 | train=data/coco1cls.txt 3 | valid=data/coco1cls.txt 4 | names=data/coco.names 5 | -------------------------------------------------------------------------------- /data/coco1cls.txt: -------------------------------------------------------------------------------- 1 | ../coco/images/train2017/000000000901.jpg 2 | ../coco/images/train2017/000000001464.jpg 3 | ../coco/images/train2017/000000003220.jpg 4 | ../coco/images/train2017/000000003365.jpg 5 | ../coco/images/train2017/000000004772.jpg 6 | ../coco/images/train2017/000000009987.jpg 7 | ../coco/images/train2017/000000010498.jpg 8 | ../coco/images/train2017/000000012455.jpg 9 | ../coco/images/train2017/000000013992.jpg 10 | ../coco/images/train2017/000000014125.jpg 11 | ../coco/images/train2017/000000016314.jpg 12 | ../coco/images/train2017/000000016670.jpg 13 | ../coco/images/train2017/000000018412.jpg 14 | ../coco/images/train2017/000000021212.jpg 15 | ../coco/images/train2017/000000021826.jpg 16 | ../coco/images/train2017/000000030566.jpg 17 | -------------------------------------------------------------------------------- /data/coco2014.data: -------------------------------------------------------------------------------- 1 | classes=80 2 | train=../coco/trainvalno5k.txt 3 | valid=../coco/5k.txt 4 | names=data/coco.names 5 | -------------------------------------------------------------------------------- /data/coco2017.data: -------------------------------------------------------------------------------- 1 | classes=80 2 | train=../coco/train2017.txt 3 | valid=../coco/val2017.txt 4 | names=data/coco.names 5 | -------------------------------------------------------------------------------- /data/coco64.data: -------------------------------------------------------------------------------- 1 | classes=80 2 | train=data/coco64.txt 3 | valid=data/coco64.txt 4 | names=data/coco.names 5 | -------------------------------------------------------------------------------- /data/coco64.txt: -------------------------------------------------------------------------------- 1 | ../coco/images/train2017/000000109622.jpg 2 | ../coco/images/train2017/000000160694.jpg 3 | ../coco/images/train2017/000000308590.jpg 4 | ../coco/images/train2017/000000327573.jpg 5 | ../coco/images/train2017/000000062929.jpg 6 | ../coco/images/train2017/000000512793.jpg 7 | ../coco/images/train2017/000000371735.jpg 8 | ../coco/images/train2017/000000148118.jpg 9 | ../coco/images/train2017/000000309856.jpg 10 | ../coco/images/train2017/000000141882.jpg 11 | ../coco/images/train2017/000000318783.jpg 12 | ../coco/images/train2017/000000337760.jpg 13 | ../coco/images/train2017/000000298197.jpg 14 | ../coco/images/train2017/000000042421.jpg 15 | ../coco/images/train2017/000000328898.jpg 16 | ../coco/images/train2017/000000458856.jpg 17 | ../coco/images/train2017/000000073824.jpg 18 | ../coco/images/train2017/000000252846.jpg 19 | ../coco/images/train2017/000000459590.jpg 20 | ../coco/images/train2017/000000273650.jpg 21 | ../coco/images/train2017/000000331311.jpg 22 | ../coco/images/train2017/000000156326.jpg 23 | ../coco/images/train2017/000000262985.jpg 24 | ../coco/images/train2017/000000253580.jpg 25 | ../coco/images/train2017/000000447976.jpg 26 | ../coco/images/train2017/000000378077.jpg 27 | ../coco/images/train2017/000000259913.jpg 28 | ../coco/images/train2017/000000424553.jpg 29 | ../coco/images/train2017/000000000612.jpg 30 | ../coco/images/train2017/000000267625.jpg 31 | ../coco/images/train2017/000000566012.jpg 32 | ../coco/images/train2017/000000196664.jpg 33 | ../coco/images/train2017/000000363331.jpg 34 | ../coco/images/train2017/000000057992.jpg 35 | ../coco/images/train2017/000000520047.jpg 36 | ../coco/images/train2017/000000453903.jpg 37 | ../coco/images/train2017/000000162083.jpg 38 | ../coco/images/train2017/000000268516.jpg 39 | ../coco/images/train2017/000000277436.jpg 40 | ../coco/images/train2017/000000189744.jpg 41 | ../coco/images/train2017/000000041128.jpg 42 | ../coco/images/train2017/000000527728.jpg 43 | ../coco/images/train2017/000000465269.jpg 44 | ../coco/images/train2017/000000246833.jpg 45 | ../coco/images/train2017/000000076784.jpg 46 | ../coco/images/train2017/000000323715.jpg 47 | ../coco/images/train2017/000000560463.jpg 48 | ../coco/images/train2017/000000006263.jpg 49 | ../coco/images/train2017/000000094701.jpg 50 | ../coco/images/train2017/000000521359.jpg 51 | ../coco/images/train2017/000000302903.jpg 52 | ../coco/images/train2017/000000047559.jpg 53 | ../coco/images/train2017/000000480583.jpg 54 | ../coco/images/train2017/000000050025.jpg 55 | ../coco/images/train2017/000000084512.jpg 56 | ../coco/images/train2017/000000508913.jpg 57 | ../coco/images/train2017/000000093708.jpg 58 | ../coco/images/train2017/000000070493.jpg 59 | ../coco/images/train2017/000000539270.jpg 60 | ../coco/images/train2017/000000474402.jpg 61 | ../coco/images/train2017/000000209842.jpg 62 | ../coco/images/train2017/000000028820.jpg 63 | ../coco/images/train2017/000000154257.jpg 64 | ../coco/images/train2017/000000342499.jpg 65 | -------------------------------------------------------------------------------- /data/coco_paper.names: -------------------------------------------------------------------------------- 1 | person 2 | bicycle 3 | car 4 | motorcycle 5 | airplane 6 | bus 7 | train 8 | truck 9 | boat 10 | traffic light 11 | fire hydrant 12 | street sign 13 | stop sign 14 | parking meter 15 | bench 16 | bird 17 | cat 18 | dog 19 | horse 20 | sheep 21 | cow 22 | elephant 23 | bear 24 | zebra 25 | giraffe 26 | hat 27 | backpack 28 | umbrella 29 | shoe 30 | eye glasses 31 | handbag 32 | tie 33 | suitcase 34 | frisbee 35 | skis 36 | snowboard 37 | sports ball 38 | kite 39 | baseball bat 40 | baseball glove 41 | skateboard 42 | surfboard 43 | tennis racket 44 | bottle 45 | plate 46 | wine glass 47 | cup 48 | fork 49 | knife 50 | spoon 51 | bowl 52 | banana 53 | apple 54 | sandwich 55 | orange 56 | broccoli 57 | carrot 58 | hot dog 59 | pizza 60 | donut 61 | cake 62 | chair 63 | couch 64 | potted plant 65 | bed 66 | mirror 67 | dining table 68 | window 69 | desk 70 | toilet 71 | door 72 | tv 73 | laptop 74 | mouse 75 | remote 76 | keyboard 77 | cell phone 78 | microwave 79 | oven 80 | toaster 81 | sink 82 | refrigerator 83 | blender 84 | book 85 | clock 86 | vase 87 | scissors 88 | teddy bear 89 | hair drier 90 | toothbrush 91 | hair brush -------------------------------------------------------------------------------- /data/get_coco2014.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Zip coco folder 3 | # zip -r coco.zip coco 4 | # tar -czvf coco.tar.gz coco 5 | 6 | # Download labels from Google Drive, accepting presented query 7 | filename="coco2014labels.zip" 8 | fileid="1s6-CmF5_SElM28r52P1OUrCcuXZN-SFo" 9 | curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null 10 | curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" -o ${filename} 11 | rm ./cookie 12 | 13 | # Unzip labels 14 | unzip -q ${filename} # for coco.zip 15 | # tar -xzf ${filename} # for coco.tar.gz 16 | rm ${filename} 17 | 18 | # Download and unzip images 19 | cd coco/images 20 | f="train2014.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f 21 | f="val2014.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f 22 | 23 | # cd out 24 | cd ../.. 25 | -------------------------------------------------------------------------------- /data/get_coco2017.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Zip coco folder 3 | # zip -r coco.zip coco 4 | # tar -czvf coco.tar.gz coco 5 | 6 | # Download labels from Google Drive, accepting presented query 7 | filename="coco2017labels.zip" 8 | fileid="1cXZR_ckHki6nddOmcysCuuJFM--T-Q6L" 9 | curl -c ./cookie -s -L "https://drive.google.com/uc?export=download&id=${fileid}" > /dev/null 10 | curl -Lb ./cookie "https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}" -o ${filename} 11 | rm ./cookie 12 | 13 | # Unzip labels 14 | unzip -q ${filename} # for coco.zip 15 | # tar -xzf ${filename} # for coco.tar.gz 16 | rm ${filename} 17 | 18 | # Download and unzip images 19 | cd coco/images 20 | f="train2017.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f 21 | f="val2017.zip" && curl http://images.cocodataset.org/zips/$f -o $f && unzip -q $f && rm $f 22 | 23 | # cd out 24 | cd ../.. 25 | -------------------------------------------------------------------------------- /data/samples/bus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightsnack/YOLObile/900db66830b56da9e0a99f96d27c39ce2932c886/data/samples/bus.jpg -------------------------------------------------------------------------------- /data/samples/zidane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightsnack/YOLObile/900db66830b56da9e0a99f96d27c39ce2932c886/data/samples/zidane.jpg -------------------------------------------------------------------------------- /detect.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from models import * # set ONNX_EXPORT in models.py 4 | from utils.datasets import * 5 | from utils.utils import * 6 | 7 | 8 | def detect(save_img=False): 9 | imgsz = (320, 320) if ONNX_EXPORT else opt.img_size # (320, 192) or (416, 256) or (608, 352) for (height, width) 10 | out, source, weights, half, view_img, save_txt = opt.output, opt.source, opt.weights, opt.half, opt.view_img, opt.save_txt 11 | webcam = source == '0' or source.startswith('rtsp') or source.startswith('http') or source.endswith('.txt') 12 | 13 | # Initialize 14 | device = torch_utils.select_device(device='cpu' if ONNX_EXPORT else opt.device) 15 | if os.path.exists(out): 16 | shutil.rmtree(out) # delete output folder 17 | os.makedirs(out) # make new output folder 18 | 19 | # Initialize model 20 | model = Darknet(opt.cfg, imgsz) 21 | 22 | # Load weights 23 | attempt_download(weights) 24 | if weights.endswith('.pt'): # pytorch format 25 | model.load_state_dict(torch.load(weights, map_location=device)['model'],strict=False) 26 | else: # darknet format 27 | load_darknet_weights(model, weights) 28 | 29 | # Second-stage classifier 30 | classify = False 31 | if classify: 32 | modelc = torch_utils.load_classifier(name='resnet101', n=2) # initialize 33 | modelc.load_state_dict(torch.load('weights/resnet101.pt', map_location=device)['model']) # load weights 34 | modelc.to(device).eval() 35 | 36 | # Eval mode 37 | model.to(device).eval() 38 | 39 | # Fuse Conv2d + BatchNorm2d layers 40 | # model.fuse() 41 | 42 | # Export mode 43 | if ONNX_EXPORT: 44 | # model.fuse() 45 | img = torch.zeros((1, 3) + imgsz) # (1, 3, 320, 192) 46 | f = opt.weights.replace(opt.weights.split('.')[-1], 'onnx') # *.onnx filename 47 | torch.onnx.export(model, img, f, verbose=False, opset_version=9, 48 | input_names=['images'], output_names=['classes', 'boxes']) 49 | 50 | # Validate exported model 51 | import onnx 52 | model = onnx.load(f) # Load the ONNX model 53 | onnx.checker.check_model(model) # Check that the IR is well formed 54 | print(onnx.helper.printable_graph(model.graph)) # Print a human readable representation of the graph 55 | return 56 | 57 | # Half precision 58 | half = half and device.type != 'cpu' # half precision only supported on CUDA 59 | if half: 60 | model.half() 61 | 62 | # Set Dataloader 63 | vid_path, vid_writer = None, None 64 | if webcam: 65 | view_img = True 66 | torch.backends.cudnn.benchmark = True # set True to speed up constant image size inference 67 | dataset = LoadStreams(source, img_size=imgsz) 68 | else: 69 | save_img = True 70 | dataset = LoadImages(source, img_size=imgsz) 71 | 72 | # Get names and colors 73 | names = load_classes(opt.names) 74 | colors = [[random.randint(0, 255) for _ in range(3)] for _ in range(len(names))] 75 | 76 | # Run inference 77 | t0 = time.time() 78 | img = torch.zeros((1, 3, imgsz, imgsz), device=device) # init img 79 | _ = model(img.half() if half else img.float()) if device.type != 'cpu' else None # run once 80 | for path, img, im0s, vid_cap in dataset: 81 | img = torch.from_numpy(img).to(device) 82 | img = img.half() if half else img.float() # uint8 to fp16/32 83 | img /= 255.0 # 0 - 255 to 0.0 - 1.0 84 | if img.ndimension() == 3: 85 | img = img.unsqueeze(0) 86 | 87 | # Inference 88 | t1 = torch_utils.time_synchronized() 89 | pred = model(img, augment=opt.augment)[0] 90 | t2 = torch_utils.time_synchronized() 91 | 92 | # to float 93 | if half: 94 | pred = pred.float() 95 | 96 | # Apply NMS 97 | pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, 98 | multi_label=False, classes=opt.classes, agnostic=opt.agnostic_nms) 99 | 100 | # Apply Classifier 101 | if classify: 102 | pred = apply_classifier(pred, modelc, img, im0s) 103 | 104 | # Process detections 105 | for i, det in enumerate(pred): # detections for image i 106 | if webcam: # batch_size >= 1 107 | p, s, im0 = path[i], '%g: ' % i, im0s[i].copy() 108 | else: 109 | p, s, im0 = path, '', im0s 110 | 111 | save_path = str(Path(out) / Path(p).name) 112 | s += '%gx%g ' % img.shape[2:] # print string 113 | gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] #  normalization gain whwh 114 | if det is not None and len(det): 115 | # Rescale boxes from imgsz to im0 size 116 | det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round() 117 | 118 | # Print results 119 | for c in det[:, -1].unique(): 120 | n = (det[:, -1] == c).sum() # detections per class 121 | s += '%g %ss, ' % (n, names[int(c)]) # add to string 122 | 123 | # Write results 124 | for *xyxy, conf, cls in det: 125 | if save_txt: # Write to file 126 | xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh 127 | with open(save_path[:save_path.rfind('.')] + '.txt', 'a') as file: 128 | file.write(('%g ' * 5 + '\n') % (cls, *xywh)) # label format 129 | 130 | if save_img or view_img: # Add bbox to image 131 | label = '%s %.2f' % (names[int(cls)], conf) 132 | plot_one_box(xyxy, im0, label=label, color=colors[int(cls)]) 133 | 134 | # Print time (inference + NMS) 135 | print('%sDone. (%.3fs)' % (s, t2 - t1)) 136 | 137 | # Stream results 138 | if view_img: 139 | cv2.imshow(p, im0) 140 | if cv2.waitKey(1) == ord('q'): # q to quit 141 | raise StopIteration 142 | 143 | # Save results (image with detections) 144 | if save_img: 145 | if dataset.mode == 'images': 146 | cv2.imwrite(save_path, im0) 147 | else: 148 | if vid_path != save_path: # new video 149 | vid_path = save_path 150 | if isinstance(vid_writer, cv2.VideoWriter): 151 | vid_writer.release() # release previous video writer 152 | 153 | fps = vid_cap.get(cv2.CAP_PROP_FPS) 154 | w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH)) 155 | h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) 156 | vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*opt.fourcc), fps, (w, h)) 157 | vid_writer.write(im0) 158 | 159 | if save_txt or save_img: 160 | print('Results saved to %s' % os.getcwd() + os.sep + out) 161 | if platform == 'darwin': # MacOS 162 | os.system('open ' + save_path) 163 | 164 | print('Done. (%.3fs)' % (time.time() - t0)) 165 | 166 | 167 | if __name__ == '__main__': 168 | parser = argparse.ArgumentParser() 169 | parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') 170 | parser.add_argument('--names', type=str, default='data/coco.names', help='*.names path') 171 | parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='weights path') 172 | parser.add_argument('--source', type=str, default='data/samples', help='source') # input file/folder, 0 for webcam 173 | parser.add_argument('--output', type=str, default='output', help='output folder') # output folder 174 | parser.add_argument('--img-size', type=int, default=512, help='inference size (pixels)') 175 | parser.add_argument('--conf-thres', type=float, default=0.3, help='object confidence threshold') 176 | parser.add_argument('--iou-thres', type=float, default=0.6, help='IOU threshold for NMS') 177 | parser.add_argument('--fourcc', type=str, default='mp4v', help='output video codec (verify ffmpeg support)') 178 | parser.add_argument('--half', action='store_true', help='half precision FP16 inference') 179 | parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') 180 | parser.add_argument('--view-img', action='store_true', help='display results') 181 | parser.add_argument('--save-txt', action='store_true', help='save results to *.txt') 182 | parser.add_argument('--classes', nargs='+', type=int, help='filter by class') 183 | parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') 184 | parser.add_argument('--augment', action='store_true', help='augmented inference') 185 | opt = parser.parse_args() 186 | # opt.cfg = check_file(opt.cfg) # check file 187 | # opt.names = check_file(opt.names) # check file 188 | print(opt) 189 | 190 | with torch.no_grad(): 191 | detect() 192 | -------------------------------------------------------------------------------- /figure/yolo_demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightsnack/YOLObile/900db66830b56da9e0a99f96d27c39ce2932c886/figure/yolo_demo.jpg -------------------------------------------------------------------------------- /figure/yolobilemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightsnack/YOLObile/900db66830b56da9e0a99f96d27c39ce2932c886/figure/yolobilemap.png -------------------------------------------------------------------------------- /model_pruned/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightsnack/YOLObile/900db66830b56da9e0a99f96d27c39ce2932c886/model_pruned/.gitkeep -------------------------------------------------------------------------------- /model_retrained/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightsnack/YOLObile/900db66830b56da9e0a99f96d27c39ce2932c886/model_retrained/.gitkeep -------------------------------------------------------------------------------- /models.py: -------------------------------------------------------------------------------- 1 | from utils.google_utils import * 2 | from utils.layers import * 3 | from utils.parse_config import * 4 | 5 | ONNX_EXPORT = False 6 | 7 | 8 | def create_modules(module_defs, img_size, cfg): 9 | # Constructs module list of layer blocks from module configuration in module_defs 10 | 11 | img_size = [img_size] * 2 if isinstance(img_size, int) else img_size # expand if necessary 12 | _ = module_defs.pop(0) # cfg training hyperparams (unused) 13 | output_filters = [3] # input channels 14 | module_list = nn.ModuleList() 15 | routs = [] # list of layers which rout to deeper layers 16 | yolo_index = -1 17 | upsample_index = 0 18 | 19 | for i, mdef in enumerate(module_defs): 20 | modules = nn.Sequential() 21 | 22 | if mdef['type'] == 'convolutional': 23 | bn = mdef['batch_normalize'] 24 | filters = mdef['filters'] 25 | k = mdef['size'] # kernel size 26 | stride = mdef['stride'] if 'stride' in mdef else (mdef['stride_y'], mdef['stride_x']) 27 | if isinstance(k, int): # single-size conv 28 | modules.add_module('Conv2d', nn.Conv2d(in_channels=output_filters[-1], 29 | out_channels=filters, 30 | kernel_size=k, 31 | stride=stride, 32 | padding=k // 2 if mdef['pad'] else 0, 33 | groups=mdef['groups'] if 'groups' in mdef else 1, 34 | bias=not bn)) 35 | else: # multiple-size conv 36 | modules.add_module('MixConv2d', MixConv2d(in_ch=output_filters[-1], 37 | out_ch=filters, 38 | k=k, 39 | stride=stride, 40 | bias=not bn)) 41 | 42 | if bn: 43 | modules.add_module('BatchNorm2d', nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4)) 44 | else: 45 | routs.append(i) # detection output (goes into yolo layer) 46 | 47 | if mdef['activation'] == 'leaky': # activation study https://github.com/ultralytics/yolov3/issues/441 48 | modules.add_module('activation', nn.LeakyReLU(0.1, inplace=True)) 49 | elif mdef['activation'] == 'swish': 50 | modules.add_module('activation', Swish()) 51 | elif mdef['activation'] == 'mish': 52 | modules.add_module('activation', Mish()) 53 | 54 | elif mdef['type'] == 'BatchNorm2d': 55 | filters = output_filters[-1] 56 | modules = nn.BatchNorm2d(filters, momentum=0.03, eps=1E-4) 57 | if i == 0 and filters == 3: # normalize RGB image 58 | # imagenet mean and var https://pytorch.org/docs/stable/torchvision/models.html#classification 59 | modules.running_mean = torch.tensor([0.485, 0.456, 0.406]) 60 | modules.running_var = torch.tensor([0.0524, 0.0502, 0.0506]) 61 | 62 | elif mdef['type'] == 'maxpool': 63 | k = mdef['size'] # kernel size 64 | stride = mdef['stride'] 65 | maxpool = nn.MaxPool2d(kernel_size=k, stride=stride, padding=(k - 1) // 2) 66 | if k == 2 and stride == 1: # yolov3-tiny 67 | modules.add_module('ZeroPad2d', nn.ZeroPad2d((0, 1, 0, 1))) 68 | modules.add_module('MaxPool2d', maxpool) 69 | else: 70 | modules = maxpool 71 | 72 | elif mdef['type'] == 'upsample': 73 | if ONNX_EXPORT: # explicitly state size, avoid scale_factor 74 | # if yolo_index== -1: 75 | # yolo_index = 0 76 | g = (upsample_index + 1) * 2 / 32 # gain 77 | modules = nn.Upsample(size=tuple(int(x * g) for x in img_size)) # img_size = (320, 192) 78 | upsample_index = upsample_index + 1 79 | else: 80 | modules = nn.Upsample(scale_factor=mdef['stride']) 81 | 82 | elif mdef['type'] == 'route': # nn.Sequential() placeholder for 'route' layer 83 | layers = mdef['layers'] 84 | filters = sum([output_filters[l + 1 if l > 0 else l] for l in layers]) 85 | routs.extend([i + l if l < 0 else l for l in layers]) 86 | modules = FeatureConcat(layers=layers) 87 | if 'groups' in mdef: 88 | groups = mdef['groups'] 89 | group_id = mdef['group_id'] 90 | modules = RouteGroup(layers=layers,groups=groups, group_id=group_id) 91 | filters //=groups 92 | elif mdef['type'] == 'shortcut': # nn.Sequential() placeholder for 'shortcut' layer 93 | layers = mdef['from'] 94 | filters = output_filters[-1] 95 | routs.extend([i + l if l < 0 else l for l in layers]) 96 | modules = WeightedFeatureFusion(layers=layers, weight='weights_type' in mdef) 97 | 98 | elif mdef['type'] == 'reorg3d': # yolov3-spp-pan-scale 99 | pass 100 | 101 | elif mdef['type'] == 'yolo': 102 | yolo_index += 1 103 | stride = [32, 16, 8] # P5, P4, P3 strides 104 | if any(x in cfg for x in ['panet', 'yolov4', 'cd53']): # stride order reversed 105 | stride = list(reversed(stride)) 106 | layers = mdef['from'] if 'from' in mdef else [] 107 | modules = YOLOLayer(anchors=mdef['anchors'][mdef['mask']], # anchor list 108 | nc=mdef['classes'], # number of classes 109 | img_size=img_size, # (416, 416) 110 | yolo_index=yolo_index, # 0, 1, 2... 111 | layers=layers, # output layers 112 | stride=stride[yolo_index]) 113 | 114 | # Initialize preceding Conv2d() bias (https://arxiv.org/pdf/1708.02002.pdf section 3.3) 115 | try: 116 | j = layers[yolo_index] if 'from' in mdef else -1 117 | # If previous layer is a dropout layer, get the one before 118 | if module_list[j].__class__.__name__ == 'Dropout': 119 | j -= 1 120 | bias_ = module_list[j][0].bias # shape(255,) 121 | bias = bias_[:modules.no * modules.na].view(modules.na, -1) # shape(3,85) 122 | bias[:, 4] += -4.5 # obj 123 | bias[:, 5:] += math.log(0.6 / (modules.nc - 0.99)) # cls (sigmoid(p) = 1/nc) 124 | module_list[j][0].bias = torch.nn.Parameter(bias_, requires_grad=bias_.requires_grad) 125 | except: 126 | print('WARNING: smart bias initialization failure.') 127 | 128 | elif mdef['type'] == 'dropout': 129 | perc = float(mdef['probability']) 130 | modules = nn.Dropout(p=perc) 131 | else: 132 | print('Warning: Unrecognized Layer Type: ' + mdef['type']) 133 | 134 | # Register module list and number of output filters 135 | module_list.append(modules) 136 | output_filters.append(filters) 137 | 138 | routs_binary = [False] * (i + 1) 139 | for i in routs: 140 | routs_binary[i] = True 141 | return module_list, routs_binary 142 | 143 | 144 | class YOLOLayer(nn.Module): 145 | def __init__(self, anchors, nc, img_size, yolo_index, layers, stride): 146 | super(YOLOLayer, self).__init__() 147 | self.anchors = torch.Tensor(anchors) 148 | self.index = yolo_index # index of this layer in layers 149 | self.layers = layers # model output layer indices 150 | self.stride = stride # layer stride 151 | self.nl = len(layers) # number of output layers (3) 152 | self.na = len(anchors) # number of anchors (3) 153 | self.nc = nc # number of classes (80) 154 | self.no = nc + 5 # number of outputs (85) 155 | self.nx, self.ny, self.ng = 0, 0, 0 # initialize number of x, y gridpoints 156 | self.anchor_vec = self.anchors / self.stride 157 | self.anchor_wh = self.anchor_vec.view(1, self.na, 1, 1, 2) 158 | 159 | if ONNX_EXPORT: 160 | self.training = False 161 | self.create_grids((img_size[1] // stride, img_size[0] // stride)) # number x, y grid points 162 | 163 | def create_grids(self, ng=(13, 13), device='cpu'): 164 | self.nx, self.ny = ng # x and y grid size 165 | self.ng = torch.tensor(ng, dtype=torch.float) 166 | 167 | # build xy offsets 168 | if not self.training: 169 | yv, xv = torch.meshgrid([torch.arange(self.ny, device=device), torch.arange(self.nx, device=device)]) 170 | self.grid = torch.stack((xv, yv), 2).view((1, 1, self.ny, self.nx, 2)).float() 171 | 172 | if self.anchor_vec.device != device: 173 | self.anchor_vec = self.anchor_vec.to(device) 174 | self.anchor_wh = self.anchor_wh.to(device) 175 | 176 | def forward(self, p, out): 177 | ASFF = False # https://arxiv.org/abs/1911.09516 178 | if ASFF: 179 | i, n = self.index, self.nl # index in layers, number of layers 180 | p = out[self.layers[i]] 181 | bs, _, ny, nx = p.shape # bs, 255, 13, 13 182 | if (self.nx, self.ny) != (nx, ny): 183 | self.create_grids((nx, ny), p.device) 184 | 185 | # outputs and weights 186 | # w = F.softmax(p[:, -n:], 1) # normalized weights 187 | w = torch.sigmoid(p[:, -n:]) * (2 / n) # sigmoid weights (faster) 188 | # w = w / w.sum(1).unsqueeze(1) # normalize across layer dimension 189 | 190 | # weighted ASFF sum 191 | p = out[self.layers[i]][:, :-n] * w[:, i:i + 1] 192 | for j in range(n): 193 | if j != i: 194 | p += w[:, j:j + 1] * \ 195 | F.interpolate(out[self.layers[j]][:, :-n], size=[ny, nx], mode='bilinear', align_corners=False) 196 | 197 | elif ONNX_EXPORT: 198 | bs = 1 # batch size 199 | else: 200 | bs, _, ny, nx = p.shape # bs, 255, 13, 13 201 | if (self.nx, self.ny) != (nx, ny): 202 | self.create_grids((nx, ny), p.device) 203 | 204 | # p.view(bs, 255, 13, 13) -- > (bs, 3, 13, 13, 85) # (bs, anchors, grid, grid, classes + xywh) 205 | p = p.view(bs, self.na, self.no, self.ny, self.nx).permute(0, 1, 3, 4, 2).contiguous() # prediction 206 | 207 | if self.training: 208 | return p 209 | 210 | elif ONNX_EXPORT: 211 | # Avoid broadcasting for ANE operations 212 | m = self.na * self.nx * self.ny 213 | ng = 1. / self.ng.repeat(m, 1) 214 | grid = self.grid.repeat(1, self.na, 1, 1, 1).view(m, 2) 215 | anchor_wh = self.anchor_wh.repeat(1, 1, self.nx, self.ny, 1).view(m, 2) * ng 216 | 217 | p = p.view(m, self.no) 218 | xy = torch.sigmoid(p[:, 0:2]) + grid # x, y 219 | wh = torch.exp(p[:, 2:4]) * anchor_wh # width, height 220 | p_cls = torch.sigmoid(p[:, 4:5]) if self.nc == 1 else \ 221 | torch.sigmoid(p[:, 5:self.no]) * torch.sigmoid(p[:, 4:5]) # conf 222 | return p_cls, xy * ng, wh 223 | 224 | else: # inference 225 | io = p.clone() # inference output 226 | io[..., :2] = torch.sigmoid(io[..., :2]).to(p.device) + self.grid.to(p.device) # xy 227 | io[..., 2:4] = torch.exp(io[..., 2:4]).to(p.device) * self.anchor_wh.to(p.device) # wh yolo method 228 | io[..., :4] *= self.stride 229 | torch.sigmoid_(io[..., 4:]) 230 | return io.view(bs, -1, self.no), p # view [1, 3, 13, 13, 85] as [1, 507, 85] 231 | 232 | 233 | class Darknet(nn.Module): 234 | # YOLOv3 object detection model 235 | 236 | def __init__(self, cfg, img_size=(416, 416), verbose=False): 237 | super(Darknet, self).__init__() 238 | 239 | self.module_defs = parse_model_cfg(cfg) 240 | self.module_list, self.routs = create_modules(self.module_defs, img_size, cfg) 241 | self.yolo_layers = get_yolo_layers(self) 242 | # torch_utils.initialize_weights(self) 243 | 244 | # Darknet Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 245 | self.version = np.array([0, 2, 5], dtype=np.int32) # (int32) version info: major, minor, revision 246 | self.seen = np.array([0], dtype=np.int64) # (int64) number of images seen during training 247 | self.info(verbose) if not ONNX_EXPORT else None # print model description 248 | 249 | def forward(self, x, augment=False, verbose=False): 250 | 251 | if not augment: 252 | return self.forward_once(x) 253 | else: # Augment images (inference and test only) https://github.com/ultralytics/yolov3/issues/931 254 | img_size = x.shape[-2:] # height, width 255 | s = [0.83, 0.67] # scales 256 | y = [] 257 | for i, xi in enumerate((x, 258 | torch_utils.scale_img(x.flip(3), s[0], same_shape=False), # flip-lr and scale 259 | torch_utils.scale_img(x, s[1], same_shape=False), # scale 260 | )): 261 | # cv2.imwrite('img%g.jpg' % i, 255 * xi[0].numpy().transpose((1, 2, 0))[:, :, ::-1]) 262 | y.append(self.forward_once(xi)[0]) 263 | 264 | y[1][..., :4] /= s[0] # scale 265 | y[1][..., 0] = img_size[1] - y[1][..., 0] # flip lr 266 | y[2][..., :4] /= s[1] # scale 267 | 268 | # for i, yi in enumerate(y): # coco small, medium, large = < 32**2 < 96**2 < 269 | # area = yi[..., 2:4].prod(2)[:, :, None] 270 | # if i == 1: 271 | # yi *= (area < 96. ** 2).float() 272 | # elif i == 2: 273 | # yi *= (area > 32. ** 2).float() 274 | # y[i] = yi 275 | 276 | y = torch.cat(y, 1) 277 | return y, None 278 | 279 | def forward_once(self, x, augment=False, verbose=False): 280 | img_size = x.shape[-2:] # height, width 281 | yolo_out, out = [], [] 282 | if verbose: 283 | print('0', x.shape) 284 | str = '' 285 | 286 | # Augment images (inference and test only) 287 | if augment: # https://github.com/ultralytics/yolov3/issues/931 288 | nb = x.shape[0] # batch size 289 | s = [0.83, 0.67] # scales 290 | x = torch.cat((x, 291 | torch_utils.scale_img(x.flip(3), s[0]), # flip-lr and scale 292 | torch_utils.scale_img(x, s[1]), # scale 293 | ), 0) 294 | 295 | for i, module in enumerate(self.module_list): 296 | name = module.__class__.__name__ 297 | if name in ['WeightedFeatureFusion', 'FeatureConcat', 'RouteGroup']: # sum, concat 298 | if verbose: 299 | l = [i - 1] + module.layers # layers 300 | sh = [list(x.shape)] + [list(out[i].shape) for i in module.layers] # shapes 301 | str = ' >> ' + ' + '.join(['layer %g %s' % x for x in zip(l, sh)]) 302 | x = module(x, out) # WeightedFeatureFusion(), FeatureConcat() 303 | elif name == 'YOLOLayer': 304 | yolo_out.append(module(x, out)) 305 | else: # run module directly, i.e. mtype = 'convolutional', 'upsample', 'maxpool', 'batchnorm2d' etc. 306 | x = module(x) 307 | 308 | out.append(x if self.routs[i] else []) 309 | if verbose: 310 | print('%g/%g %s -' % (i, len(self.module_list), name), list(x.shape), str) 311 | str = '' 312 | 313 | if self.training: # train 314 | return yolo_out 315 | elif ONNX_EXPORT: # export 316 | x = [torch.cat(x, 0) for x in zip(*yolo_out)] 317 | return x[0], torch.cat(x[1:3], 1) # scores, boxes: 3780x80, 3780x4 318 | else: # inference or test 319 | x, p = zip(*yolo_out) # inference output, training output 320 | x = torch.cat(x, 1) # cat yolo outputs 321 | if augment: # de-augment results 322 | x = torch.split(x, nb, dim=0) 323 | x[1][..., :4] /= s[0] # scale 324 | x[1][..., 0] = img_size[1] - x[1][..., 0] # flip lr 325 | x[2][..., :4] /= s[1] # scale 326 | x = torch.cat(x, 1) 327 | return x, p 328 | 329 | def fuse(self): 330 | # Fuse Conv2d + BatchNorm2d layers throughout model 331 | print('Fusing layers...') 332 | fused_list = nn.ModuleList() 333 | for a in list(self.children())[0]: 334 | if isinstance(a, nn.Sequential): 335 | for i, b in enumerate(a): 336 | if isinstance(b, nn.modules.batchnorm.BatchNorm2d): 337 | # fuse this bn layer with the previous conv2d layer 338 | conv = a[i - 1] 339 | fused = torch_utils.fuse_conv_and_bn(conv, b) 340 | a = nn.Sequential(fused, *list(a.children())[i + 1:]) 341 | break 342 | fused_list.append(a) 343 | self.module_list = fused_list 344 | self.info() if not ONNX_EXPORT else None # yolov3-spp reduced from 225 to 152 layers 345 | 346 | def info(self, verbose=False): 347 | torch_utils.model_info(self, verbose) 348 | 349 | def prunedinfo(self, verbose=False): 350 | return torch_utils.prunned_model_info(self, verbose) 351 | 352 | 353 | def get_yolo_layers(model): 354 | return [i for i, m in enumerate(model.module_list) if m.__class__.__name__ == 'YOLOLayer'] # [89, 101, 113] 355 | 356 | 357 | def load_darknet_weights(self, weights, cutoff=-1): 358 | # Parses and loads the weights stored in 'weights' 359 | 360 | # Establish cutoffs (load layers between 0 and cutoff. if cutoff = -1 all are loaded) 361 | file = Path(weights).name 362 | if file == 'darknet53.conv.74': 363 | cutoff = 75 364 | elif file == 'yolov3-tiny.conv.15': 365 | cutoff = 15 366 | 367 | # Read weights file 368 | with open(weights, 'rb') as f: 369 | # Read Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 370 | self.version = np.fromfile(f, dtype=np.int32, count=3) # (int32) version info: major, minor, revision 371 | self.seen = np.fromfile(f, dtype=np.int64, count=1) # (int64) number of images seen during training 372 | 373 | weights = np.fromfile(f, dtype=np.float32) # the rest are weights 374 | 375 | ptr = 0 376 | for i, (mdef, module) in enumerate(zip(self.module_defs[:cutoff], self.module_list[:cutoff])): 377 | if mdef['type'] == 'convolutional': 378 | conv = module[0] 379 | if mdef['batch_normalize']: 380 | # Load BN bias, weights, running mean and running variance 381 | bn = module[1] 382 | nb = bn.bias.numel() # number of biases 383 | # Bias 384 | bn.bias.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.bias)) 385 | ptr += nb 386 | # Weight 387 | bn.weight.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.weight)) 388 | ptr += nb 389 | # Running Mean 390 | bn.running_mean.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.running_mean)) 391 | ptr += nb 392 | # Running Var 393 | bn.running_var.data.copy_(torch.from_numpy(weights[ptr:ptr + nb]).view_as(bn.running_var)) 394 | ptr += nb 395 | else: 396 | # Load conv. bias 397 | nb = conv.bias.numel() 398 | conv_b = torch.from_numpy(weights[ptr:ptr + nb]).view_as(conv.bias) 399 | conv.bias.data.copy_(conv_b) 400 | ptr += nb 401 | # Load conv. weights 402 | nw = conv.weight.numel() # number of weights 403 | conv.weight.data.copy_(torch.from_numpy(weights[ptr:ptr + nw]).view_as(conv.weight)) 404 | ptr += nw 405 | 406 | 407 | def save_weights(self, path='model.weights', cutoff=-1): 408 | # Converts a PyTorch model to Darket format (*.pt to *.weights) 409 | # Note: Does not work if model.fuse() is applied 410 | with open(path, 'wb') as f: 411 | # Write Header https://github.com/AlexeyAB/darknet/issues/2914#issuecomment-496675346 412 | self.version.tofile(f) # (int32) version info: major, minor, revision 413 | self.seen.tofile(f) # (int64) number of images seen during training 414 | 415 | # Iterate through layers 416 | for i, (mdef, module) in enumerate(zip(self.module_defs[:cutoff], self.module_list[:cutoff])): 417 | if mdef['type'] == 'convolutional': 418 | conv_layer = module[0] 419 | # If batch norm, load bn first 420 | if mdef['batch_normalize']: 421 | bn_layer = module[1] 422 | bn_layer.bias.data.cpu().numpy().tofile(f) 423 | bn_layer.weight.data.cpu().numpy().tofile(f) 424 | bn_layer.running_mean.data.cpu().numpy().tofile(f) 425 | bn_layer.running_var.data.cpu().numpy().tofile(f) 426 | # Load conv bias 427 | else: 428 | conv_layer.bias.data.cpu().numpy().tofile(f) 429 | # Load conv weights 430 | conv_layer.weight.data.cpu().numpy().tofile(f) 431 | 432 | 433 | def convert(cfg='cfg/yolov3-spp.cfg', weights='weights/yolov3-spp.weights'): 434 | # Converts between PyTorch and Darknet format per extension (i.e. *.weights convert to *.pt and vice versa) 435 | # from models import *; convert('cfg/yolov3-spp.cfg', 'weights/yolov3-spp.weights') 436 | 437 | # Initialize model 438 | model = Darknet(cfg) 439 | 440 | # Load weights and save 441 | if weights.endswith('.pt'): # if PyTorch format 442 | model.load_state_dict(torch.load(weights, map_location='cpu')['model']) 443 | target = weights.rsplit('.', 1)[0] + '.weights' 444 | save_weights(model, path=target, cutoff=-1) 445 | print("Success: converted '%s' to '%s'" % (weights, target)) 446 | 447 | elif weights.endswith('.weights'): # darknet format 448 | _ = load_darknet_weights(model, weights) 449 | 450 | chkpt = {'epoch': -1, 451 | 'best_fitness': None, 452 | 'training_results': None, 453 | 'model': model.state_dict(), 454 | 'optimizer': None} 455 | 456 | target = weights.rsplit('.', 1)[0] + '.pt' 457 | torch.save(chkpt, target) 458 | print("Success: converted '%s' to '%s'" % (weights, target)) 459 | 460 | else: 461 | print('Error: extension not supported.') 462 | 463 | 464 | def attempt_download(weights): 465 | # Attempt to download pretrained weights if not found locally 466 | weights = weights.strip() 467 | msg = weights + ' missing, try downloading from https://drive.google.com/open?id=1LezFG5g3BCW6iYaV89B2i64cqEUZD7e0' 468 | 469 | if len(weights) > 0 and not os.path.isfile(weights): 470 | d = {'yolov3-spp.weights': '16lYS4bcIdM2HdmyJBVDOvt3Trx6N3W2R', 471 | 'yolov3.weights': '1uTlyDWlnaqXcsKOktP5aH_zRDbfcDp-y', 472 | 'yolov3-tiny.weights': '1CCF-iNIIkYesIDzaPvdwlcf7H9zSsKZQ', 473 | 'yolov3-spp.pt': '1f6Ovy3BSq2wYq4UfvFUpxJFNDFfrIDcR', 474 | 'yolov3.pt': '1SHNFyoe5Ni8DajDNEqgB2oVKBb_NoEad', 475 | 'yolov3-tiny.pt': '10m_3MlpQwRtZetQxtksm9jqHrPTHZ6vo', 476 | 'darknet53.conv.74': '1WUVBid-XuoUBmvzBVUCBl_ELrzqwA8dJ', 477 | 'yolov3-tiny.conv.15': '1Bw0kCpplxUqyRYAJr9RY9SGnOJbo9nEj', 478 | 'yolov3-spp-ultralytics.pt': '1UcR-zVoMs7DH5dj3N1bswkiQTA4dmKF4'} 479 | 480 | file = Path(weights).name 481 | if file in d: 482 | r = gdrive_download(id=d[file], name=weights) 483 | else: # download from pjreddie.com 484 | url = 'https://pjreddie.com/media/files/' + file 485 | print('Downloading ' + url) 486 | r = os.system('curl -f ' + url + ' -o ' + weights) 487 | 488 | # Error check 489 | if not (r == 0 and os.path.exists(weights) and os.path.getsize(weights) > 1E6): # weights exist and > 1MB 490 | os.system('rm ' + weights) # remove partial downloads 491 | raise Exception(msg) 492 | -------------------------------------------------------------------------------- /prune_config/config_csdarknet53pan_avgv8.yaml: -------------------------------------------------------------------------------- 1 | prune_ratios: 2 | # module_list.0.Conv2d.weight: 3 | # 0.0 4 | module_list.1.Conv2d.weight: 5 | 0.84 6 | module_list.2.Conv2d.weight: 7 | 0.84 8 | module_list.3.Conv2d.weight: 9 | 0.84 10 | module_list.5.Conv2d.weight: 11 | 0.84 12 | module_list.6.Conv2d.weight: 13 | 0.84 14 | module_list.8.Conv2d.weight: 15 | 0.84 16 | module_list.9.Conv2d.weight: 17 | 0.84 18 | module_list.10.Conv2d.weight: 19 | 0.84 20 | module_list.12.Conv2d.weight: 21 | 0.84 22 | module_list.13.Conv2d.weight: 23 | 0.84 24 | module_list.15.Conv2d.weight: 25 | 0.84 26 | module_list.17.Conv2d.weight: 27 | 0.84 28 | module_list.18.Conv2d.weight: 29 | 0.84 30 | module_list.19.Conv2d.weight: 31 | 0.84 32 | module_list.21.Conv2d.weight: 33 | 0.84 34 | module_list.22.Conv2d.weight: 35 | 0.84 36 | module_list.23.Conv2d.weight: 37 | 0.84 38 | module_list.25.Conv2d.weight: 39 | 0.84 40 | module_list.26.Conv2d.weight: 41 | 0.84 42 | module_list.28.Conv2d.weight: 43 | 0.84 44 | module_list.29.Conv2d.weight: 45 | 0.84 46 | module_list.31.Conv2d.weight: 47 | 0.84 48 | module_list.32.Conv2d.weight: 49 | 0.84 50 | module_list.34.Conv2d.weight: 51 | 0.84 52 | module_list.35.Conv2d.weight: 53 | 0.84 54 | module_list.37.Conv2d.weight: 55 | 0.84 56 | module_list.38.Conv2d.weight: 57 | 0.84 58 | module_list.40.Conv2d.weight: 59 | 0.84 60 | module_list.41.Conv2d.weight: 61 | 0.84 62 | module_list.43.Conv2d.weight: 63 | 0.84 64 | module_list.44.Conv2d.weight: 65 | 0.84 66 | module_list.46.Conv2d.weight: 67 | 0.84 68 | module_list.48.Conv2d.weight: 69 | 0.84 70 | module_list.49.Conv2d.weight: 71 | 0.84 72 | module_list.50.Conv2d.weight: 73 | 0.84 74 | module_list.52.Conv2d.weight: 75 | 0.84 76 | module_list.53.Conv2d.weight: 77 | 0.84 78 | module_list.54.Conv2d.weight: 79 | 0.84 80 | module_list.56.Conv2d.weight: 81 | 0.84 82 | module_list.57.Conv2d.weight: 83 | 0.84 84 | module_list.59.Conv2d.weight: 85 | 0.84 86 | module_list.60.Conv2d.weight: 87 | 0.84 88 | module_list.62.Conv2d.weight: 89 | 0.84 90 | module_list.63.Conv2d.weight: 91 | 0.84 92 | module_list.65.Conv2d.weight: 93 | 0.84 94 | module_list.66.Conv2d.weight: 95 | 0.84 96 | module_list.68.Conv2d.weight: 97 | 0.84 98 | module_list.69.Conv2d.weight: 99 | 0.84 100 | module_list.71.Conv2d.weight: 101 | 0.84 102 | module_list.72.Conv2d.weight: 103 | 0.84 104 | module_list.74.Conv2d.weight: 105 | 0.84 106 | module_list.75.Conv2d.weight: 107 | 0.84 108 | module_list.77.Conv2d.weight: 109 | 0.84 110 | module_list.79.Conv2d.weight: 111 | 0.84 112 | module_list.80.Conv2d.weight: 113 | 0.84 114 | module_list.81.Conv2d.weight: 115 | 0.84 116 | module_list.83.Conv2d.weight: 117 | 0.84 118 | module_list.84.Conv2d.weight: 119 | 0.84 120 | module_list.85.Conv2d.weight: 121 | 0.84 122 | module_list.87.Conv2d.weight: 123 | 0.84 124 | module_list.88.Conv2d.weight: 125 | 0.84 126 | module_list.90.Conv2d.weight: 127 | 0.84 128 | module_list.91.Conv2d.weight: 129 | 0.84 130 | module_list.93.Conv2d.weight: 131 | 0.84 132 | module_list.94.Conv2d.weight: 133 | 0.84 134 | module_list.96.Conv2d.weight: 135 | 0.84 136 | module_list.98.Conv2d.weight: 137 | 0.84 138 | module_list.99.Conv2d.weight: 139 | 0.84 140 | module_list.100.Conv2d.weight: 141 | 0.84 142 | module_list.101.Conv2d.weight: 143 | 0.84 144 | module_list.108.Conv2d.weight: 145 | 0.84 146 | module_list.109.Conv2d.weight: 147 | 0.84 148 | module_list.110.Conv2d.weight: 149 | 0.84 150 | module_list.111.Conv2d.weight: 151 | 0.84 152 | module_list.114.Conv2d.weight: 153 | 0.84 154 | module_list.116.Conv2d.weight: 155 | 0.84 156 | module_list.117.Conv2d.weight: 157 | 0.84 158 | module_list.118.Conv2d.weight: 159 | 0.84 160 | module_list.119.Conv2d.weight: 161 | 0.84 162 | module_list.120.Conv2d.weight: 163 | 0.84 164 | module_list.121.Conv2d.weight: 165 | 0.84 166 | module_list.124.Conv2d.weight: 167 | 0.84 168 | module_list.126.Conv2d.weight: 169 | 0.84 170 | module_list.127.Conv2d.weight: 171 | 0.84 172 | module_list.128.Conv2d.weight: 173 | 0.84 174 | module_list.129.Conv2d.weight: 175 | 0.84 176 | module_list.130.Conv2d.weight: 177 | 0.84 178 | module_list.131.Conv2d.weight: 179 | 0.84 180 | # module_list.132.Conv2d.weight: 181 | # 0.84 182 | module_list.135.Conv2d.weight: 183 | 0.84 184 | module_list.137.Conv2d.weight: 185 | 0.84 186 | module_list.138.Conv2d.weight: 187 | 0.84 188 | module_list.139.Conv2d.weight: 189 | 0.84 190 | module_list.140.Conv2d.weight: 191 | 0.84 192 | module_list.141.Conv2d.weight: 193 | 0.84 194 | module_list.142.Conv2d.weight: 195 | 0.84 196 | # module_list.143.Conv2d.weight: 197 | # 0.84 198 | module_list.146.Conv2d.weight: 199 | 0.84 200 | module_list.148.Conv2d.weight: 201 | 0.84 202 | module_list.149.Conv2d.weight: 203 | 0.84 204 | module_list.150.Conv2d.weight: 205 | 0.84 206 | module_list.151.Conv2d.weight: 207 | 0.84 208 | module_list.152.Conv2d.weight: 209 | 0.84 210 | module_list.153.Conv2d.weight: 211 | 0.84 212 | # module_list.154.Conv2d.weight: 213 | # 0.84 214 | 215 | 216 | -------------------------------------------------------------------------------- /prune_config/config_csdarknet53pan_slv8.yaml: -------------------------------------------------------------------------------- 1 | prune_ratios: 2 | # module_list.0.Conv2d.weight: 3 | # 0.0 4 | module_list.1.Conv2d.weight: 5 | 0.946 6 | module_list.2.Conv2d.weight: 7 | 0.946 8 | module_list.3.Conv2d.weight: 9 | 0.946 10 | module_list.5.Conv2d.weight: 11 | 0 12 | module_list.6.Conv2d.weight: 13 | 0 14 | module_list.8.Conv2d.weight: 15 | 0.946 16 | module_list.9.Conv2d.weight: 17 | 0.946 18 | module_list.10.Conv2d.weight: 19 | 0.946 20 | module_list.12.Conv2d.weight: 21 | 0.946 22 | module_list.13.Conv2d.weight: 23 | 0.949 24 | module_list.15.Conv2d.weight: 25 | 0.946 26 | module_list.17.Conv2d.weight: 27 | 0.949 28 | module_list.18.Conv2d.weight: 29 | 0 30 | module_list.19.Conv2d.weight: 31 | 0 32 | module_list.21.Conv2d.weight: 33 | 0.95 34 | module_list.22.Conv2d.weight: 35 | 0.949 36 | module_list.23.Conv2d.weight: 37 | 0.957 38 | module_list.25.Conv2d.weight: 39 | 0.949 40 | module_list.26.Conv2d.weight: 41 | 0.95 42 | module_list.28.Conv2d.weight: 43 | 0.949 44 | module_list.29.Conv2d.weight: 45 | 0.95 46 | module_list.31.Conv2d.weight: 47 | 0.949 48 | module_list.32.Conv2d.weight: 49 | 0.95 50 | module_list.34.Conv2d.weight: 51 | 0.949 52 | module_list.35.Conv2d.weight: 53 | 0.95 54 | module_list.37.Conv2d.weight: 55 | 0.949 56 | module_list.38.Conv2d.weight: 57 | 0.95 58 | module_list.40.Conv2d.weight: 59 | 0.949 60 | module_list.41.Conv2d.weight: 61 | 0.95 62 | module_list.43.Conv2d.weight: 63 | 0.949 64 | module_list.44.Conv2d.weight: 65 | 0.95 66 | module_list.46.Conv2d.weight: 67 | 0.949 68 | module_list.48.Conv2d.weight: 69 | 0 70 | module_list.49.Conv2d.weight: 71 | 0.5 72 | module_list.50.Conv2d.weight: 73 | 0 74 | module_list.52.Conv2d.weight: 75 | 0.948 76 | module_list.53.Conv2d.weight: 77 | 0.949 78 | module_list.54.Conv2d.weight: 79 | 0.948 80 | module_list.56.Conv2d.weight: 81 | 0.949 82 | module_list.57.Conv2d.weight: 83 | 0.95 84 | module_list.59.Conv2d.weight: 85 | 0.949 86 | module_list.60.Conv2d.weight: 87 | 0.95 88 | module_list.62.Conv2d.weight: 89 | 0.949 90 | module_list.63.Conv2d.weight: 91 | 0.95 92 | module_list.65.Conv2d.weight: 93 | 0.949 94 | module_list.66.Conv2d.weight: 95 | 0.95 96 | module_list.68.Conv2d.weight: 97 | 0.948 98 | module_list.69.Conv2d.weight: 99 | 0.95 100 | module_list.71.Conv2d.weight: 101 | 0.949 102 | module_list.72.Conv2d.weight: 103 | 0.95 104 | module_list.74.Conv2d.weight: 105 | 0.949 106 | module_list.75.Conv2d.weight: 107 | 0.957 108 | module_list.77.Conv2d.weight: 109 | 0.949 110 | module_list.79.Conv2d.weight: 111 | 0 112 | module_list.80.Conv2d.weight: 113 | 0.5 114 | module_list.81.Conv2d.weight: 115 | 0 116 | module_list.83.Conv2d.weight: 117 | 0.957 118 | module_list.84.Conv2d.weight: 119 | 0.948 120 | module_list.85.Conv2d.weight: 121 | 0.95 122 | module_list.87.Conv2d.weight: 123 | 0.948 124 | module_list.88.Conv2d.weight: 125 | 0.95 126 | module_list.90.Conv2d.weight: 127 | 0.948 128 | module_list.91.Conv2d.weight: 129 | 0.95 130 | module_list.93.Conv2d.weight: 131 | 0.948 132 | module_list.94.Conv2d.weight: 133 | 0.95 134 | module_list.96.Conv2d.weight: 135 | 0.949 136 | module_list.98.Conv2d.weight: 137 | 0.948 138 | module_list.99.Conv2d.weight: 139 | 0.948 140 | module_list.100.Conv2d.weight: 141 | 0.95 142 | module_list.101.Conv2d.weight: 143 | 0.957 144 | module_list.108.Conv2d.weight: 145 | 0.957 146 | module_list.109.Conv2d.weight: 147 | 0.95 148 | module_list.110.Conv2d.weight: 149 | 0 150 | module_list.111.Conv2d.weight: 151 | 0.949 152 | module_list.114.Conv2d.weight: 153 | 0 154 | module_list.116.Conv2d.weight: 155 | 0.949 156 | module_list.117.Conv2d.weight: 157 | 0.95 158 | module_list.118.Conv2d.weight: 159 | 0.949 160 | module_list.119.Conv2d.weight: 161 | 0.95 162 | module_list.120.Conv2d.weight: 163 | 0 164 | module_list.121.Conv2d.weight: 165 | 0.949 166 | module_list.124.Conv2d.weight: 167 | 0 168 | module_list.126.Conv2d.weight: 169 | 0.949 170 | module_list.127.Conv2d.weight: 171 | 0.95 172 | module_list.128.Conv2d.weight: 173 | 0.949 174 | module_list.129.Conv2d.weight: 175 | 0.95 176 | module_list.130.Conv2d.weight: 177 | 0.949 178 | module_list.131.Conv2d.weight: 179 | 0.957 180 | # module_list.132.Conv2d.weight: 181 | # 0.957 182 | module_list.135.Conv2d.weight: 183 | 0.957 184 | module_list.137.Conv2d.weight: 185 | 0.948 186 | module_list.138.Conv2d.weight: 187 | 0.95 188 | module_list.139.Conv2d.weight: 189 | 0.948 190 | module_list.140.Conv2d.weight: 191 | 0.95 192 | module_list.141.Conv2d.weight: 193 | 0.948 194 | module_list.142.Conv2d.weight: 195 | 0.95 196 | # module_list.143.Conv2d.weight: 197 | # 0.948 198 | module_list.146.Conv2d.weight: 199 | 0.957 200 | module_list.148.Conv2d.weight: 201 | 0.957 202 | module_list.149.Conv2d.weight: 203 | 0.957 204 | module_list.150.Conv2d.weight: 205 | 0.948 206 | module_list.151.Conv2d.weight: 207 | 0.957 208 | module_list.152.Conv2d.weight: 209 | 0.95 210 | module_list.153.Conv2d.weight: 211 | 0.948 212 | # module_list.154.Conv2d.weight: 213 | # 0.948 214 | 215 | 216 | -------------------------------------------------------------------------------- /prune_config/config_csdarknet53pan_v10.yaml: -------------------------------------------------------------------------------- 1 | prune_ratios: 2 | # module_list.0.Conv2d.weight: 3 | # 0.0 4 | module_list.1.Conv2d.weight: 5 | 0.4 6 | module_list.2.Conv2d.weight: 7 | 0.6 8 | module_list.3.Conv2d.weight: 9 | 0.5 10 | module_list.5.Conv2d.weight: 11 | 0.7 12 | module_list.6.Conv2d.weight: 13 | 0.5 14 | module_list.8.Conv2d.weight: 15 | 0.7 16 | module_list.9.Conv2d.weight: 17 | 0.5 18 | module_list.10.Conv2d.weight: 19 | 0.6 20 | module_list.12.Conv2d.weight: 21 | 0.6 22 | module_list.13.Conv2d.weight: 23 | 0.72 24 | module_list.15.Conv2d.weight: 25 | 0.6 26 | module_list.17.Conv2d.weight: 27 | 0.72 28 | module_list.18.Conv2d.weight: 29 | 0.88 30 | module_list.19.Conv2d.weight: 31 | 0.88 32 | module_list.21.Conv2d.weight: 33 | 0.91 34 | module_list.22.Conv2d.weight: 35 | 0.72 36 | module_list.23.Conv2d.weight: 37 | 0.88 38 | module_list.25.Conv2d.weight: 39 | 0.72 40 | module_list.26.Conv2d.weight: 41 | 0.91 42 | module_list.28.Conv2d.weight: 43 | 0.72 44 | module_list.29.Conv2d.weight: 45 | 0.91 46 | module_list.31.Conv2d.weight: 47 | 0.72 48 | module_list.32.Conv2d.weight: 49 | 0.91 50 | module_list.34.Conv2d.weight: 51 | 0.72 52 | module_list.35.Conv2d.weight: 53 | 0.91 54 | module_list.37.Conv2d.weight: 55 | 0.72 56 | module_list.38.Conv2d.weight: 57 | 0.93 58 | module_list.40.Conv2d.weight: 59 | 0.72 60 | module_list.41.Conv2d.weight: 61 | 0.93 62 | module_list.43.Conv2d.weight: 63 | 0.72 64 | module_list.44.Conv2d.weight: 65 | 0.93 66 | module_list.46.Conv2d.weight: 67 | 0.72 68 | module_list.48.Conv2d.weight: 69 | 0.85 70 | module_list.49.Conv2d.weight: 71 | 0.93 72 | module_list.50.Conv2d.weight: 73 | 0.85 74 | module_list.52.Conv2d.weight: 75 | 0.85 76 | module_list.53.Conv2d.weight: 77 | 0.77 78 | module_list.54.Conv2d.weight: 79 | 0.85 80 | module_list.56.Conv2d.weight: 81 | 0.72 82 | module_list.57.Conv2d.weight: 83 | 0.93 84 | module_list.59.Conv2d.weight: 85 | 0.72 86 | module_list.60.Conv2d.weight: 87 | 0.93 88 | module_list.62.Conv2d.weight: 89 | 0.75 90 | module_list.63.Conv2d.weight: 91 | 0.93 92 | module_list.65.Conv2d.weight: 93 | 0.75 94 | module_list.66.Conv2d.weight: 95 | 0.93 96 | module_list.68.Conv2d.weight: 97 | 0.85 98 | module_list.69.Conv2d.weight: 99 | 0.93 100 | module_list.71.Conv2d.weight: 101 | 0.75 102 | module_list.72.Conv2d.weight: 103 | 0.93 104 | module_list.74.Conv2d.weight: 105 | 0.75 106 | module_list.75.Conv2d.weight: 107 | 0.91 108 | module_list.77.Conv2d.weight: 109 | 0.75 110 | module_list.79.Conv2d.weight: 111 | 0.85 112 | module_list.80.Conv2d.weight: 113 | 0.93 114 | module_list.81.Conv2d.weight: 115 | 0.85 116 | module_list.83.Conv2d.weight: 117 | 0.91 118 | module_list.84.Conv2d.weight: 119 | 0.85 120 | module_list.85.Conv2d.weight: 121 | 0.93 122 | module_list.87.Conv2d.weight: 123 | 0.85 124 | module_list.88.Conv2d.weight: 125 | 0.93 126 | module_list.90.Conv2d.weight: 127 | 0.85 128 | module_list.91.Conv2d.weight: 129 | 0.93 130 | module_list.93.Conv2d.weight: 131 | 0.85 132 | module_list.94.Conv2d.weight: 133 | 0.93 134 | module_list.96.Conv2d.weight: 135 | 0.75 136 | module_list.98.Conv2d.weight: 137 | 0.85 138 | module_list.99.Conv2d.weight: 139 | 0.85 140 | module_list.100.Conv2d.weight: 141 | 0.93 142 | module_list.101.Conv2d.weight: 143 | 0.91 144 | module_list.108.Conv2d.weight: 145 | 0.91 146 | module_list.109.Conv2d.weight: 147 | 0.95 148 | module_list.110.Conv2d.weight: 149 | 0.87 150 | module_list.111.Conv2d.weight: 151 | 0.75 152 | module_list.114.Conv2d.weight: 153 | 0.75 154 | module_list.116.Conv2d.weight: 155 | 0.75 156 | module_list.117.Conv2d.weight: 157 | 0.96 158 | module_list.118.Conv2d.weight: 159 | 0.75 160 | module_list.119.Conv2d.weight: 161 | 0.95 162 | module_list.120.Conv2d.weight: 163 | 0.85 164 | module_list.121.Conv2d.weight: 165 | 0.75 166 | module_list.124.Conv2d.weight: 167 | 0.75 168 | module_list.126.Conv2d.weight: 169 | 0.75 170 | module_list.127.Conv2d.weight: 171 | 0.95 172 | module_list.128.Conv2d.weight: 173 | 0.75 174 | module_list.129.Conv2d.weight: 175 | 0.96 176 | module_list.130.Conv2d.weight: 177 | 0.75 178 | module_list.131.Conv2d.weight: 179 | 0.91 180 | # module_list.132.Conv2d.weight: 181 | # 0.91 182 | module_list.135.Conv2d.weight: 183 | 0.91 184 | module_list.137.Conv2d.weight: 185 | 0.85 186 | module_list.138.Conv2d.weight: 187 | 0.92 188 | module_list.139.Conv2d.weight: 189 | 0.85 190 | module_list.140.Conv2d.weight: 191 | 0.92 192 | module_list.141.Conv2d.weight: 193 | 0.86 194 | module_list.142.Conv2d.weight: 195 | 0.93 196 | # module_list.143.Conv2d.weight: 197 | # 0.85 198 | module_list.146.Conv2d.weight: 199 | 0.9 200 | module_list.148.Conv2d.weight: 201 | 0.9 202 | module_list.149.Conv2d.weight: 203 | 0.9 204 | module_list.150.Conv2d.weight: 205 | 0.86 206 | module_list.151.Conv2d.weight: 207 | 0.9 208 | module_list.152.Conv2d.weight: 209 | 0.92 210 | module_list.153.Conv2d.weight: 211 | 0.85 212 | # module_list.154.Conv2d.weight: 213 | # 0.85 214 | 215 | 216 | -------------------------------------------------------------------------------- /prune_config/config_csdarknet53pan_v14.yaml: -------------------------------------------------------------------------------- 1 | prune_ratios: 2 | # module_list.0.Conv2d.weight: 3 | # 0.0 4 | module_list.1.Conv2d.weight: 5 | 0.6 6 | module_list.2.Conv2d.weight: 7 | 0.8 8 | module_list.3.Conv2d.weight: 9 | 0.7 10 | module_list.5.Conv2d.weight: 11 | 0.8 12 | module_list.6.Conv2d.weight: 13 | 0.7 14 | module_list.8.Conv2d.weight: 15 | 0.8 16 | module_list.9.Conv2d.weight: 17 | 0.6 18 | module_list.10.Conv2d.weight: 19 | 0.7 20 | module_list.12.Conv2d.weight: 21 | 0.7 22 | module_list.13.Conv2d.weight: 23 | 0.85 24 | module_list.15.Conv2d.weight: 25 | 0.7 26 | module_list.17.Conv2d.weight: 27 | 0.85 28 | module_list.18.Conv2d.weight: 29 | 0.89 30 | module_list.19.Conv2d.weight: 31 | 0.89 32 | module_list.21.Conv2d.weight: 33 | 0.93 34 | module_list.22.Conv2d.weight: 35 | 0.85 36 | module_list.23.Conv2d.weight: 37 | 0.89 38 | module_list.25.Conv2d.weight: 39 | 0.85 40 | module_list.26.Conv2d.weight: 41 | 0.93 42 | module_list.28.Conv2d.weight: 43 | 0.85 44 | module_list.29.Conv2d.weight: 45 | 0.93 46 | module_list.31.Conv2d.weight: 47 | 0.85 48 | module_list.32.Conv2d.weight: 49 | 0.9375 50 | module_list.34.Conv2d.weight: 51 | 0.85 52 | module_list.35.Conv2d.weight: 53 | 0.9375 54 | module_list.37.Conv2d.weight: 55 | 0.85 56 | module_list.38.Conv2d.weight: 57 | 0.9375 58 | module_list.40.Conv2d.weight: 59 | 0.85 60 | module_list.41.Conv2d.weight: 61 | 0.9375 62 | module_list.43.Conv2d.weight: 63 | 0.85 64 | module_list.44.Conv2d.weight: 65 | 0.9375 66 | module_list.46.Conv2d.weight: 67 | 0.85 68 | module_list.48.Conv2d.weight: 69 | 0.92 70 | module_list.49.Conv2d.weight: 71 | 0.9375 72 | module_list.50.Conv2d.weight: 73 | 0.92 74 | module_list.52.Conv2d.weight: 75 | 0.92 76 | module_list.53.Conv2d.weight: 77 | 0.87 78 | module_list.54.Conv2d.weight: 79 | 0.92 80 | module_list.56.Conv2d.weight: 81 | 0.87 82 | module_list.57.Conv2d.weight: 83 | 0.9375 84 | module_list.59.Conv2d.weight: 85 | 0.87 86 | module_list.60.Conv2d.weight: 87 | 0.9375 88 | module_list.62.Conv2d.weight: 89 | 0.87 90 | module_list.63.Conv2d.weight: 91 | 0.9375 92 | module_list.65.Conv2d.weight: 93 | 0.89 94 | module_list.66.Conv2d.weight: 95 | 0.94 96 | module_list.68.Conv2d.weight: 97 | 0.92 98 | module_list.69.Conv2d.weight: 99 | 0.94 100 | module_list.71.Conv2d.weight: 101 | 0.89 102 | module_list.72.Conv2d.weight: 103 | 0.94 104 | module_list.74.Conv2d.weight: 105 | 0.89 106 | module_list.75.Conv2d.weight: 107 | 0.94 108 | module_list.77.Conv2d.weight: 109 | 0.89 110 | module_list.79.Conv2d.weight: 111 | 0.92 112 | module_list.80.Conv2d.weight: 113 | 0.94 114 | module_list.81.Conv2d.weight: 115 | 0.92 116 | module_list.83.Conv2d.weight: 117 | 0.94 118 | module_list.84.Conv2d.weight: 119 | 0.92 120 | module_list.85.Conv2d.weight: 121 | 0.94 122 | module_list.87.Conv2d.weight: 123 | 0.92 124 | module_list.88.Conv2d.weight: 125 | 0.94 126 | module_list.90.Conv2d.weight: 127 | 0.92 128 | module_list.91.Conv2d.weight: 129 | 0.94 130 | module_list.93.Conv2d.weight: 131 | 0.92 132 | module_list.94.Conv2d.weight: 133 | 0.94 134 | module_list.96.Conv2d.weight: 135 | 0.89 136 | module_list.98.Conv2d.weight: 137 | 0.92 138 | module_list.99.Conv2d.weight: 139 | 0.92 140 | module_list.100.Conv2d.weight: 141 | 0.94 142 | module_list.101.Conv2d.weight: 143 | 0.94 144 | module_list.108.Conv2d.weight: 145 | 0.94 146 | module_list.109.Conv2d.weight: 147 | 0.95 148 | module_list.110.Conv2d.weight: 149 | 0.92 150 | module_list.111.Conv2d.weight: 151 | 0.89 152 | module_list.114.Conv2d.weight: 153 | 0.89 154 | module_list.116.Conv2d.weight: 155 | 0.89 156 | module_list.117.Conv2d.weight: 157 | 0.96 158 | module_list.118.Conv2d.weight: 159 | 0.89 160 | module_list.119.Conv2d.weight: 161 | 0.95 162 | module_list.120.Conv2d.weight: 163 | 0.92 164 | module_list.121.Conv2d.weight: 165 | 0.89 166 | module_list.124.Conv2d.weight: 167 | 0.89 168 | module_list.126.Conv2d.weight: 169 | 0.89 170 | module_list.127.Conv2d.weight: 171 | 0.95 172 | module_list.128.Conv2d.weight: 173 | 0.89 174 | module_list.129.Conv2d.weight: 175 | 0.96 176 | module_list.130.Conv2d.weight: 177 | 0.89 178 | module_list.131.Conv2d.weight: 179 | 0.94 180 | # module_list.132.Conv2d.weight: 181 | # 0.9375 182 | module_list.135.Conv2d.weight: 183 | 0.9375 184 | module_list.137.Conv2d.weight: 185 | 0.92 186 | module_list.138.Conv2d.weight: 187 | 0.95 188 | module_list.139.Conv2d.weight: 189 | 0.92 190 | module_list.140.Conv2d.weight: 191 | 0.95 192 | module_list.141.Conv2d.weight: 193 | 0.91 194 | module_list.142.Conv2d.weight: 195 | 0.9375 196 | # module_list.143.Conv2d.weight: 197 | # 0.92 198 | module_list.146.Conv2d.weight: 199 | 0.9375 200 | module_list.148.Conv2d.weight: 201 | 0.9375 202 | module_list.149.Conv2d.weight: 203 | 0.9375 204 | module_list.150.Conv2d.weight: 205 | 0.91 206 | module_list.151.Conv2d.weight: 207 | 0.9375 208 | module_list.152.Conv2d.weight: 209 | 0.95 210 | module_list.153.Conv2d.weight: 211 | 0.92 212 | # module_list.154.Conv2d.weight: 213 | # 0.92 214 | 215 | 216 | -------------------------------------------------------------------------------- /prune_config/config_csdarknet53pan_v2.yaml: -------------------------------------------------------------------------------- 1 | prune_ratios: 2 | # module_list.0.Conv2d.weight: 3 | # 0.0 4 | module_list.1.Conv2d.weight: 5 | 0.3 6 | module_list.2.Conv2d.weight: 7 | 0.3 8 | module_list.3.Conv2d.weight: 9 | 0.3 10 | module_list.5.Conv2d.weight: 11 | 0.3 12 | module_list.6.Conv2d.weight: 13 | 0.4 14 | module_list.8.Conv2d.weight: 15 | 0.4 16 | module_list.9.Conv2d.weight: 17 | 0.3 18 | module_list.10.Conv2d.weight: 19 | 0.4 20 | module_list.12.Conv2d.weight: 21 | 0.3 22 | module_list.13.Conv2d.weight: 23 | 0.4 24 | module_list.15.Conv2d.weight: 25 | 0.3 26 | module_list.17.Conv2d.weight: 27 | 0.5 28 | module_list.18.Conv2d.weight: 29 | 0.5 30 | module_list.19.Conv2d.weight: 31 | 0.5 32 | module_list.21.Conv2d.weight: 33 | 0.5 34 | module_list.22.Conv2d.weight: 35 | 0.5 36 | module_list.23.Conv2d.weight: 37 | 0.5 38 | module_list.25.Conv2d.weight: 39 | 0.5 40 | module_list.26.Conv2d.weight: 41 | 0.52 42 | module_list.28.Conv2d.weight: 43 | 0.48 44 | module_list.29.Conv2d.weight: 45 | 0.52 46 | module_list.31.Conv2d.weight: 47 | 0.48 48 | module_list.32.Conv2d.weight: 49 | 0.48 50 | module_list.34.Conv2d.weight: 51 | 0.48 52 | module_list.35.Conv2d.weight: 53 | 0.48 54 | module_list.37.Conv2d.weight: 55 | 0.48 56 | module_list.38.Conv2d.weight: 57 | 0.48 58 | module_list.40.Conv2d.weight: 59 | 0.48 60 | module_list.41.Conv2d.weight: 61 | 0.48 62 | module_list.43.Conv2d.weight: 63 | 0.48 64 | module_list.44.Conv2d.weight: 65 | 0.48 66 | module_list.46.Conv2d.weight: 67 | 0.48 68 | module_list.48.Conv2d.weight: 69 | 0.48 70 | module_list.49.Conv2d.weight: 71 | 0.52 72 | module_list.50.Conv2d.weight: 73 | 0.48 74 | module_list.52.Conv2d.weight: 75 | 0.48 76 | module_list.53.Conv2d.weight: 77 | 0.48 78 | module_list.54.Conv2d.weight: 79 | 0.48 80 | module_list.56.Conv2d.weight: 81 | 0.48 82 | module_list.57.Conv2d.weight: 83 | 0.52 84 | module_list.59.Conv2d.weight: 85 | 0.5 86 | module_list.60.Conv2d.weight: 87 | 0.5 88 | module_list.62.Conv2d.weight: 89 | 0.5 90 | module_list.63.Conv2d.weight: 91 | 0.5 92 | module_list.65.Conv2d.weight: 93 | 0.5 94 | module_list.66.Conv2d.weight: 95 | 0.5 96 | module_list.68.Conv2d.weight: 97 | 0.5 98 | module_list.69.Conv2d.weight: 99 | 0.5 100 | module_list.71.Conv2d.weight: 101 | 0.5 102 | module_list.72.Conv2d.weight: 103 | 0.5 104 | module_list.74.Conv2d.weight: 105 | 0.5 106 | module_list.75.Conv2d.weight: 107 | 0.5 108 | module_list.77.Conv2d.weight: 109 | 0.5 110 | module_list.79.Conv2d.weight: 111 | 0.5 112 | module_list.80.Conv2d.weight: 113 | 0.5 114 | module_list.81.Conv2d.weight: 115 | 0.5 116 | module_list.83.Conv2d.weight: 117 | 0.5 118 | module_list.84.Conv2d.weight: 119 | 0.5 120 | module_list.85.Conv2d.weight: 121 | 0.5 122 | module_list.87.Conv2d.weight: 123 | 0.5 124 | module_list.88.Conv2d.weight: 125 | 0.5 126 | module_list.90.Conv2d.weight: 127 | 0.5 128 | module_list.91.Conv2d.weight: 129 | 0.5 130 | module_list.93.Conv2d.weight: 131 | 0.5 132 | module_list.94.Conv2d.weight: 133 | 0.52 134 | module_list.96.Conv2d.weight: 135 | 0.5 136 | module_list.98.Conv2d.weight: 137 | 0.52 138 | module_list.99.Conv2d.weight: 139 | 0.52 140 | module_list.100.Conv2d.weight: 141 | 0.52 142 | module_list.101.Conv2d.weight: 143 | 0.5 144 | module_list.108.Conv2d.weight: 145 | 0.5 146 | module_list.109.Conv2d.weight: 147 | 0.52 148 | module_list.110.Conv2d.weight: 149 | 0.5 150 | module_list.111.Conv2d.weight: 151 | 0.5 152 | module_list.114.Conv2d.weight: 153 | 0.5 154 | module_list.116.Conv2d.weight: 155 | 0.5 156 | module_list.117.Conv2d.weight: 157 | 0.52 158 | module_list.118.Conv2d.weight: 159 | 0.5 160 | module_list.119.Conv2d.weight: 161 | 0.52 162 | module_list.120.Conv2d.weight: 163 | 0.52 164 | module_list.121.Conv2d.weight: 165 | 0.5 166 | module_list.124.Conv2d.weight: 167 | 0.5 168 | module_list.126.Conv2d.weight: 169 | 0.5 170 | module_list.127.Conv2d.weight: 171 | 0.52 172 | module_list.128.Conv2d.weight: 173 | 0.5 174 | module_list.129.Conv2d.weight: 175 | 0.52 176 | module_list.130.Conv2d.weight: 177 | 0.5 178 | module_list.131.Conv2d.weight: 179 | 0.5 180 | # module_list.132.Conv2d.weight: 181 | # 0.5 182 | module_list.135.Conv2d.weight: 183 | 0.5 184 | module_list.137.Conv2d.weight: 185 | 0.5 186 | module_list.138.Conv2d.weight: 187 | 0.52 188 | module_list.139.Conv2d.weight: 189 | 0.5 190 | module_list.140.Conv2d.weight: 191 | 0.52 192 | module_list.141.Conv2d.weight: 193 | 0.5 194 | module_list.142.Conv2d.weight: 195 | 0.52 196 | # module_list.143.Conv2d.weight: 197 | # 0.5 198 | module_list.146.Conv2d.weight: 199 | 0.5 200 | module_list.148.Conv2d.weight: 201 | 0.5 202 | module_list.149.Conv2d.weight: 203 | 0.5 204 | module_list.150.Conv2d.weight: 205 | 0.5 206 | module_list.151.Conv2d.weight: 207 | 0.5 208 | module_list.152.Conv2d.weight: 209 | 0.52 210 | module_list.153.Conv2d.weight: 211 | 0.5 212 | # module_list.154.Conv2d.weight: 213 | # 0.5 214 | 215 | 216 | -------------------------------------------------------------------------------- /prune_config/config_csdarknet53pan_v4.yaml: -------------------------------------------------------------------------------- 1 | prune_ratios: 2 | # module_list.0.Conv2d.weight: 3 | # 0.0 4 | module_list.1.Conv2d.weight: 5 | 0.3 6 | module_list.2.Conv2d.weight: 7 | 0.4 8 | module_list.3.Conv2d.weight: 9 | 0.3 10 | module_list.5.Conv2d.weight: 11 | 0.6 12 | module_list.6.Conv2d.weight: 13 | 0.4 14 | module_list.8.Conv2d.weight: 15 | 0.5 16 | module_list.9.Conv2d.weight: 17 | 0.3 18 | module_list.10.Conv2d.weight: 19 | 0.4 20 | module_list.12.Conv2d.weight: 21 | 0.3 22 | module_list.13.Conv2d.weight: 23 | 0.5 24 | module_list.15.Conv2d.weight: 25 | 0.3 26 | module_list.17.Conv2d.weight: 27 | 0.5 28 | module_list.18.Conv2d.weight: 29 | 0.75 30 | module_list.19.Conv2d.weight: 31 | 0.75 32 | module_list.21.Conv2d.weight: 33 | 0.8 34 | module_list.22.Conv2d.weight: 35 | 0.5 36 | module_list.23.Conv2d.weight: 37 | 0.75 38 | module_list.25.Conv2d.weight: 39 | 0.5 40 | module_list.26.Conv2d.weight: 41 | 0.8 42 | module_list.28.Conv2d.weight: 43 | 0.5 44 | module_list.29.Conv2d.weight: 45 | 0.8 46 | module_list.31.Conv2d.weight: 47 | 0.5 48 | module_list.32.Conv2d.weight: 49 | 0.8 50 | module_list.34.Conv2d.weight: 51 | 0.5 52 | module_list.35.Conv2d.weight: 53 | 0.8 54 | module_list.37.Conv2d.weight: 55 | 0.5 56 | module_list.38.Conv2d.weight: 57 | 0.8 58 | module_list.40.Conv2d.weight: 59 | 0.5 60 | module_list.41.Conv2d.weight: 61 | 0.8 62 | module_list.43.Conv2d.weight: 63 | 0.5 64 | module_list.44.Conv2d.weight: 65 | 0.8 66 | module_list.46.Conv2d.weight: 67 | 0.5 68 | module_list.48.Conv2d.weight: 69 | 0.6 70 | module_list.49.Conv2d.weight: 71 | 0.8 72 | module_list.50.Conv2d.weight: 73 | 0.6 74 | module_list.52.Conv2d.weight: 75 | 0.6 76 | module_list.53.Conv2d.weight: 77 | 0.5 78 | module_list.54.Conv2d.weight: 79 | 0.6 80 | module_list.56.Conv2d.weight: 81 | 0.5 82 | module_list.57.Conv2d.weight: 83 | 0.8 84 | module_list.59.Conv2d.weight: 85 | 0.5 86 | module_list.60.Conv2d.weight: 87 | 0.8 88 | module_list.62.Conv2d.weight: 89 | 0.5 90 | module_list.63.Conv2d.weight: 91 | 0.8 92 | module_list.65.Conv2d.weight: 93 | 0.5 94 | module_list.66.Conv2d.weight: 95 | 0.8 96 | module_list.68.Conv2d.weight: 97 | 0.6 98 | module_list.69.Conv2d.weight: 99 | 0.8 100 | module_list.71.Conv2d.weight: 101 | 0.5 102 | module_list.72.Conv2d.weight: 103 | 0.8 104 | module_list.74.Conv2d.weight: 105 | 0.5 106 | module_list.75.Conv2d.weight: 107 | 0.75 108 | module_list.77.Conv2d.weight: 109 | 0.5 110 | module_list.79.Conv2d.weight: 111 | 0.6 112 | module_list.80.Conv2d.weight: 113 | 0.8 114 | module_list.81.Conv2d.weight: 115 | 0.7 116 | module_list.83.Conv2d.weight: 117 | 0.65 118 | module_list.84.Conv2d.weight: 119 | 0.6 120 | module_list.85.Conv2d.weight: 121 | 0.8 122 | module_list.87.Conv2d.weight: 123 | 0.6 124 | module_list.88.Conv2d.weight: 125 | 0.8 126 | module_list.90.Conv2d.weight: 127 | 0.6 128 | module_list.91.Conv2d.weight: 129 | 0.8 130 | module_list.93.Conv2d.weight: 131 | 0.6 132 | module_list.94.Conv2d.weight: 133 | 0.8 134 | module_list.96.Conv2d.weight: 135 | 0.5 136 | module_list.98.Conv2d.weight: 137 | 0.6 138 | module_list.99.Conv2d.weight: 139 | 0.6 140 | module_list.100.Conv2d.weight: 141 | 0.8 142 | module_list.101.Conv2d.weight: 143 | 0.75 144 | module_list.108.Conv2d.weight: 145 | 0.75 146 | module_list.109.Conv2d.weight: 147 | 0.8 148 | module_list.110.Conv2d.weight: 149 | 0.7 150 | module_list.111.Conv2d.weight: 151 | 0.5 152 | module_list.114.Conv2d.weight: 153 | 0.5 154 | module_list.116.Conv2d.weight: 155 | 0.5 156 | module_list.117.Conv2d.weight: 157 | 0.8 158 | module_list.118.Conv2d.weight: 159 | 0.5 160 | module_list.119.Conv2d.weight: 161 | 0.8 162 | module_list.120.Conv2d.weight: 163 | 0.6 164 | module_list.121.Conv2d.weight: 165 | 0.5 166 | module_list.124.Conv2d.weight: 167 | 0.5 168 | module_list.126.Conv2d.weight: 169 | 0.5 170 | module_list.127.Conv2d.weight: 171 | 0.8 172 | module_list.128.Conv2d.weight: 173 | 0.5 174 | module_list.129.Conv2d.weight: 175 | 0.8 176 | module_list.130.Conv2d.weight: 177 | 0.5 178 | module_list.131.Conv2d.weight: 179 | 0.75 180 | # module_list.132.Conv2d.weight: 181 | # 0.75 182 | module_list.135.Conv2d.weight: 183 | 0.75 184 | module_list.137.Conv2d.weight: 185 | 0.7 186 | module_list.138.Conv2d.weight: 187 | 0.8 188 | module_list.139.Conv2d.weight: 189 | 0.7 190 | module_list.140.Conv2d.weight: 191 | 0.8 192 | module_list.141.Conv2d.weight: 193 | 0.7 194 | module_list.142.Conv2d.weight: 195 | 0.8 196 | # module_list.143.Conv2d.weight: 197 | # 0.7 198 | module_list.146.Conv2d.weight: 199 | 0.75 200 | module_list.148.Conv2d.weight: 201 | 0.75 202 | module_list.149.Conv2d.weight: 203 | 0.75 204 | module_list.150.Conv2d.weight: 205 | 0.7 206 | module_list.151.Conv2d.weight: 207 | 0.75 208 | module_list.152.Conv2d.weight: 209 | 0.8 210 | module_list.153.Conv2d.weight: 211 | 0.7 212 | # module_list.154.Conv2d.weight: 213 | # 0.7 214 | 215 | 216 | -------------------------------------------------------------------------------- /prune_config/config_csdarknet53pan_v8.yaml: -------------------------------------------------------------------------------- 1 | prune_ratios: 2 | # module_list.0.Conv2d.weight: 3 | # 0.0 4 | module_list.1.Conv2d.weight: 5 | 0.4 6 | module_list.2.Conv2d.weight: 7 | 0.5 8 | module_list.3.Conv2d.weight: 9 | 0.4 10 | module_list.5.Conv2d.weight: 11 | 0.6 12 | module_list.6.Conv2d.weight: 13 | 0.5 14 | module_list.8.Conv2d.weight: 15 | 0.6 16 | module_list.9.Conv2d.weight: 17 | 0.4 18 | module_list.10.Conv2d.weight: 19 | 0.5 20 | module_list.12.Conv2d.weight: 21 | 0.5 22 | module_list.13.Conv2d.weight: 23 | 0.7 24 | module_list.15.Conv2d.weight: 25 | 0.5 26 | module_list.17.Conv2d.weight: 27 | 0.7 28 | module_list.18.Conv2d.weight: 29 | 0.85 30 | module_list.19.Conv2d.weight: 31 | 0.85 32 | module_list.21.Conv2d.weight: 33 | 0.92 34 | module_list.22.Conv2d.weight: 35 | 0.7 36 | module_list.23.Conv2d.weight: 37 | 0.85 38 | module_list.25.Conv2d.weight: 39 | 0.7 40 | module_list.26.Conv2d.weight: 41 | 0.92 42 | module_list.28.Conv2d.weight: 43 | 0.7 44 | module_list.29.Conv2d.weight: 45 | 0.92 46 | module_list.31.Conv2d.weight: 47 | 0.7 48 | module_list.32.Conv2d.weight: 49 | 0.92 50 | module_list.34.Conv2d.weight: 51 | 0.7 52 | module_list.35.Conv2d.weight: 53 | 0.92 54 | module_list.37.Conv2d.weight: 55 | 0.7 56 | module_list.38.Conv2d.weight: 57 | 0.92 58 | module_list.40.Conv2d.weight: 59 | 0.7 60 | module_list.41.Conv2d.weight: 61 | 0.92 62 | module_list.43.Conv2d.weight: 63 | 0.7 64 | module_list.44.Conv2d.weight: 65 | 0.92 66 | module_list.46.Conv2d.weight: 67 | 0.7 68 | module_list.48.Conv2d.weight: 69 | 0.8 70 | module_list.49.Conv2d.weight: 71 | 0.92 72 | module_list.50.Conv2d.weight: 73 | 0.8 74 | module_list.52.Conv2d.weight: 75 | 0.8 76 | module_list.53.Conv2d.weight: 77 | 0.7 78 | module_list.54.Conv2d.weight: 79 | 0.8 80 | module_list.56.Conv2d.weight: 81 | 0.7 82 | module_list.57.Conv2d.weight: 83 | 0.92 84 | module_list.59.Conv2d.weight: 85 | 0.7 86 | module_list.60.Conv2d.weight: 87 | 0.92 88 | module_list.62.Conv2d.weight: 89 | 0.7 90 | module_list.63.Conv2d.weight: 91 | 0.92 92 | module_list.65.Conv2d.weight: 93 | 0.7 94 | module_list.66.Conv2d.weight: 95 | 0.92 96 | module_list.68.Conv2d.weight: 97 | 0.8 98 | module_list.69.Conv2d.weight: 99 | 0.92 100 | module_list.71.Conv2d.weight: 101 | 0.7 102 | module_list.72.Conv2d.weight: 103 | 0.92 104 | module_list.74.Conv2d.weight: 105 | 0.7 106 | module_list.75.Conv2d.weight: 107 | 0.85 108 | module_list.77.Conv2d.weight: 109 | 0.7 110 | module_list.79.Conv2d.weight: 111 | 0.8 112 | module_list.80.Conv2d.weight: 113 | 0.92 114 | module_list.81.Conv2d.weight: 115 | 0.8 116 | module_list.83.Conv2d.weight: 117 | 0.85 118 | module_list.84.Conv2d.weight: 119 | 0.8 120 | module_list.85.Conv2d.weight: 121 | 0.92 122 | module_list.87.Conv2d.weight: 123 | 0.8 124 | module_list.88.Conv2d.weight: 125 | 0.92 126 | module_list.90.Conv2d.weight: 127 | 0.8 128 | module_list.91.Conv2d.weight: 129 | 0.92 130 | module_list.93.Conv2d.weight: 131 | 0.8 132 | module_list.94.Conv2d.weight: 133 | 0.92 134 | module_list.96.Conv2d.weight: 135 | 0.7 136 | module_list.98.Conv2d.weight: 137 | 0.8 138 | module_list.99.Conv2d.weight: 139 | 0.8 140 | module_list.100.Conv2d.weight: 141 | 0.92 142 | module_list.101.Conv2d.weight: 143 | 0.85 144 | module_list.108.Conv2d.weight: 145 | 0.85 146 | module_list.109.Conv2d.weight: 147 | 0.95 148 | module_list.110.Conv2d.weight: 149 | 0.8 150 | module_list.111.Conv2d.weight: 151 | 0.7 152 | module_list.114.Conv2d.weight: 153 | 0.7 154 | module_list.116.Conv2d.weight: 155 | 0.7 156 | module_list.117.Conv2d.weight: 157 | 0.95 158 | module_list.118.Conv2d.weight: 159 | 0.7 160 | module_list.119.Conv2d.weight: 161 | 0.95 162 | module_list.120.Conv2d.weight: 163 | 0.8 164 | module_list.121.Conv2d.weight: 165 | 0.7 166 | module_list.124.Conv2d.weight: 167 | 0.7 168 | module_list.126.Conv2d.weight: 169 | 0.7 170 | module_list.127.Conv2d.weight: 171 | 0.95 172 | module_list.128.Conv2d.weight: 173 | 0.7 174 | module_list.129.Conv2d.weight: 175 | 0.95 176 | module_list.130.Conv2d.weight: 177 | 0.7 178 | module_list.131.Conv2d.weight: 179 | 0.85 180 | # module_list.132.Conv2d.weight: 181 | # 0.85 182 | module_list.135.Conv2d.weight: 183 | 0.85 184 | module_list.137.Conv2d.weight: 185 | 0.8 186 | module_list.138.Conv2d.weight: 187 | 0.95 188 | module_list.139.Conv2d.weight: 189 | 0.8 190 | module_list.140.Conv2d.weight: 191 | 0.95 192 | module_list.141.Conv2d.weight: 193 | 0.8 194 | module_list.142.Conv2d.weight: 195 | 0.92 196 | # module_list.143.Conv2d.weight: 197 | # 0.8 198 | module_list.146.Conv2d.weight: 199 | 0.85 200 | module_list.148.Conv2d.weight: 201 | 0.85 202 | module_list.149.Conv2d.weight: 203 | 0.85 204 | module_list.150.Conv2d.weight: 205 | 0.8 206 | module_list.151.Conv2d.weight: 207 | 0.85 208 | module_list.152.Conv2d.weight: 209 | 0.92 210 | module_list.153.Conv2d.weight: 211 | 0.8 212 | # module_list.154.Conv2d.weight: 213 | # 0.8 214 | 215 | 216 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # pip install -U -r requirements.txt 2 | # pycocotools requires numpy 1.17 https://github.com/cocodataset/cocoapi/issues/356 3 | numpy == 1.17.5 4 | opencv-python >= 4.1 5 | torch == 1.4.0 6 | torchvision==0.5.0 7 | 8 | matplotlib 9 | pycocotools 10 | tqdm 11 | pillow 12 | tensorboard >= 1.14 13 | PyYAML 14 | thop 15 | 16 | 17 | # Nvidia Apex (optional) for mixed precision training -------------------------- 18 | # git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex 19 | 20 | # Conda commands (in place of pip) --------------------------------------------- 21 | # conda update -yn base -c defaults conda 22 | # conda install -yc anaconda numpy opencv matplotlib tqdm pillow ipython 23 | # conda install -yc conda-forge scikit-image pycocotools tensorboard 24 | # conda install -yc spyder-ide spyder-line-profiler 25 | # conda install -yc pytorch pytorch torchvision 26 | # conda install -yc conda-forge protobuf numpy && pip install onnx # https://github.com/onnx/onnx#linux-and-macos 27 | -------------------------------------------------------------------------------- /runprune.sh: -------------------------------------------------------------------------------- 1 | python train.py --img-size 320 --batch-size 64 --device 0,1,2,3 --epoch 25 --admm-file darknet_admm --cfg cfg/csdarknet53s-panet-spp.cfg --weights weights/best563.pt --data data/coco2014.data 2 | echo finish admm process 3 | python train.py --img-size 320 --batch-size 64 --device 0,1,2,3 --epoch 280 --admm-file darknet_retrain --cfg cfg/csdarknet53s-panet-spp.cfg --weights weights/best563.pt --data data/coco2014.data --multi-scale 4 | echo finish retrain -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import json 3 | 4 | from torch.utils.data import DataLoader 5 | import glob 6 | from models import * 7 | from utils.datasets import * 8 | from utils.utils import * 9 | 10 | 11 | def test(cfg, 12 | data, 13 | weights=None, 14 | batch_size=16, 15 | imgsz=320, 16 | conf_thres=0.001, 17 | iou_thres=0.7, # for nms 18 | save_json=False, 19 | single_cls=False, 20 | augment=False, 21 | model=None, 22 | dataloader=None, 23 | multi_label=True): 24 | # Initialize/load model and set device 25 | if model is None: 26 | is_training = False 27 | device = torch_utils.select_device(opt.device, batch_size=batch_size) 28 | verbose = opt.task == 'test' 29 | 30 | # Remove previous 31 | for f in glob.glob('test_batch*.jpg'): 32 | os.remove(f) 33 | 34 | # Initialize model 35 | model = Darknet(cfg, imgsz) 36 | 37 | # Load weights 38 | attempt_download(weights) 39 | if weights.endswith('.pt'): # pytorch format 40 | model.load_state_dict(torch.load(weights, map_location=device)['model'], strict=False) #['model'] 41 | else: # darknet format 42 | load_darknet_weights(model, weights) 43 | 44 | # Fuse 45 | # model.fuse() 46 | model.to(device) 47 | 48 | if device.type != 'cpu' and torch.cuda.device_count() > 1: 49 | model = nn.DataParallel(model) 50 | else: # called by train.py 51 | is_training = True 52 | device = next(model.parameters()).device # get model device 53 | verbose = False 54 | 55 | # Configure run 56 | data = parse_data_cfg(data) 57 | nc = 1 if single_cls else int(data['classes']) # number of classes 58 | path = data['valid'] # path to test images 59 | names = load_classes(data['names']) # class names 60 | iouv = torch.linspace(0.5, 0.95, 10).to(device) # iou vector for mAP@0.5:0.95 61 | iouv = iouv[0].view(1) # comment for mAP@0.5:0.95 62 | niou = iouv.numel() 63 | 64 | # Dataloader 65 | if dataloader is None: 66 | dataset = LoadImagesAndLabels(path, imgsz, batch_size, rect=True, single_cls=opt.single_cls, pad=0.5) 67 | batch_size = min(batch_size, len(dataset)) 68 | dataloader = DataLoader(dataset, 69 | batch_size=batch_size, 70 | num_workers=min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8]), 71 | pin_memory=True, 72 | collate_fn=dataset.collate_fn) 73 | 74 | seen = 0 75 | model.eval() 76 | _ = model(torch.zeros((1, 3, imgsz, imgsz), device=device)) if device.type != 'cpu' else None # run once 77 | coco91class = coco80_to_coco91_class() 78 | s = ('%20s' + '%10s' * 6) % ('Class', 'Images', 'Targets', 'P', 'R', 'mAP@0.5', 'F1') 79 | p, r, f1, mp, mr, map, mf1, t0, t1 = 0., 0., 0., 0., 0., 0., 0., 0., 0. 80 | loss = torch.zeros(3, device=device) 81 | jdict, stats, ap, ap_class = [], [], [], [] 82 | for batch_i, (imgs, targets, paths, shapes) in enumerate(tqdm(dataloader, desc=s)): 83 | imgs = imgs.to(device).float() / 255.0 # uint8 to float32, 0 - 255 to 0.0 - 1.0 84 | targets = targets.to(device) 85 | nb, _, height, width = imgs.shape # batch size, channels, height, width 86 | whwh = torch.Tensor([width, height, width, height]).to(device) 87 | 88 | # Disable gradients 89 | with torch.no_grad(): 90 | # Run model 91 | t = torch_utils.time_synchronized() 92 | inf_out, train_out = model(imgs, augment=augment) # inference and training outputs 93 | t0 += torch_utils.time_synchronized() - t 94 | 95 | # Compute loss 96 | if is_training: # if model has loss hyperparameters 97 | loss += compute_loss(train_out, targets, model)[1][:3] # GIoU, obj, cls 98 | 99 | # Run NMS 100 | t = torch_utils.time_synchronized() 101 | output = non_max_suppression(inf_out, conf_thres=conf_thres, iou_thres=iou_thres, multi_label=multi_label) 102 | t1 += torch_utils.time_synchronized() - t 103 | 104 | # Statistics per image 105 | for si, pred in enumerate(output): 106 | labels = targets[targets[:, 0] == si, 1:] 107 | nl = len(labels) 108 | tcls = labels[:, 0].tolist() if nl else [] # target class 109 | seen += 1 110 | 111 | if pred is None: 112 | if nl: 113 | stats.append((torch.zeros(0, niou, dtype=torch.bool), torch.Tensor(), torch.Tensor(), tcls)) 114 | continue 115 | 116 | # Append to text file 117 | # with open('test.txt', 'a') as file: 118 | # [file.write('%11.5g' * 7 % tuple(x) + '\n') for x in pred] 119 | 120 | # Clip boxes to image bounds 121 | clip_coords(pred, (height, width)) 122 | 123 | # Append to pycocotools JSON dictionary 124 | if save_json: 125 | # [{"image_id": 42, "category_id": 18, "bbox": [258.15, 41.29, 348.26, 243.78], "score": 0.236}, ... 126 | image_id = int(Path(paths[si]).stem.split('_')[-1]) 127 | box = pred[:, :4].clone() # xyxy 128 | scale_coords(imgs[si].shape[1:], box, shapes[si][0], shapes[si][1]) # to original shape 129 | box = xyxy2xywh(box) # xywh 130 | box[:, :2] -= box[:, 2:] / 2 # xy center to top-left corner 131 | for p, b in zip(pred.tolist(), box.tolist()): 132 | jdict.append({'image_id': image_id, 133 | 'category_id': coco91class[int(p[5])], 134 | 'bbox': [round(x, 3) for x in b], 135 | 'score': round(p[4], 5)}) 136 | 137 | # Assign all predictions as incorrect 138 | correct = torch.zeros(pred.shape[0], niou, dtype=torch.bool, device=device) 139 | if nl: 140 | detected = [] # target indices 141 | tcls_tensor = labels[:, 0] 142 | 143 | # target boxes 144 | tbox = xywh2xyxy(labels[:, 1:5]) * whwh 145 | 146 | # Per target class 147 | for cls in torch.unique(tcls_tensor): 148 | ti = (cls == tcls_tensor).nonzero().view(-1) # prediction indices 149 | pi = (cls == pred[:, 5]).nonzero().view(-1) # target indices 150 | 151 | # Search for detections 152 | if pi.shape[0]: 153 | # Prediction to target ious 154 | ious, i = box_iou(pred[pi, :4], tbox[ti]).max(1) # best ious, indices 155 | 156 | # Append detections 157 | for j in (ious > iouv[0]).nonzero(): 158 | d = ti[i[j]] # detected target 159 | if d not in detected: 160 | detected.append(d) 161 | correct[pi[j]] = ious[j] > iouv # iou_thres is 1xn 162 | if len(detected) == nl: # all targets already located in image 163 | break 164 | 165 | # Append statistics (correct, conf, pcls, tcls) 166 | stats.append((correct.cpu(), pred[:, 4].cpu(), pred[:, 5].cpu(), tcls)) 167 | 168 | # Plot images 169 | if batch_i < 1: 170 | f = 'test_batch%g_gt.jpg' % batch_i # filename 171 | plot_images(imgs, targets, paths=paths, names=names, fname=f) # ground truth 172 | f = 'test_batch%g_pred.jpg' % batch_i 173 | plot_images(imgs, output_to_target(output, width, height), paths=paths, names=names, fname=f) # predictions 174 | 175 | # Compute statistics 176 | stats = [np.concatenate(x, 0) for x in zip(*stats)] # to numpy 177 | if len(stats): 178 | p, r, ap, f1, ap_class = ap_per_class(*stats) 179 | if niou > 1: 180 | p, r, ap, f1 = p[:, 0], r[:, 0], ap.mean(1), ap[:, 0] # [P, R, AP@0.5:0.95, AP@0.5] 181 | mp, mr, map, mf1 = p.mean(), r.mean(), ap.mean(), f1.mean() 182 | nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class 183 | else: 184 | nt = torch.zeros(1) 185 | 186 | # Print results 187 | pf = '%20s' + '%10.3g' * 6 # print format 188 | print(pf % ('all', seen, nt.sum(), mp, mr, map, mf1)) 189 | 190 | # Print results per class 191 | if verbose and nc > 1 and len(stats): 192 | for i, c in enumerate(ap_class): 193 | print(pf % (names[c], seen, nt[c], p[i], r[i], ap[i], f1[i])) 194 | 195 | # Print speeds 196 | if verbose or save_json: 197 | t = tuple(x / seen * 1E3 for x in (t0, t1, t0 + t1)) + (imgsz, imgsz, batch_size) # tuple 198 | print('Speed: %.1f/%.1f/%.1f ms inference/NMS/total per %gx%g image at batch-size %g' % t) 199 | 200 | # Save JSON 201 | if save_json and map and len(jdict): 202 | print('\nCOCO mAP with pycocotools...') 203 | imgIds = [int(Path(x).stem.split('_')[-1]) for x in dataloader.dataset.img_files] 204 | with open('results.json', 'w') as file: 205 | json.dump(jdict, file) 206 | 207 | try: 208 | from pycocotools.coco import COCO 209 | from pycocotools.cocoeval import COCOeval 210 | 211 | # https://github.com/cocodataset/cocoapi/blob/master/PythonAPI/pycocoEvalDemo.ipynb 212 | cocoGt = COCO(glob.glob('../coco/annotations/instances_val*.json')[0]) # initialize COCO ground truth api 213 | cocoDt = cocoGt.loadRes('results.json') # initialize COCO pred api 214 | 215 | cocoEval = COCOeval(cocoGt, cocoDt, 'bbox') 216 | cocoEval.params.imgIds = imgIds # [:32] # only evaluate these images 217 | cocoEval.evaluate() 218 | cocoEval.accumulate() 219 | cocoEval.summarize() 220 | # mf1, map = cocoEval.stats[:2] # update to pycocotools results (mAP@0.5:0.95, mAP@0.5) 221 | except: 222 | print('WARNING: pycocotools must be installed with numpy==1.17 to run correctly. ' 223 | 'See https://github.com/cocodataset/cocoapi/issues/356') 224 | 225 | # Return results 226 | maps = np.zeros(nc) + map 227 | for i, c in enumerate(ap_class): 228 | maps[c] = ap[i] 229 | return (mp, mr, map, mf1, *(loss.cpu() / len(dataloader)).tolist()), maps 230 | 231 | 232 | if __name__ == '__main__': 233 | parser = argparse.ArgumentParser(prog='test.py') 234 | parser.add_argument('--cfg', type=str, default='cfg/yolov3-spp.cfg', help='*.cfg path') 235 | parser.add_argument('--data', type=str, default='data/coco2014.data', help='*.data path') 236 | parser.add_argument('--weights', type=str, default='weights/yolov3-spp-ultralytics.pt', help='weights path') 237 | parser.add_argument('--batch-size', type=int, default=16, help='size of each image batch') 238 | parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)') 239 | parser.add_argument('--conf-thres', type=float, default=0.001, help='object confidence threshold') 240 | parser.add_argument('--iou-thres', type=float, default=0.5, help='IOU threshold for NMS') 241 | parser.add_argument('--save-json', action='store_true', help='save a cocoapi-compatible JSON results file') 242 | parser.add_argument('--task', default='test', help="'test', 'study', 'benchmark'") 243 | parser.add_argument('--device', default='', help='device id (i.e. 0 or 0,1) or cpu') 244 | parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset') 245 | parser.add_argument('--augment', action='store_true', help='augmented inference') 246 | opt = parser.parse_args() 247 | opt.save_json = opt.save_json or any([x in opt.data for x in ['coco.data', 'coco2014.data', 'coco2017.data']]) 248 | # opt.cfg = check_file(opt.cfg) # check file 249 | # opt.data = check_file(opt.data) # check file 250 | print(opt) 251 | 252 | # task = 'test', 'study', 'benchmark' 253 | if opt.task == 'test': # (default) test normally 254 | results,map = test(opt.cfg, 255 | opt.data, 256 | opt.weights, 257 | opt.batch_size, 258 | opt.img_size, 259 | opt.conf_thres, 260 | opt.iou_thres, 261 | opt.save_json, 262 | opt.single_cls, 263 | opt.augment) 264 | # print(results, map) 265 | 266 | elif opt.task == 'benchmark': # mAPs at 256-640 at conf 0.5 and 0.7 267 | y = [] 268 | for i in list(range(256, 640, 128)): # img-size 269 | for j in [0.6, 0.7]: # iou-thres 270 | t = time.time() 271 | r = test(opt.cfg, opt.data, opt.weights, opt.batch_size, i, opt.conf_thres, j, opt.save_json)[0] 272 | y.append(r + (time.time() - t,)) 273 | np.savetxt('benchmark.txt', y, fmt='%10.4g') # y = np.loadtxt('study.txt') -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nightsnack/YOLObile/900db66830b56da9e0a99f96d27c39ce2932c886/utils/__init__.py -------------------------------------------------------------------------------- /utils/adabound.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | import torch 4 | from torch.optim.optimizer import Optimizer 5 | 6 | 7 | class AdaBound(Optimizer): 8 | """Implements AdaBound algorithm. 9 | It has been proposed in `Adaptive Gradient Methods with Dynamic Bound of Learning Rate`_. 10 | Arguments: 11 | params (iterable): iterable of parameters to optimize or dicts defining 12 | parameter groups 13 | lr (float, optional): Adam learning rate (default: 1e-3) 14 | betas (Tuple[float, float], optional): coefficients used for computing 15 | running averages of gradient and its square (default: (0.9, 0.999)) 16 | final_lr (float, optional): final (SGD) learning rate (default: 0.1) 17 | gamma (float, optional): convergence speed of the bound functions (default: 1e-3) 18 | eps (float, optional): term added to the denominator to improve 19 | numerical stability (default: 1e-8) 20 | weight_decay (float, optional): weight decay (L2 penalty) (default: 0) 21 | amsbound (boolean, optional): whether to use the AMSBound variant of this algorithm 22 | .. Adaptive Gradient Methods with Dynamic Bound of Learning Rate: 23 | https://openreview.net/forum?id=Bkg3g2R9FX 24 | """ 25 | 26 | def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), final_lr=0.1, gamma=1e-3, 27 | eps=1e-8, weight_decay=0, amsbound=False): 28 | if not 0.0 <= lr: 29 | raise ValueError("Invalid learning rate: {}".format(lr)) 30 | if not 0.0 <= eps: 31 | raise ValueError("Invalid epsilon value: {}".format(eps)) 32 | if not 0.0 <= betas[0] < 1.0: 33 | raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0])) 34 | if not 0.0 <= betas[1] < 1.0: 35 | raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1])) 36 | if not 0.0 <= final_lr: 37 | raise ValueError("Invalid final learning rate: {}".format(final_lr)) 38 | if not 0.0 <= gamma < 1.0: 39 | raise ValueError("Invalid gamma parameter: {}".format(gamma)) 40 | defaults = dict(lr=lr, betas=betas, final_lr=final_lr, gamma=gamma, eps=eps, 41 | weight_decay=weight_decay, amsbound=amsbound) 42 | super(AdaBound, self).__init__(params, defaults) 43 | 44 | self.base_lrs = list(map(lambda group: group['lr'], self.param_groups)) 45 | 46 | def __setstate__(self, state): 47 | super(AdaBound, self).__setstate__(state) 48 | for group in self.param_groups: 49 | group.setdefault('amsbound', False) 50 | 51 | def step(self, closure=None): 52 | """Performs a single optimization step. 53 | Arguments: 54 | closure (callable, optional): A closure that reevaluates the model 55 | and returns the loss. 56 | """ 57 | loss = None 58 | if closure is not None: 59 | loss = closure() 60 | 61 | for group, base_lr in zip(self.param_groups, self.base_lrs): 62 | for p in group['params']: 63 | if p.grad is None: 64 | continue 65 | grad = p.grad.data 66 | if grad.is_sparse: 67 | raise RuntimeError( 68 | 'Adam does not support sparse gradients, please consider SparseAdam instead') 69 | amsbound = group['amsbound'] 70 | 71 | state = self.state[p] 72 | 73 | # State initialization 74 | if len(state) == 0: 75 | state['step'] = 0 76 | # Exponential moving average of gradient values 77 | state['exp_avg'] = torch.zeros_like(p.data) 78 | # Exponential moving average of squared gradient values 79 | state['exp_avg_sq'] = torch.zeros_like(p.data) 80 | if amsbound: 81 | # Maintains max of all exp. moving avg. of sq. grad. values 82 | state['max_exp_avg_sq'] = torch.zeros_like(p.data) 83 | 84 | exp_avg, exp_avg_sq = state['exp_avg'], state['exp_avg_sq'] 85 | if amsbound: 86 | max_exp_avg_sq = state['max_exp_avg_sq'] 87 | beta1, beta2 = group['betas'] 88 | 89 | state['step'] += 1 90 | 91 | if group['weight_decay'] != 0: 92 | grad = grad.add(group['weight_decay'], p.data) 93 | 94 | # Decay the first and second moment running average coefficient 95 | exp_avg.mul_(beta1).add_(1 - beta1, grad) 96 | exp_avg_sq.mul_(beta2).addcmul_(1 - beta2, grad, grad) 97 | if amsbound: 98 | # Maintains the maximum of all 2nd moment running avg. till now 99 | torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq) 100 | # Use the max. for normalizing running avg. of gradient 101 | denom = max_exp_avg_sq.sqrt().add_(group['eps']) 102 | else: 103 | denom = exp_avg_sq.sqrt().add_(group['eps']) 104 | 105 | bias_correction1 = 1 - beta1 ** state['step'] 106 | bias_correction2 = 1 - beta2 ** state['step'] 107 | step_size = group['lr'] * math.sqrt(bias_correction2) / bias_correction1 108 | 109 | # Applies bounds on actual learning rate 110 | # lr_scheduler cannot affect final_lr, this is a workaround to apply lr decay 111 | final_lr = group['final_lr'] * group['lr'] / base_lr 112 | lower_bound = final_lr * (1 - 1 / (group['gamma'] * state['step'] + 1)) 113 | upper_bound = final_lr * (1 + 1 / (group['gamma'] * state['step'])) 114 | step_size = torch.full_like(denom, step_size) 115 | step_size.div_(denom).clamp_(lower_bound, upper_bound).mul_(exp_avg) 116 | 117 | p.data.add_(-step_size) 118 | 119 | return loss 120 | 121 | 122 | class AdaBoundW(Optimizer): 123 | """Implements AdaBound algorithm with Decoupled Weight Decay (arxiv.org/abs/1711.05101) 124 | It has been proposed in `Adaptive Gradient Methods with Dynamic Bound of Learning Rate`_. 125 | Arguments: 126 | params (iterable): iterable of parameters to optimize or dicts defining 127 | parameter groups 128 | lr (float, optional): Adam learning rate (default: 1e-3) 129 | betas (Tuple[float, float], optional): coefficients used for computing 130 | running averages of gradient and its square (default: (0.9, 0.999)) 131 | final_lr (float, optional): final (SGD) learning rate (default: 0.1) 132 | gamma (float, optional): convergence speed of the bound functions (default: 1e-3) 133 | eps (float, optional): term added to the denominator to improve 134 | numerical stability (default: 1e-8) 135 | weight_decay (float, optional): weight decay (L2 penalty) (default: 0) 136 | amsbound (boolean, optional): whether to use the AMSBound variant of this algorithm 137 | .. Adaptive Gradient Methods with Dynamic Bound of Learning Rate: 138 | https://openreview.net/forum?id=Bkg3g2R9FX 139 | """ 140 | 141 | def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), final_lr=0.1, gamma=1e-3, 142 | eps=1e-8, weight_decay=0, amsbound=False): 143 | if not 0.0 <= lr: 144 | raise ValueError("Invalid learning rate: {}".format(lr)) 145 | if not 0.0 <= eps: 146 | raise ValueError("Invalid epsilon value: {}".format(eps)) 147 | if not 0.0 <= betas[0] < 1.0: 148 | raise ValueError("Invalid beta parameter at index 0: {}".format(betas[0])) 149 | if not 0.0 <= betas[1] < 1.0: 150 | raise ValueError("Invalid beta parameter at index 1: {}".format(betas[1])) 151 | if not 0.0 <= final_lr: 152 | raise ValueError("Invalid final learning rate: {}".format(final_lr)) 153 | if not 0.0 <= gamma < 1.0: 154 | raise ValueError("Invalid gamma parameter: {}".format(gamma)) 155 | defaults = dict(lr=lr, betas=betas, final_lr=final_lr, gamma=gamma, eps=eps, 156 | weight_decay=weight_decay, amsbound=amsbound) 157 | super(AdaBoundW, self).__init__(params, defaults) 158 | 159 | self.base_lrs = list(map(lambda group: group['lr'], self.param_groups)) 160 | 161 | def __setstate__(self, state): 162 | super(AdaBoundW, self).__setstate__(state) 163 | for group in self.param_groups: 164 | group.setdefault('amsbound', False) 165 | 166 | def step(self, closure=None): 167 | """Performs a single optimization step. 168 | Arguments: 169 | closure (callable, optional): A closure that reevaluates the model 170 | and returns the loss. 171 | """ 172 | loss = None 173 | if closure is not None: 174 | loss = closure() 175 | 176 | for group, base_lr in zip(self.param_groups, self.base_lrs): 177 | for p in group['params']: 178 | if p.grad is None: 179 | continue 180 | grad = p.grad.data 181 | if grad.is_sparse: 182 | raise RuntimeError( 183 | 'Adam does not support sparse gradients, please consider SparseAdam instead') 184 | amsbound = group['amsbound'] 185 | 186 | state = self.state[p] 187 | 188 | # State initialization 189 | if len(state) == 0: 190 | state['step'] = 0 191 | # Exponential moving average of gradient values 192 | state['exp_avg'] = torch.zeros_like(p.data) 193 | # Exponential moving average of squared gradient values 194 | state['exp_avg_sq'] = torch.zeros_like(p.data) 195 | if amsbound: 196 | # Maintains max of all exp. moving avg. of sq. grad. values 197 | state['max_exp_avg_sq'] = torch.zeros_like(p.data) 198 | 199 | exp_avg, exp_avg_sq = state['exp_avg'], state['exp_avg_sq'] 200 | if amsbound: 201 | max_exp_avg_sq = state['max_exp_avg_sq'] 202 | beta1, beta2 = group['betas'] 203 | 204 | state['step'] += 1 205 | 206 | # Decay the first and second moment running average coefficient 207 | exp_avg.mul_(beta1).add_(1 - beta1, grad) 208 | exp_avg_sq.mul_(beta2).addcmul_(1 - beta2, grad, grad) 209 | if amsbound: 210 | # Maintains the maximum of all 2nd moment running avg. till now 211 | torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq) 212 | # Use the max. for normalizing running avg. of gradient 213 | denom = max_exp_avg_sq.sqrt().add_(group['eps']) 214 | else: 215 | denom = exp_avg_sq.sqrt().add_(group['eps']) 216 | 217 | bias_correction1 = 1 - beta1 ** state['step'] 218 | bias_correction2 = 1 - beta2 ** state['step'] 219 | step_size = group['lr'] * math.sqrt(bias_correction2) / bias_correction1 220 | 221 | # Applies bounds on actual learning rate 222 | # lr_scheduler cannot affect final_lr, this is a workaround to apply lr decay 223 | final_lr = group['final_lr'] * group['lr'] / base_lr 224 | lower_bound = final_lr * (1 - 1 / (group['gamma'] * state['step'] + 1)) 225 | upper_bound = final_lr * (1 + 1 / (group['gamma'] * state['step'])) 226 | step_size = torch.full_like(denom, step_size) 227 | step_size.div_(denom).clamp_(lower_bound, upper_bound).mul_(exp_avg) 228 | 229 | if group['weight_decay'] != 0: 230 | decayed_weights = torch.mul(p.data, group['weight_decay']) 231 | p.data.add_(-step_size) 232 | p.data.sub_(decayed_weights) 233 | else: 234 | p.data.add_(-step_size) 235 | 236 | return loss 237 | -------------------------------------------------------------------------------- /utils/checkfile.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | imagedir = 'data/coco/images/train2017/' 5 | labeldir = 'data/coco/labels/train2017' 6 | newdir = 'data/coco/empty/train2017' 7 | labellist = os.listdir(labeldir) 8 | emptyfile = 0 9 | for image in os.listdir(imagedir): 10 | label = image.replace("jpg","txt") 11 | if label not in labellist: 12 | print("Label {} not exits".format(label)) 13 | emptyfile = emptyfile+1 14 | shutil.move(imagedir+image, newdir) 15 | print(emptyfile) 16 | -------------------------------------------------------------------------------- /utils/cleanfile.py: -------------------------------------------------------------------------------- 1 | # f = open('data/coco/val2017.txt', 'r') 2 | # f1 = open('data/coco/val2017.shapes', 'r') 3 | import os 4 | 5 | imagedir = 'data/coco/images/train2017/' 6 | newdir = 'data/coco/empty/train2017' 7 | nonemptyfile = 0 8 | imagelist = os.listdir(newdir) 9 | 10 | with open('data/coco/train2017.txt', 'r') as r: 11 | lines=r.readlines() 12 | with open('data/coco/train2017.shapes', 'r') as r: 13 | sline=r.readlines() 14 | with open('data/coco/train2020.txt','w') as w: 15 | with open('data/coco/train2020.shapes', 'w') as ws: 16 | for i in range(len(lines)): 17 | imagename = lines[i][-17:-1] 18 | if imagename not in imagelist: 19 | w.write(lines[i]) 20 | ws.write(sline[i]) 21 | nonemptyfile = nonemptyfile+1 22 | 23 | print(nonemptyfile) 24 | -------------------------------------------------------------------------------- /utils/evolve.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #for i in 0 1 2 3 3 | #do 4 | # t=ultralytics/yolov3:v139 && sudo docker pull $t && sudo nvidia-docker run -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t utils/evolve.sh $i 5 | # sleep 30 6 | #done 7 | 8 | while true; do 9 | # python3 train.py --data ../data/sm4/out.data --img-size 320 --epochs 100 --batch 64 --accum 1 --weights yolov3-tiny.conv.15 --multi --bucket ult/wer --evolve --cache --device $1 --cfg yolov3-tiny3-1cls.cfg --single --adam 10 | # python3 train.py --data ../out/data.data --img-size 608 --epochs 10 --batch 8 --accum 8 --weights ultralytics68.pt --multi --bucket ult/athena --evolve --device $1 --cfg yolov3-spp-1cls.cfg 11 | 12 | python3 train.py --data coco2014.data --img-size 512 608 --epochs 27 --batch 8 --accum 8 --evolve --weights '' --bucket ult/coco/sppa_512 --device $1 --cfg yolov3-sppa.cfg --multi 13 | done 14 | 15 | 16 | # coco epoch times --img-size 416 608 --epochs 27 --batch 16 --accum 4 17 | # 36:34 2080ti 18 | # 21:58 V100 19 | # 63:00 T4 -------------------------------------------------------------------------------- /utils/gcp.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # New VM 4 | rm -rf sample_data yolov3 5 | git clone https://github.com/ultralytics/yolov3 6 | # git clone -b test --depth 1 https://github.com/ultralytics/yolov3 test # branch 7 | # sudo apt-get install zip 8 | #git clone https://github.com/NVIDIA/apex && cd apex && pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" . --user && cd .. && rm -rf apex 9 | sudo conda install -yc conda-forge scikit-image pycocotools 10 | # python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('193Zp_ye-3qXMonR1nZj3YyxMtQkMy50k','coco2014.zip')" 11 | python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1WQT6SOktSe8Uw6r10-2JhbEhMY5DJaph','coco2017.zip')" 12 | python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('1C3HewOG9akA3y456SZLBJZfNDPkBwAto','knife.zip')" 13 | python3 -c "from yolov3.utils.google_utils import gdrive_download; gdrive_download('13g3LqdpkNE8sPosVJT6KFXlfoMypzRP4','sm4.zip')" 14 | sudo shutdown 15 | 16 | # Mount local SSD 17 | lsblk 18 | sudo mkfs.ext4 -F /dev/nvme0n1 19 | sudo mkdir -p /mnt/disks/nvme0n1 20 | sudo mount /dev/nvme0n1 /mnt/disks/nvme0n1 21 | sudo chmod a+w /mnt/disks/nvme0n1 22 | cp -r coco /mnt/disks/nvme0n1 23 | 24 | # Kill All 25 | t=ultralytics/yolov3:v1 26 | docker kill $(docker ps -a -q --filter ancestor=$t) 27 | 28 | # Evolve coco 29 | sudo -s 30 | t=ultralytics/yolov3:evolve 31 | # docker kill $(docker ps -a -q --filter ancestor=$t) 32 | for i in 0 1 6 7 33 | do 34 | docker pull $t && docker run --gpus all -d --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t bash utils/evolve.sh $i 35 | sleep 30 36 | done 37 | 38 | #COCO training 39 | n=131 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 640 --epochs 300 --batch 16 --weights '' --device 0 --cfg yolov3-spp.cfg --bucket ult/coco --name $n && sudo shutdown 40 | n=132 && t=ultralytics/coco:v131 && sudo docker pull $t && sudo docker run -it --gpus all --ipc=host -v "$(pwd)"/coco:/usr/src/coco $t python3 train.py --data coco2014.data --img-size 320 640 --epochs 300 --batch 64 --weights '' --device 0 --cfg yolov3-tiny.cfg --bucket ult/coco --name $n && sudo shutdown 41 | -------------------------------------------------------------------------------- /utils/google_utils.py: -------------------------------------------------------------------------------- 1 | # This file contains google utils: https://cloud.google.com/storage/docs/reference/libraries 2 | # pip install --upgrade google-cloud-storage 3 | 4 | import os 5 | import time 6 | 7 | 8 | # from google.cloud import storage 9 | 10 | 11 | def gdrive_download(id='1HaXkef9z6y5l4vUnCYgdmEAj61c6bfWO', name='coco.zip'): 12 | # https://gist.github.com/tanaikech/f0f2d122e05bf5f971611258c22c110f 13 | # Downloads a file from Google Drive, accepting presented query 14 | # from utils.google_utils import *; gdrive_download() 15 | t = time.time() 16 | 17 | print('Downloading https://drive.google.com/uc?export=download&id=%s as %s... ' % (id, name), end='') 18 | os.remove(name) if os.path.exists(name) else None # remove existing 19 | os.remove('cookie') if os.path.exists('cookie') else None 20 | 21 | # Attempt file download 22 | os.system("curl -c ./cookie -s -L \"https://drive.google.com/uc?export=download&id=%s\" > /dev/null" % id) 23 | if os.path.exists('cookie'): # large file 24 | s = "curl -Lb ./cookie \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=%s\" -o %s" % ( 25 | id, name) 26 | else: # small file 27 | s = "curl -s -L -o %s 'https://drive.google.com/uc?export=download&id=%s'" % (name, id) 28 | r = os.system(s) # execute, capture return values 29 | os.remove('cookie') if os.path.exists('cookie') else None 30 | 31 | # Error check 32 | if r != 0: 33 | os.remove(name) if os.path.exists(name) else None # remove partial 34 | print('Download error ') # raise Exception('Download error') 35 | return r 36 | 37 | # Unzip if archive 38 | if name.endswith('.zip'): 39 | print('unzipping... ', end='') 40 | os.system('unzip -q %s' % name) # unzip 41 | os.remove(name) # remove zip to free space 42 | 43 | print('Done (%.1fs)' % (time.time() - t)) 44 | return r 45 | 46 | 47 | def upload_blob(bucket_name, source_file_name, destination_blob_name): 48 | # Uploads a file to a bucket 49 | # https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-python 50 | 51 | storage_client = storage.Client() 52 | bucket = storage_client.get_bucket(bucket_name) 53 | blob = bucket.blob(destination_blob_name) 54 | 55 | blob.upload_from_filename(source_file_name) 56 | 57 | print('File {} uploaded to {}.'.format( 58 | source_file_name, 59 | destination_blob_name)) 60 | 61 | 62 | def download_blob(bucket_name, source_blob_name, destination_file_name): 63 | # Uploads a blob from a bucket 64 | storage_client = storage.Client() 65 | bucket = storage_client.get_bucket(bucket_name) 66 | blob = bucket.blob(source_blob_name) 67 | 68 | blob.download_to_filename(destination_file_name) 69 | 70 | print('Blob {} downloaded to {}.'.format( 71 | source_blob_name, 72 | destination_file_name)) 73 | -------------------------------------------------------------------------------- /utils/layers.py: -------------------------------------------------------------------------------- 1 | import torch.nn.functional as F 2 | 3 | from utils.utils import * 4 | 5 | 6 | def make_divisible(v, divisor): 7 | # Function ensures all layers have a channel number that is divisible by 8 8 | # https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py 9 | return math.ceil(v / divisor) * divisor 10 | 11 | 12 | class Flatten(nn.Module): 13 | # Use after nn.AdaptiveAvgPool2d(1) to remove last 2 dimensions 14 | def forward(self, x): 15 | return x.view(x.size(0), -1) 16 | 17 | 18 | class Concat(nn.Module): 19 | # Concatenate a list of tensors along dimension 20 | def __init__(self, dimension=1): 21 | super(Concat, self).__init__() 22 | self.d = dimension 23 | 24 | def forward(self, x): 25 | return torch.cat(x, self.d) 26 | 27 | class RouteGroup(nn.Module): 28 | 29 | def __init__(self, layers, groups, group_id): 30 | super(RouteGroup, self).__init__() 31 | self.layers = layers 32 | self.multi = len(layers) > 1 33 | self.groups = groups 34 | self.group_id = group_id 35 | 36 | def forward(self, x, outputs): 37 | if self.multi: 38 | outs = [] 39 | for layer in self.layers: 40 | out = torch.chunk(outputs[layer], self.groups, dim=1) 41 | outs.append(out[self.group_id]) 42 | return torch.cat(outs, dim=1) 43 | else: 44 | out = torch.chunk(outputs[self.layers[0]], self.groups, dim=1) 45 | return out[self.group_id] 46 | 47 | class FeatureConcat(nn.Module): 48 | def __init__(self, layers): 49 | super(FeatureConcat, self).__init__() 50 | self.layers = layers # layer indices 51 | self.multiple = len(layers) > 1 # multiple layers flag 52 | 53 | def forward(self, x, outputs): 54 | return torch.cat([outputs[i] for i in self.layers], 1) if self.multiple else outputs[self.layers[0]] 55 | 56 | 57 | class WeightedFeatureFusion(nn.Module): # weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070 58 | def __init__(self, layers, weight=False): 59 | super(WeightedFeatureFusion, self).__init__() 60 | self.layers = layers # layer indices 61 | self.weight = weight # apply weights boolean 62 | self.n = len(layers) + 1 # number of layers 63 | if weight: 64 | self.w = nn.Parameter(torch.zeros(self.n), requires_grad=True) # layer weights 65 | 66 | def forward(self, x, outputs): 67 | # Weights 68 | if self.weight: 69 | w = torch.sigmoid(self.w) * (2 / self.n) # sigmoid weights (0-1) 70 | x = x * w[0] 71 | 72 | # Fusion 73 | nx = x.shape[1] # input channels 74 | for i in range(self.n - 1): 75 | a = outputs[self.layers[i]] * w[i + 1] if self.weight else outputs[self.layers[i]] # feature to add 76 | na = a.shape[1] # feature channels 77 | 78 | # Adjust channels 79 | if nx == na: # same shape 80 | x = x + a 81 | elif nx > na: # slice input 82 | x[:, :na] = x[:, :na] + a # or a = nn.ZeroPad2d((0, 0, 0, 0, 0, dc))(a); x = x + a 83 | else: # slice feature 84 | x = x + a[:, :nx] 85 | 86 | return x 87 | 88 | 89 | class MixConv2d(nn.Module): # MixConv: Mixed Depthwise Convolutional Kernels https://arxiv.org/abs/1907.09595 90 | def __init__(self, in_ch, out_ch, k=(3, 5, 7), stride=1, dilation=1, bias=True, method='equal_params'): 91 | super(MixConv2d, self).__init__() 92 | 93 | groups = len(k) 94 | if method == 'equal_ch': # equal channels per group 95 | i = torch.linspace(0, groups - 1E-6, out_ch).floor() # out_ch indices 96 | ch = [(i == g).sum() for g in range(groups)] 97 | else: # 'equal_params': equal parameter count per group 98 | b = [out_ch] + [0] * groups 99 | a = np.eye(groups + 1, groups, k=-1) 100 | a -= np.roll(a, 1, axis=1) 101 | a *= np.array(k) ** 2 102 | a[0] = 1 103 | ch = np.linalg.lstsq(a, b, rcond=None)[0].round().astype(int) # solve for equal weight indices, ax = b 104 | 105 | self.m = nn.ModuleList([nn.Conv2d(in_channels=in_ch, 106 | out_channels=ch[g], 107 | kernel_size=k[g], 108 | stride=stride, 109 | padding=k[g] // 2, # 'same' pad 110 | dilation=dilation, 111 | bias=bias) for g in range(groups)]) 112 | 113 | def forward(self, x): 114 | return torch.cat([m(x) for m in self.m], 1) 115 | 116 | 117 | # Activation functions below ------------------------------------------------------------------------------------------- 118 | class SwishImplementation(torch.autograd.Function): 119 | @staticmethod 120 | def forward(ctx, x): 121 | ctx.save_for_backward(x) 122 | return x * torch.sigmoid(x) 123 | 124 | @staticmethod 125 | def backward(ctx, grad_output): 126 | x = ctx.saved_tensors[0] 127 | sx = torch.sigmoid(x) # sigmoid(ctx) 128 | return grad_output * (sx * (1 + x * (1 - sx))) 129 | 130 | 131 | class MishImplementation(torch.autograd.Function): 132 | @staticmethod 133 | def forward(ctx, x): 134 | ctx.save_for_backward(x) 135 | return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x))) 136 | 137 | @staticmethod 138 | def backward(ctx, grad_output): 139 | x = ctx.saved_tensors[0] 140 | sx = torch.sigmoid(x) 141 | fx = F.softplus(x).tanh() 142 | return grad_output * (fx + x * sx * (1 - fx * fx)) 143 | 144 | 145 | class MemoryEfficientSwish(nn.Module): 146 | def forward(self, x): 147 | return SwishImplementation.apply(x) 148 | 149 | 150 | class MemoryEfficientMish(nn.Module): 151 | def forward(self, x): 152 | return MishImplementation.apply(x) 153 | 154 | 155 | class Swish(nn.Module): 156 | def forward(self, x): 157 | return x * torch.sigmoid(x) 158 | 159 | 160 | class HardSwish(nn.Module): # https://arxiv.org/pdf/1905.02244.pdf 161 | def forward(self, x): 162 | return x * F.hardtanh(x + 3, 0., 6., True) / 6. 163 | 164 | 165 | class Mish(nn.Module): # https://github.com/digantamisra98/Mish 166 | def forward(self, x): 167 | return x * F.softplus(x).tanh() 168 | -------------------------------------------------------------------------------- /utils/parse_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import numpy as np 4 | 5 | 6 | def parse_model_cfg(path): 7 | # Parse the yolo *.cfg file and return module definitions path may be 'cfg/yolov3.cfg', 'yolov3.cfg', or 'yolov3' 8 | if not path.endswith('.cfg'): # add .cfg suffix if omitted 9 | path += '.cfg' 10 | if not os.path.exists(path) and os.path.exists('cfg' + os.sep + path): # add cfg/ prefix if omitted 11 | path = 'cfg' + os.sep + path 12 | 13 | with open(path, 'r') as f: 14 | lines = f.read().split('\n') 15 | lines = [x for x in lines if x and not x.startswith('#')] 16 | lines = [x.rstrip().lstrip() for x in lines] # get rid of fringe whitespaces 17 | mdefs = [] # module definitions 18 | for line in lines: 19 | if line.startswith('['): # This marks the start of a new block 20 | mdefs.append({}) 21 | mdefs[-1]['type'] = line[1:-1].rstrip() 22 | if mdefs[-1]['type'] == 'convolutional': 23 | mdefs[-1]['batch_normalize'] = 0 # pre-populate with zeros (may be overwritten later) 24 | else: 25 | key, val = line.split("=") 26 | key = key.rstrip() 27 | 28 | if key == 'anchors': # return nparray 29 | mdefs[-1][key] = np.array([float(x) for x in val.split(',')]).reshape((-1, 2)) # np anchors 30 | elif (key in ['from', 'layers', 'mask']) or (key == 'size' and ',' in val): # return array 31 | mdefs[-1][key] = [int(x) for x in val.split(',')] 32 | else: 33 | val = val.strip() 34 | # TODO: .isnumeric() actually fails to get the float case 35 | if val.isnumeric(): # return int or float 36 | mdefs[-1][key] = int(val) if (int(val) - float(val)) == 0 else float(val) 37 | else: 38 | mdefs[-1][key] = val # return string 39 | 40 | # Check all fields are supported 41 | supported = ['type', 'batch_normalize', 'filters', 'size', 'stride', 'pad', 'activation', 'layers', 'groups', 'group_id', 'resize', 42 | 'from', 'mask', 'anchors', 'classes', 'num', 'jitter', 'ignore_thresh', 'truth_thresh', 'random', 43 | 'stride_x', 'stride_y', 'weights_type', 'weights_normalization', 'scale_x_y', 'beta_nms', 'nms_kind', 44 | 'iou_loss', 'iou_normalizer', 'cls_normalizer', 'iou_thresh', 'probability'] 45 | 46 | f = [] # fields 47 | for x in mdefs[1:]: 48 | [f.append(k) for k in x if k not in f] 49 | u = [x for x in f if x not in supported] # unsupported fields 50 | assert not any(u), "Unsupported fields %s in %s. See https://github.com/ultralytics/yolov3/issues/631" % (u, path) 51 | 52 | return mdefs 53 | 54 | 55 | def parse_data_cfg(path): 56 | # Parses the data configuration file 57 | if not os.path.exists(path) and os.path.exists('data' + os.sep + path): # add data/ prefix if omitted 58 | path = 'data' + os.sep + path 59 | 60 | with open(path, 'r') as f: 61 | lines = f.readlines() 62 | 63 | options = dict() 64 | for line in lines: 65 | line = line.strip() 66 | if line == '' or line.startswith('#'): 67 | continue 68 | key, val = line.split('=') 69 | options[key.strip()] = val.strip() 70 | 71 | return options 72 | -------------------------------------------------------------------------------- /utils/profile_local.py: -------------------------------------------------------------------------------- 1 | from distutils.version import LooseVersion 2 | 3 | from thop.vision.basic_hooks import * 4 | from thop.rnn_hooks import * 5 | import numpy as np 6 | 7 | # logger = logging.getLogger(__name__) 8 | # logger.setLevel(logging.INFO) 9 | def prRed(skk): print("\033[91m{}\033[00m".format(skk)) 10 | 11 | 12 | def prGreen(skk): print("\033[92m{}\033[00m".format(skk)) 13 | 14 | 15 | def prYellow(skk): print("\033[93m{}\033[00m".format(skk)) 16 | 17 | 18 | if LooseVersion(torch.__version__) < LooseVersion("1.0.0"): 19 | logging.warning( 20 | "You are using an old version PyTorch {version}, which THOP is not going to support in the future.".format( 21 | version=torch.__version__)) 22 | 23 | default_dtype = torch.float64 24 | 25 | register_hooks = { 26 | nn.ZeroPad2d: zero_ops, # padding does not involve any multiplication. 27 | 28 | nn.Conv1d: count_convNd, 29 | nn.Conv2d: count_convNd, 30 | nn.Conv3d: count_convNd, 31 | nn.ConvTranspose1d: count_convNd, 32 | nn.ConvTranspose2d: count_convNd, 33 | nn.ConvTranspose3d: count_convNd, 34 | 35 | nn.BatchNorm1d: count_bn, 36 | nn.BatchNorm2d: count_bn, 37 | nn.BatchNorm3d: count_bn, 38 | nn.SyncBatchNorm: count_bn, 39 | 40 | nn.ReLU: zero_ops, 41 | nn.ReLU6: zero_ops, 42 | nn.LeakyReLU: count_relu, 43 | 44 | nn.MaxPool1d: zero_ops, 45 | nn.MaxPool2d: zero_ops, 46 | nn.MaxPool3d: zero_ops, 47 | nn.AdaptiveMaxPool1d: zero_ops, 48 | nn.AdaptiveMaxPool2d: zero_ops, 49 | nn.AdaptiveMaxPool3d: zero_ops, 50 | 51 | nn.AvgPool1d: count_avgpool, 52 | nn.AvgPool2d: count_avgpool, 53 | nn.AvgPool3d: count_avgpool, 54 | nn.AdaptiveAvgPool1d: count_adap_avgpool, 55 | nn.AdaptiveAvgPool2d: count_adap_avgpool, 56 | nn.AdaptiveAvgPool3d: count_adap_avgpool, 57 | 58 | nn.Linear: count_linear, 59 | nn.Dropout: zero_ops, 60 | 61 | nn.Upsample: count_upsample, 62 | nn.UpsamplingBilinear2d: count_upsample, 63 | nn.UpsamplingNearest2d: count_upsample, 64 | 65 | nn.RNNCell: count_rnn_cell, 66 | nn.GRUCell: count_gru_cell, 67 | nn.LSTMCell: count_lstm_cell, 68 | nn.RNN: count_rnn, 69 | nn.GRU: count_gru, 70 | nn.LSTM: count_lstm, 71 | } 72 | 73 | 74 | def profile_origin(model, inputs, custom_ops=None, verbose=True): 75 | handler_collection = [] 76 | types_collection = set() 77 | if custom_ops is None: 78 | custom_ops = {} 79 | 80 | def add_hooks(m): 81 | if len(list(m.children())) > 0: 82 | return 83 | 84 | if hasattr(m, "total_ops") or hasattr(m, "total_params"): 85 | logging.warning("Either .total_ops or .total_params is already defined in %s. " 86 | "Be careful, it might change your code's behavior." % str(m)) 87 | 88 | m.register_buffer('total_ops', torch.zeros(1, dtype=default_dtype)) 89 | m.register_buffer('total_params', torch.zeros(1, dtype=default_dtype)) 90 | 91 | for p in m.parameters(): 92 | m.total_params += torch.DoubleTensor([p.numel()]) 93 | 94 | m_type = type(m) 95 | 96 | fn = None 97 | if m_type in custom_ops: # if defined both op maps, use custom_ops to overwrite. 98 | fn = custom_ops[m_type] 99 | if m_type not in types_collection and verbose: 100 | print("[INFO] Customize rule %s() %s." % (fn.__qualname__, m_type)) 101 | elif m_type in register_hooks: 102 | fn = register_hooks[m_type] 103 | if m_type not in types_collection and verbose: 104 | print("[INFO] Register %s() for %s." % (fn.__qualname__, m_type)) 105 | else: 106 | if m_type not in types_collection and verbose: 107 | prRed("[WARN] Cannot find rule for %s. Treat it as zero Macs and zero Params." % m_type) 108 | 109 | if fn is not None: 110 | handler = m.register_forward_hook(fn) 111 | handler_collection.append(handler) 112 | types_collection.add(m_type) 113 | 114 | training = model.training 115 | 116 | model.eval() 117 | model.apply(add_hooks) 118 | 119 | with torch.no_grad(): 120 | model(*inputs) 121 | 122 | total_ops = 0 123 | total_params = 0 124 | for m in model.modules(): 125 | if len(list(m.children())) > 0: # skip for non-leaf module 126 | continue 127 | total_ops += m.total_ops 128 | total_params += m.total_params 129 | 130 | total_ops = total_ops.item() 131 | total_params = total_params.item() 132 | 133 | # reset model to original status 134 | model.train(training) 135 | for handler in handler_collection: 136 | handler.remove() 137 | 138 | # remove temporal buffers 139 | for n, m in model.named_modules(): 140 | if len(list(m.children())) > 0: 141 | continue 142 | if "total_ops" in m._buffers: 143 | m._buffers.pop("total_ops") 144 | if "total_params" in m._buffers: 145 | m._buffers.pop("total_params") 146 | 147 | return total_ops, total_params 148 | 149 | 150 | def profile(model: nn.Module, inputs, custom_ops=None, verbose=True): 151 | handler_collection = {} 152 | types_collection = set() 153 | if custom_ops is None: 154 | custom_ops = {} 155 | 156 | def add_hooks(m: nn.Module): 157 | m.register_buffer('total_ops', torch.zeros(1, dtype=torch.float64)) 158 | m.register_buffer('total_params', torch.zeros(1, dtype=torch.float64)) 159 | 160 | # for p in m.parameters(): 161 | # m.total_params += torch.DoubleTensor([p.numel()]) 162 | 163 | m_type = type(m) 164 | 165 | fn = None 166 | if m_type in custom_ops: # if defined both op maps, use custom_ops to overwrite. 167 | fn = custom_ops[m_type] 168 | if m_type not in types_collection and verbose: 169 | print("[INFO] Customize rule %s() %s." % (fn.__qualname__, m_type)) 170 | elif m_type in register_hooks: 171 | fn = register_hooks[m_type] 172 | if m_type not in types_collection and verbose: 173 | print("[INFO] Register %s() for %s." % (fn.__qualname__, m_type)) 174 | else: 175 | if m_type not in types_collection and verbose: 176 | prRed("[WARN] Cannot find rule for %s. Treat it as zero Macs and zero Params." % m_type) 177 | 178 | if fn is not None: 179 | handler_collection[m] = (m.register_forward_hook(fn), m.register_forward_hook(count_parameters)) 180 | types_collection.add(m_type) 181 | 182 | prev_training_status = model.training 183 | 184 | model.eval() 185 | model.apply(add_hooks) 186 | 187 | with torch.no_grad(): 188 | model(*inputs) 189 | 190 | def dfs_count(module: nn.Module, prefix="\t") -> (int, int): 191 | total_ops, total_params = 0, 0 192 | for m in module.children(): 193 | # if not hasattr(m, "total_ops") and not hasattr(m, "total_params"): # and len(list(m.children())) > 0: 194 | # m_ops, m_params = dfs_count(m, prefix=prefix + "\t") 195 | # else: 196 | # m_ops, m_params = m.total_ops, m.total_params 197 | if m in handler_collection and not isinstance(m, (nn.Sequential, nn.ModuleList)): #, nn.BatchNorm2d, nn.LeakyReLU, nn.MaxPool2d, nn.Upsample 198 | m_ops, m_params = m.total_ops.item(), m.total_params.item() 199 | if (m.total_params==0): 200 | continue 201 | weight = m.weight.data 202 | if (len(weight.size()) == 4): # and "shortcut" not in name): # only consider conv layers 203 | zeros = np.sum(weight.cpu().detach().numpy() == 0) 204 | # total_zeros += zeros 205 | non_zeros = np.sum(weight.cpu().detach().numpy() != 0) 206 | # total_nonzeros += non_zeros 207 | nonsparcity = non_zeros / (zeros + non_zeros) 208 | m_ops = m_ops*nonsparcity 209 | m_params = m_params*nonsparcity 210 | else: 211 | m_ops, m_params = dfs_count(m, prefix=prefix + "\t") 212 | total_ops += m_ops 213 | total_params += m_params 214 | # print(prefix, module._get_name(), (total_ops, total_params)) 215 | return total_ops, total_params 216 | 217 | total_ops, total_params = dfs_count(model) 218 | 219 | # reset model to original status 220 | model.train(prev_training_status) 221 | for m, (op_handler, params_handler) in handler_collection.items(): 222 | op_handler.remove() 223 | params_handler.remove() 224 | m._buffers.pop("total_ops") 225 | m._buffers.pop("total_params") 226 | 227 | return total_ops, total_params -------------------------------------------------------------------------------- /utils/torch_utils.py: -------------------------------------------------------------------------------- 1 | import math 2 | import os 3 | import time 4 | from copy import deepcopy 5 | 6 | import torch 7 | import torch.backends.cudnn as cudnn 8 | import torch.nn as nn 9 | import torch.nn.functional as F 10 | 11 | from utils import profile_local 12 | 13 | 14 | def init_seeds(seed=0): 15 | torch.manual_seed(seed) 16 | 17 | # Reduce randomness (may be slower on Tesla GPUs) # https://pytorch.org/docs/stable/notes/randomness.html 18 | if seed == 0: 19 | cudnn.deterministic = False 20 | cudnn.benchmark = True 21 | 22 | 23 | def select_device(device='', apex=False, batch_size=None): 24 | # device = 'cpu' or '0' or '0,1,2,3' 25 | cpu_request = device.lower() == 'cpu' 26 | if device and not cpu_request: # if device requested other than 'cpu' 27 | os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable 28 | assert torch.cuda.is_available(), 'CUDA unavailable, invalid device %s requested' % device # check availablity 29 | 30 | cuda = False if cpu_request else torch.cuda.is_available() 31 | if cuda: 32 | c = 1024 ** 2 # bytes to MB 33 | ng = torch.cuda.device_count() 34 | if ng > 1 and batch_size: # check that batch_size is compatible with device_count 35 | assert batch_size % ng == 0, 'batch-size %g not multiple of GPU count %g' % (batch_size, ng) 36 | x = [torch.cuda.get_device_properties(i) for i in range(ng)] 37 | s = 'Using CUDA ' + ('Apex ' if apex else '') # apex for mixed precision https://github.com/NVIDIA/apex 38 | for i in range(0, ng): 39 | if i == 1: 40 | s = ' ' * len(s) 41 | print("%sdevice%g _CudaDeviceProperties(name='%s', total_memory=%dMB)" % 42 | (s, i, x[i].name, x[i].total_memory / c)) 43 | else: 44 | print('Using CPU') 45 | 46 | print('') # skip a line 47 | return torch.device('cuda:0' if cuda else 'cpu') 48 | 49 | 50 | def time_synchronized(): 51 | torch.cuda.synchronize() if torch.cuda.is_available() else None 52 | return time.time() 53 | 54 | 55 | def initialize_weights(model): 56 | for m in model.modules(): 57 | t = type(m) 58 | if t is nn.Conv2d: 59 | pass # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') 60 | elif t is nn.BatchNorm2d: 61 | m.eps = 1e-4 62 | m.momentum = 0.03 63 | elif t in [nn.LeakyReLU, nn.ReLU, nn.ReLU6]: 64 | m.inplace = True 65 | 66 | 67 | def find_modules(model, mclass=nn.Conv2d): 68 | # finds layer indices matching module class 'mclass' 69 | return [i for i, m in enumerate(model.module_list) if isinstance(m, mclass)] 70 | 71 | 72 | def fuse_conv_and_bn(conv, bn): 73 | # https://tehnokv.com/posts/fusing-batchnorm-and-conv/ 74 | with torch.no_grad(): 75 | # init 76 | fusedconv = torch.nn.Conv2d(conv.in_channels, 77 | conv.out_channels, 78 | kernel_size=conv.kernel_size, 79 | stride=conv.stride, 80 | padding=conv.padding, 81 | bias=True) 82 | 83 | # prepare filters 84 | w_conv = conv.weight.clone().view(conv.out_channels, -1) 85 | w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var))) 86 | fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.size())) 87 | 88 | # prepare spatial bias 89 | if conv.bias is not None: 90 | b_conv = conv.bias 91 | else: 92 | b_conv = torch.zeros(conv.weight.size(0)) 93 | b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps)) 94 | fusedconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn) 95 | 96 | return fusedconv 97 | 98 | 99 | def model_info(model, verbose=False): 100 | # Plots a line-by-line description of a PyTorch model 101 | n_p = sum(x.numel() for x in model.parameters()) # number parameters 102 | n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients 103 | if verbose: 104 | print('%5s %40s %9s %12s %20s %10s %10s' % ('layer', 'name', 'gradient', 'parameters', 'shape', 'mu', 'sigma')) 105 | for i, (name, p) in enumerate(model.named_parameters()): 106 | name = name.replace('module_list.', '') 107 | print('%5g %40s %9s %12g %20s %10.3g %10.3g' % 108 | (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) 109 | 110 | try: # FLOPS 111 | from thop import profile 112 | macs, _ = profile(model, inputs=(torch.zeros(1, 3, 320, 320),), verbose=False) 113 | fs = ', %.1f GFLOPS' % (macs / 1E9 * 2) 114 | except: 115 | fs = '' 116 | 117 | print('Model Summary: %g layers, %g parameters, %g gradients%s' % (len(list(model.parameters())), n_p, n_g, fs)) 118 | return n_p, macs 119 | 120 | def prunned_model_info(model, verbose=False): 121 | # Plots a line-by-line description of a PyTorch model 122 | n_p = sum(x.numel() for x in model.parameters()) # number parameters 123 | n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients 124 | if verbose: 125 | print('%5s %40s %9s %12s %20s %10s %10s' % ('layer', 'name', 'gradient', 'parameters', 'shape', 'mu', 'sigma')) 126 | for i, (name, p) in enumerate(model.named_parameters()): 127 | name = name.replace('module_list.', '') 128 | print('%5g %40s %9s %12g %20s %10.3g %10.3g' % 129 | (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) 130 | 131 | try: # FLOPS 132 | # from thop import profile 133 | macs, n_p = profile_local.profile(model, inputs=(torch.zeros(1, 3, 320, 320),), verbose=False) 134 | fs = ', %.1f GFLOPS' % (macs / 1E9 * 2) 135 | except: 136 | fs = '' 137 | 138 | print('Model Summary: %g layers, %g parameters %s' % (len(list(model.parameters())), n_p, fs)) 139 | return n_p, macs 140 | 141 | def load_classifier(name='resnet101', n=2): 142 | # Loads a pretrained model reshaped to n-class output 143 | import pretrainedmodels # https://github.com/Cadene/pretrained-models.pytorch#torchvision 144 | model = pretrainedmodels.__dict__[name](num_classes=1000, pretrained='imagenet') 145 | 146 | # Display model properties 147 | for x in ['model.input_size', 'model.input_space', 'model.input_range', 'model.mean', 'model.std']: 148 | print(x + ' =', eval(x)) 149 | 150 | # Reshape output to n classes 151 | filters = model.last_linear.weight.shape[1] 152 | model.last_linear.bias = torch.nn.Parameter(torch.zeros(n)) 153 | model.last_linear.weight = torch.nn.Parameter(torch.zeros(n, filters)) 154 | model.last_linear.out_features = n 155 | return model 156 | 157 | 158 | def scale_img(img, ratio=1.0, same_shape=True): # img(16,3,256,416), r=ratio 159 | # scales img(bs,3,y,x) by ratio 160 | h, w = img.shape[2:] 161 | s = (int(h * ratio), int(w * ratio)) # new size 162 | img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize 163 | if not same_shape: # pad/crop img 164 | gs = 64 # (pixels) grid size 165 | h, w = [math.ceil(x * ratio / gs) * gs for x in (h, w)] 166 | return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean 167 | 168 | 169 | class ModelEMA: 170 | """ Model Exponential Moving Average from https://github.com/rwightman/pytorch-image-models 171 | Keep a moving average of everything in the model state_dict (parameters and buffers). 172 | This is intended to allow functionality like 173 | https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage 174 | A smoothed version of the weights is necessary for some training schemes to perform well. 175 | E.g. Google's hyper-params for training MNASNet, MobileNet-V3, EfficientNet, etc that use 176 | RMSprop with a short 2.4-3 epoch decay period and slow LR decay rate of .96-.99 requires EMA 177 | smoothing of weights to match results. Pay attention to the decay constant you are using 178 | relative to your update count per epoch. 179 | To keep EMA from using GPU resources, set device='cpu'. This will save a bit of memory but 180 | disable validation of the EMA weights. Validation will have to be done manually in a separate 181 | process, or after the training stops converging. 182 | This class is sensitive where it is initialized in the sequence of model init, 183 | GPU assignment and distributed training wrappers. 184 | I've tested with the sequence in my own train.py for torch.DataParallel, apex.DDP, and single-GPU. 185 | """ 186 | 187 | def __init__(self, model, decay=0.9999, device=''): 188 | # make a copy of the model for accumulating moving average of weights 189 | self.ema = deepcopy(model) 190 | self.ema.eval() 191 | self.updates = 0 # number of EMA updates 192 | self.decay = lambda x: decay * (1 - math.exp(-x / 2000)) # decay exponential ramp (to help early epochs) 193 | self.device = device # perform ema on different device from model if set 194 | if device: 195 | self.ema.to(device=device) 196 | for p in self.ema.parameters(): 197 | p.requires_grad_(False) 198 | 199 | def update(self, model): 200 | self.updates += 1 201 | d = self.decay(self.updates) 202 | with torch.no_grad(): 203 | if type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel): 204 | msd, esd = model.module.state_dict(), self.ema.module.state_dict() 205 | else: 206 | msd, esd = model.state_dict(), self.ema.state_dict() 207 | 208 | for k, v in esd.items(): 209 | if v.dtype.is_floating_point: 210 | v *= d 211 | v += (1. - d) * msd[k].detach() 212 | 213 | def update_attr(self, model): 214 | # Assign attributes (which may change during training) 215 | for k in model.__dict__.keys(): 216 | if not k.startswith('_'): 217 | setattr(self.ema, k, getattr(model, k)) 218 | -------------------------------------------------------------------------------- /weights/download_yolov3_weights.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # make '/weights' directory if it does not exist and cd into it 4 | # mkdir -p weights && cd weights 5 | 6 | # copy darknet weight files, continue '-c' if partially downloaded 7 | # wget -c https://pjreddie.com/media/files/yolov3.weights 8 | # wget -c https://pjreddie.com/media/files/yolov3-tiny.weights 9 | # wget -c https://pjreddie.com/media/files/yolov3-spp.weights 10 | 11 | # yolov3 pytorch weights 12 | # download from Google Drive: https://drive.google.com/drive/folders/1uxgUBemJVw9wZsdpboYbzUN4bcRhsuAI 13 | 14 | # darknet53 weights (first 75 layers only) 15 | # wget -c https://pjreddie.com/media/files/darknet53.conv.74 16 | 17 | # yolov3-tiny weights from darknet (first 16 layers only) 18 | # ./darknet partial cfg/yolov3-tiny.cfg yolov3-tiny.weights yolov3-tiny.conv.15 15 19 | # mv yolov3-tiny.conv.15 ../ 20 | 21 | # new method 22 | python3 -c "from models import *; 23 | attempt_download('weights/yolov3.pt'); 24 | attempt_download('weights/yolov3-spp.pt')" 25 | --------------------------------------------------------------------------------