Repository: megvii-research/mdistiller Branch: master Commit: a08d46f10d61 Files: 117 Total size: 626.8 KB Directory structure: gitextract_b7kwa80j/ ├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── configs/ │ ├── cifar100/ │ │ ├── at.yaml │ │ ├── crd.yaml │ │ ├── dkd/ │ │ │ ├── res110_res32.yaml │ │ │ ├── res32x4_res8x4.yaml │ │ │ ├── res32x4_shuv1.yaml │ │ │ ├── res32x4_shuv2.yaml │ │ │ ├── res50_mv2.yaml │ │ │ ├── res56_res20.yaml │ │ │ ├── vgg13_mv2.yaml │ │ │ ├── vgg13_vgg8.yaml │ │ │ ├── wrn40_2_shuv1.yaml │ │ │ ├── wrn40_2_wrn_16_2.yaml │ │ │ └── wrn40_2_wrn_40_1.yaml │ │ ├── dot/ │ │ │ ├── res32x4_res8x4.yaml │ │ │ ├── res32x4_shuv2.yaml │ │ │ └── vgg13_vgg8.yaml │ │ ├── fitnet.yaml │ │ ├── kd.yaml │ │ ├── kdsvd.yaml │ │ ├── nst.yaml │ │ ├── ofd.yaml │ │ ├── pkt.yaml │ │ ├── reviewkd.yaml │ │ ├── rkd.yaml │ │ ├── sp.yaml │ │ ├── vanilla.yaml │ │ └── vid.yaml │ ├── imagenet/ │ │ ├── r34_r18/ │ │ │ ├── at.yaml │ │ │ ├── crd.yaml │ │ │ ├── dkd.yaml │ │ │ ├── dot.yaml │ │ │ ├── kd.yaml │ │ │ └── reviewkd.yaml │ │ └── r50_mv1/ │ │ ├── at.yaml │ │ ├── crd.yaml │ │ ├── dkd.yaml │ │ ├── dot.yaml │ │ ├── kd.yaml │ │ ├── ofd.yaml │ │ └── reviewkd.yaml │ └── tiny_imagenet/ │ └── dot/ │ ├── r18_mv2.yaml │ └── r18_shuv2.yaml ├── detection/ │ ├── README.md │ ├── __init__.py │ ├── configs/ │ │ ├── Base-Distillation.yaml │ │ ├── DKD/ │ │ │ ├── DKD-MV2-R50.yaml │ │ │ ├── DKD-R18-R101.yaml │ │ │ ├── DKD-R50-R101.yaml │ │ │ ├── ReviewDKD-MV2-R50.yaml │ │ │ ├── ReviewDKD-R18-R101.yaml │ │ │ └── ReviewDKD-R50-R101.yaml │ │ └── ReviewKD/ │ │ ├── ReviewKD-MV2-R50-Mask.yaml │ │ ├── ReviewKD-MV2-R50.yaml │ │ ├── ReviewKD-R18-R101-Mask.yaml │ │ ├── ReviewKD-R18-R101.yaml │ │ ├── ReviewKD-R50-R101-Mask.yaml │ │ └── ReviewKD-R50-R101.yaml │ ├── model/ │ │ ├── __init__.py │ │ ├── backbone/ │ │ │ ├── __init__.py │ │ │ ├── fpn.py │ │ │ ├── mobilenetv2.py │ │ │ └── resnet.py │ │ ├── config.py │ │ ├── rcnn.py │ │ ├── reviewkd.py │ │ └── teacher/ │ │ ├── __init__.py │ │ └── teacher.py │ └── train_net.py ├── mdistiller/ │ ├── __init__.py │ ├── dataset/ │ │ ├── __init__.py │ │ ├── cifar100.py │ │ ├── imagenet.py │ │ └── tiny_imagenet.py │ ├── distillers/ │ │ ├── AT.py │ │ ├── CRD.py │ │ ├── DKD.py │ │ ├── FitNet.py │ │ ├── KD.py │ │ ├── KDSVD.py │ │ ├── NST.py │ │ ├── OFD.py │ │ ├── PKT.py │ │ ├── RKD.py │ │ ├── ReviewKD.py │ │ ├── SP.py │ │ ├── VID.py │ │ ├── __init__.py │ │ ├── _base.py │ │ └── _common.py │ ├── engine/ │ │ ├── __init__.py │ │ ├── cfg.py │ │ ├── dot.py │ │ ├── trainer.py │ │ └── utils.py │ └── models/ │ ├── __init__.py │ ├── cifar/ │ │ ├── ShuffleNetv1.py │ │ ├── ShuffleNetv2.py │ │ ├── __init__.py │ │ ├── mobilenetv2.py │ │ ├── mv2_tinyimagenet.py │ │ ├── resnet.py │ │ ├── resnetv2.py │ │ ├── vgg.py │ │ └── wrn.py │ └── imagenet/ │ ├── __init__.py │ ├── mobilenetv1.py │ └── resnet.py ├── requirements.txt ├── setup.py └── tools/ ├── eval.py ├── train.py └── visualizations/ ├── correlation.ipynb └── tsne.ipynb ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ * linguist-language=Python ================================================ FILE: .gitignore ================================================ .idea/ data data/ output output*/ detection/datasets detection/output detection/output*/ ckpts/ *.pth *.t7 tmp*.py *.pdf # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # pyenv .python-version # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ # wandb wandb/ # download ckpts download_ckpts/ ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2022 MEGVII Research Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. detectron2 Copyright 2020 - present, Facebook, Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. RepDistiller Copyright (c) 2020, Yonglong Tian ================================================ FILE: README.md ================================================
This repo is (1) a PyTorch library that provides classical knowledge distillation algorithms on mainstream CV benchmarks, (2) the official implementation of the CVPR-2022 paper: [Decoupled Knowledge Distillation](https://arxiv.org/abs/2203.08679). (3) the official implementation of the ICCV-2023 paper: [DOT: A Distillation-Oriented Trainer](https://openaccess.thecvf.com/content/ICCV2023/papers/Zhao_DOT_A_Distillation-Oriented_Trainer_ICCV_2023_paper.pdf). # DOT: A Distillation-Oriented Trainer ### Framework
### Main Benchmark Results On CIFAR-100: | Teacher
Student | ResNet32x4
ResNet8x4| VGG13
VGG8| ResNet32x4
ShuffleNet-V2| |:---------------:|:-----------------:|:-----------------:|:-----------------:| | KD | 73.33 | 72.98 | 74.45 | | **KD+DOT** | **75.12** | **73.77** | **75.55** | On Tiny-ImageNet: | Teacher
Student |ResNet18
MobileNet-V2|ResNet18
ShuffleNet-V2| |:---------------:|:-----------------:|:-----------------:| | KD | 58.35 | 62.26 | | **KD+DOT** | **64.01** | **65.75** | On ImageNet: | Teacher
Student |ResNet34
ResNet18|ResNet50
MobileNet-V1| |:---------------:|:-----------------:|:-----------------:| | KD | 71.03 | 70.50 | | **KD+DOT** | **71.72** | **73.09** | # Decoupled Knowledge Distillation ### Framework & Performance
### Main Benchmark Results On CIFAR-100: | Teacher
Student |ResNet56
ResNet20|ResNet110
ResNet32| ResNet32x4
ResNet8x4| WRN-40-2
WRN-16-2| WRN-40-2
WRN-40-1 | VGG13
VGG8| |:---------------:|:-----------------:|:-----------------:|:-----------------:|:------------------:|:------------------:|:--------------------:| | KD | 70.66 | 73.08 | 73.33 | 74.92 | 73.54 | 72.98 | | **DKD** | **71.97** | **74.11** | **76.32** | **76.23** | **74.81** | **74.68** | | Teacher
Student |ResNet32x4
ShuffleNet-V1|WRN-40-2
ShuffleNet-V1| VGG13
MobileNet-V2| ResNet50
MobileNet-V2| ResNet32x4
MobileNet-V2| |:---------------:|:-----------------:|:-----------------:|:-----------------:|:------------------:|:------------------:| | KD | 74.07 | 74.83 | 67.37 | 67.35 | 74.45 | | **DKD** | **76.45** | **76.70** | **69.71** | **70.35** | **77.07** | On ImageNet: | Teacher
Student |ResNet34
ResNet18|ResNet50
MobileNet-V1| |:---------------:|:-----------------:|:-----------------:| | KD | 71.03 | 70.50 | | **DKD** | **71.70** | **72.05** | # MDistiller ### Introduction MDistiller supports the following distillation methods on CIFAR-100, ImageNet and MS-COCO: |Method|Paper Link|CIFAR-100|ImageNet|MS-COCO| |:---:|:---:|:---:|:---:|:---:| |KD| |✓|✓| | |FitNet| |✓| | | |AT| |✓|✓| | |NST| |✓| | | |PKT| |✓| | | |KDSVD| |✓| | | |OFD| |✓|✓| | |RKD| |✓| | | |VID| |✓| | | |SP| |✓| | | |CRD| |✓|✓| | |ReviewKD| |✓|✓|✓| |DKD| |✓|✓|✓| ### Installation Environments: - Python 3.6 - PyTorch 1.9.0 - torchvision 0.10.0 Install the package: ``` sudo pip3 install -r requirements.txt sudo python3 setup.py develop ``` ### Getting started 0. Wandb as the logger - The registeration: . - If you don't want wandb as your logger, set `CFG.LOG.WANDB` as `False` at `mdistiller/engine/cfg.py`. 1. Evaluation - You can evaluate the performance of our models or models trained by yourself. - Our models are at , please download the checkpoints to `./download_ckpts` - If test the models on ImageNet, please download the dataset at and put them to `./data/imagenet` ```bash # evaluate teachers python3 tools/eval.py -m resnet32x4 # resnet32x4 on cifar100 python3 tools/eval.py -m ResNet34 -d imagenet # ResNet34 on imagenet # evaluate students python3 tools/eval.p -m resnet8x4 -c download_ckpts/dkd_resnet8x4 # dkd-resnet8x4 on cifar100 python3 tools/eval.p -m MobileNetV1 -c download_ckpts/imgnet_dkd_mv1 -d imagenet # dkd-mv1 on imagenet python3 tools/eval.p -m model_name -c output/your_exp/student_best # your checkpoints ``` 2. Training on CIFAR-100 - Download the `cifar_teachers.tar` at and untar it to `./download_ckpts` via `tar xvf cifar_teachers.tar`. ```bash # for instance, our DKD method. python3 tools/train.py --cfg configs/cifar100/dkd/res32x4_res8x4.yaml # you can also change settings at command line python3 tools/train.py --cfg configs/cifar100/dkd/res32x4_res8x4.yaml SOLVER.BATCH_SIZE 128 SOLVER.LR 0.1 ``` 3. Training on ImageNet - Download the dataset at and put them to `./data/imagenet` ```bash # for instance, our DKD method. python3 tools/train.py --cfg configs/imagenet/r34_r18/dkd.yaml ``` 4. Training on MS-COCO - see [detection.md](detection/README.md) 5. Extension: Visualizations - Jupyter notebooks: [tsne](tools/visualizations/tsne.ipynb) and [correlation_matrices](tools/visualizations/correlation.ipynb) ### Custom Distillation Method 1. create a python file at `mdistiller/distillers/` and define the distiller ```python from ._base import Distiller class MyDistiller(Distiller): def __init__(self, student, teacher, cfg): super(MyDistiller, self).__init__(student, teacher) self.hyper1 = cfg.MyDistiller.hyper1 ... def forward_train(self, image, target, **kwargs): # return the output logits and a Dict of losses ... # rewrite the get_learnable_parameters function if there are more nn modules for distillation. # rewrite the get_extra_parameters if you want to obtain the extra cost. ... ``` 2. regist the distiller in `distiller_dict` at `mdistiller/distillers/__init__.py` 3. regist the corresponding hyper-parameters at `mdistiller/engines/cfg.py` 4. create a new config file and test it. # Citation If this repo is helpful for your research, please consider citing the paper: ```BibTeX @article{zhao2022dkd, title={Decoupled Knowledge Distillation}, author={Zhao, Borui and Cui, Quan and Song, Renjie and Qiu, Yiyu and Liang, Jiajun}, journal={arXiv preprint arXiv:2203.08679}, year={2022} } @article{zhao2023dot, title={DOT: A Distillation-Oriented Trainer}, author={Zhao, Borui and Cui, Quan and Song, Renjie and Liang, Jiajun}, journal={arXiv preprint arXiv:2307.08436}, year={2023} } ``` # License MDistiller is released under the MIT license. See [LICENSE](LICENSE) for details. # Acknowledgement - Thanks for CRD and ReviewKD. We build this library based on the [CRD's codebase](https://github.com/HobbitLong/RepDistiller) and the [ReviewKD's codebase](https://github.com/dvlab-research/ReviewKD). - Thanks Yiyu Qiu and Yi Shi for the code contribution during their internship in MEGVII Technology. - Thanks Xin Jin for the discussion about DKD. ================================================ FILE: configs/cifar100/at.yaml ================================================ EXPERIMENT: NAME: "" TAG: "at,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "AT" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/crd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "crd,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "CRD" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" TRAINER: "crd" ================================================ FILE: configs/cifar100/dkd/res110_res32.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,res110,res32" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "DKD" TEACHER: "resnet110" STUDENT: "resnet32" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" DKD: BETA: 2.0 ================================================ FILE: configs/cifar100/dkd/res32x4_res8x4.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "DKD" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/dkd/res32x4_shuv1.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,res32x4,shuv1" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "DKD" TEACHER: "resnet32x4" STUDENT: "ShuffleV1" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.01 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/dkd/res32x4_shuv2.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,res32x4,shuv2" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "DKD" TEACHER: "resnet32x4" STUDENT: "ShuffleV2" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.01 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/dkd/res50_mv2.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,res50,mv2" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "DKD" TEACHER: "ResNet50" STUDENT: "MobileNetV2" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.01 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/dkd/res56_res20.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,res56,res20" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "DKD" TEACHER: "resnet56" STUDENT: "resnet20" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" DKD: BETA: 2.0 ================================================ FILE: configs/cifar100/dkd/vgg13_mv2.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,vgg13,mv2" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "DKD" TEACHER: "vgg13" STUDENT: "MobileNetV2" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.01 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" DKD: BETA: 6.0 ================================================ FILE: configs/cifar100/dkd/vgg13_vgg8.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,vgg13,vgg8" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "DKD" TEACHER: "vgg13" STUDENT: "vgg8" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" DKD: BETA: 6.0 ================================================ FILE: configs/cifar100/dkd/wrn40_2_shuv1.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,wrn_40_2,shuv1" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "DKD" TEACHER: "wrn_40_2" STUDENT: "ShuffleV1" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.01 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/dkd/wrn40_2_wrn_16_2.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,wrn_40_2,wrn_16_2" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "DKD" TEACHER: "wrn_40_2" STUDENT: "wrn_16_2" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" DKD: BETA: 6.0 ================================================ FILE: configs/cifar100/dkd/wrn40_2_wrn_40_1.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,wrn_40_2,wrn_40_1" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "DKD" TEACHER: "wrn_40_2" STUDENT: "wrn_40_1" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" DKD: BETA: 6.0 ================================================ FILE: configs/cifar100/dot/res32x4_res8x4.yaml ================================================ EXPERIMENT: NAME: "" TAG: "kd,dot,res32x4,res8x4" PROJECT: "dot_cifar" DISTILLER: TYPE: "KD" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" TRAINER: "dot" DOT: DELTA: 0.075 ================================================ FILE: configs/cifar100/dot/res32x4_shuv2.yaml ================================================ EXPERIMENT: NAME: "" TAG: "kd,dot,res32x4,shuv2" PROJECT: "dot_cifar" DISTILLER: TYPE: "KD" TEACHER: "resnet32x4" STUDENT: "ShuffleV2" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.01 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" TRAINER: "dot" DOT: DELTA: 0.075 ================================================ FILE: configs/cifar100/dot/vgg13_vgg8.yaml ================================================ EXPERIMENT: NAME: "" TAG: "kd,dot,vgg13,vgg8" PROJECT: "dot_cifar" DISTILLER: TYPE: "KD" TEACHER: "vgg13" STUDENT: "vgg8" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" TRAINER: "dot" DOT: DELTA: 0.075 ================================================ FILE: configs/cifar100/fitnet.yaml ================================================ EXPERIMENT: NAME: "" TAG: "fitnet,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "FITNET" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/kd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "kd,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "KD" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/kdsvd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "kdsvd,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "KDSVD" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/nst.yaml ================================================ EXPERIMENT: NAME: "" TAG: "nst,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "NST" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/ofd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "ofd,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "OFD" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/pkt.yaml ================================================ EXPERIMENT: NAME: "" TAG: "pkt,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "PKT" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/reviewkd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "reviewkd,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "REVIEWKD" TEACHER: "resnet32x4" STUDENT: "resnet8x4" REVIEWKD: REVIEWKD_WEIGHT: 5.0 SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/rkd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "rkd,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "RKD" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/sp.yaml ================================================ EXPERIMENT: NAME: "" TAG: "sp,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "SP" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/vanilla.yaml ================================================ EXPERIMENT: NAME: "" TAG: "vanilla,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "NONE" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/cifar100/vid.yaml ================================================ EXPERIMENT: NAME: "" TAG: "vid,res32x4,res8x4" PROJECT: "cifar100_baselines" DISTILLER: TYPE: "VID" TEACHER: "resnet32x4" STUDENT: "resnet8x4" SOLVER: BATCH_SIZE: 64 EPOCHS: 240 LR: 0.05 LR_DECAY_STAGES: [150, 180, 210] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" ================================================ FILE: configs/imagenet/r34_r18/at.yaml ================================================ EXPERIMENT: NAME: "" TAG: "at,res34,res18" PROJECT: "imagenet_baselines" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "AT" TEACHER: "ResNet34" STUDENT: "ResNet18" SOLVER: BATCH_SIZE: 512 EPOCHS: 100 LR: 0.2 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 ================================================ FILE: configs/imagenet/r34_r18/crd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "crd,res34,res18" PROJECT: "imagenet_baselines" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "CRD" TEACHER: "ResNet34" STUDENT: "ResNet18" SOLVER: BATCH_SIZE: 256 EPOCHS: 100 LR: 0.1 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" TRAINER: "crd" CRD: FEAT: STUDENT_DIM: 512 TEACHER_DIM: 512 LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 ================================================ FILE: configs/imagenet/r34_r18/dkd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,res34,res18" PROJECT: "imagenet_baselines" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "DKD" TEACHER: "ResNet34" STUDENT: "ResNet18" SOLVER: BATCH_SIZE: 512 EPOCHS: 100 LR: 0.2 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 DKD: CE_WEIGHT: 1.0 BETA: 0.5 T: 1.0 WARMUP: 1 ================================================ FILE: configs/imagenet/r34_r18/dot.yaml ================================================ EXPERIMENT: NAME: "" TAG: "kd,dot,res34,res18" PROJECT: "dot_imagenet" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "KD" TEACHER: "ResNet34" STUDENT: "ResNet18" SOLVER: BATCH_SIZE: 512 EPOCHS: 100 LR: 0.2 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" TRAINER: "dot" DOT: DELTA: 0.09 KD: TEMPERATURE: 1 LOSS: CE_WEIGHT: 0.5 KD_WEIGHT: 0.5 LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 ================================================ FILE: configs/imagenet/r34_r18/kd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "kd,res34,res18" PROJECT: "imagenet_baselines" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "KD" TEACHER: "ResNet34" STUDENT: "ResNet18" SOLVER: BATCH_SIZE: 512 EPOCHS: 100 LR: 0.2 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" KD: TEMPERATURE: 1 LOSS: CE_WEIGHT: 0.5 KD_WEIGHT: 0.5 LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 ================================================ FILE: configs/imagenet/r34_r18/reviewkd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "reviewkd,res34,res18" PROJECT: "imagenet_baselines" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "REVIEWKD" TEACHER: "ResNet34" STUDENT: "ResNet18" SOLVER: BATCH_SIZE: 256 EPOCHS: 100 LR: 0.1 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 REVIEWKD: CE_WEIGHT: 1.0 REVIEWKD_WEIGHT: 1.0 WARMUP_EPOCHS: 1 SHAPES: [1,7,14,28,56] OUT_SHAPES: [1,7,14,28,56] IN_CHANNELS: [64,128,256,512,512] OUT_CHANNELS: [64,128,256,512,512] STU_PREACT: True ================================================ FILE: configs/imagenet/r50_mv1/at.yaml ================================================ EXPERIMENT: NAME: "" TAG: "at,res50,mobilenetv1" PROJECT: "imagenet_baselines" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "AT" TEACHER: "ResNet50" STUDENT: "MobileNetV1" SOLVER: BATCH_SIZE: 512 EPOCHS: 100 LR: 0.2 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 ================================================ FILE: configs/imagenet/r50_mv1/crd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "crd,res50,mobilenetv1" PROJECT: "imagenet_baselines" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "CRD" TEACHER: "ResNet50" STUDENT: "MobileNetV1" SOLVER: BATCH_SIZE: 256 EPOCHS: 100 LR: 0.1 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" TRAINER: "crd" CRD: FEAT: STUDENT_DIM: 1024 TEACHER_DIM: 2048 LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 ================================================ FILE: configs/imagenet/r50_mv1/dkd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "dkd,res50,mobilenetv1" PROJECT: "imagenet_baselines" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "DKD" TEACHER: "ResNet50" STUDENT: "MobileNetV1" SOLVER: BATCH_SIZE: 512 EPOCHS: 100 LR: 0.2 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 DKD: CE_WEIGHT: 1.0 BETA: 2.0 T: 1.0 WARMUP: 1 ================================================ FILE: configs/imagenet/r50_mv1/dot.yaml ================================================ EXPERIMENT: NAME: "" TAG: "kd,dot,res50,mobilenetv1" PROJECT: "dot_imagenet" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "KD" TEACHER: "ResNet50" STUDENT: "MobileNetV1" SOLVER: BATCH_SIZE: 512 EPOCHS: 100 LR: 0.2 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" TRAINER: "dot" DOT: DELTA: 0.09 KD: TEMPERATURE: 1 LOSS: CE_WEIGHT: 0.5 KD_WEIGHT: 0.5 LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 ================================================ FILE: configs/imagenet/r50_mv1/kd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "kd,res50,mobilenetv1" PROJECT: "imagenet_baselines" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "KD" TEACHER: "ResNet50" STUDENT: "MobileNetV1" SOLVER: BATCH_SIZE: 512 EPOCHS: 100 LR: 0.2 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" KD: TEMPERATURE: 1 LOSS: CE_WEIGHT: 0.5 KD_WEIGHT: 0.5 LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 ================================================ FILE: configs/imagenet/r50_mv1/ofd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "ofd,res50,mobilenetv1" PROJECT: "imagenet_baselines" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "OFD" TEACHER: "ResNet50" STUDENT: "MobileNetV1" SOLVER: BATCH_SIZE: 128 EPOCHS: 100 LR: 0.05 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" OFD: LOSS: FEAT_WEIGHT: 0.0001 LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 ================================================ FILE: configs/imagenet/r50_mv1/reviewkd.yaml ================================================ EXPERIMENT: NAME: "" TAG: "reviewkd,res50,mobilenetv1" PROJECT: "imagenet_baselines" DATASET: TYPE: "imagenet" NUM_WORKERS: 32 TEST: BATCH_SIZE: 128 DISTILLER: TYPE: "REVIEWKD" TEACHER: "ResNet50" STUDENT: "MobileNetV1" SOLVER: BATCH_SIZE: 256 EPOCHS: 100 LR: 0.1 LR_DECAY_STAGES: [30, 60, 90] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0001 MOMENTUM: 0.9 TYPE: "SGD" LOG: TENSORBOARD_FREQ: 50 SAVE_CHECKPOINT_FREQ: 10 REVIEWKD: CE_WEIGHT: 1.0 REVIEWKD_WEIGHT: 8.0 WARMUP_EPOCHS: 1 SHAPES: [1,7,14,28,56] OUT_SHAPES: [1,7,14,28,56] IN_CHANNELS: [128,256,512,1024,1024] OUT_CHANNELS: [256,512,1024,2048,2048] MAX_MID_CHANNEL: 256 STU_PREACT: True ================================================ FILE: configs/tiny_imagenet/dot/r18_mv2.yaml ================================================ EXPERIMENT: NAME: "" TAG: "kd,dot,r18,mv2" PROJECT: "dot_tinyimagenet" DATASET: TYPE: "tiny_imagenet" NUM_WORKERS: 16 DISTILLER: TYPE: "KD" TEACHER: "ResNet18" STUDENT: "MobileNetV2" SOLVER: BATCH_SIZE: 256 EPOCHS: 200 LR: 0.2 LR_DECAY_STAGES: [60, 120, 160] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" TRAINER: "dot" DOT: DELTA: 0.075 ================================================ FILE: configs/tiny_imagenet/dot/r18_shuv2.yaml ================================================ EXPERIMENT: NAME: "" TAG: "kd,dot,r18,shuv2" PROJECT: "dot_tinyimagenet" DATASET: TYPE: "tiny_imagenet" NUM_WORKERS: 16 DISTILLER: TYPE: "KD" TEACHER: "ResNet18" STUDENT: "ShuffleV2" SOLVER: BATCH_SIZE: 256 EPOCHS: 200 LR: 0.2 LR_DECAY_STAGES: [60, 120, 160] LR_DECAY_RATE: 0.1 WEIGHT_DECAY: 0.0005 MOMENTUM: 0.9 TYPE: "SGD" TRAINER: "dot" DOT: DELTA: 0.075 ================================================ FILE: detection/README.md ================================================ # COCO object detection and instance segmentation PS: based on the [ReviewKD's codebase](https://github.com/dvlab-research/ReviewKD). ## Environment * 4 GPUs * python 3.6 * torch 1.9.0 * torchvision 0.10.0 ## Installation Our code is based on Detectron2, please install Detectron2 refer to https://github.com/facebookresearch/detectron2. Please put the [COCO](https://cocodataset.org/#download) dataset in datasets/. Please put the pretrained weights for teacher and student in pretrained/. You can find the pretrained weights [here](https://github.com/dvlab-research/ReviewKD/releases/). The pretrained models we provided contains both teacher's and student's weights. The teacher's weights come from Detectron2's pretrained detector. The student's weights are ImageNet pretrained weights. ## Training ``` # Tea: R-101, Stu: R-18 python3 train_net.py --config-file configs/DKD/DKD-R18-R101.yaml --num-gpus 4 # Tea: R-101, Stu: R-50 python3 train_net.py --config-file configs/DKD/DKD-R50-R101.yaml --num-gpus 4 # Tea: R-50, Stu: MV2 python3 train_net.py --config-file configs/DKD/DKD-MV2-R50.yaml --num-gpus 4 ``` ================================================ FILE: detection/__init__.py ================================================ ================================================ FILE: detection/configs/Base-Distillation.yaml ================================================ MODEL: META_ARCHITECTURE: "RCNNKD" BACKBONE: NAME: "build_resnet_fpn_backbone_kd" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"] ANCHOR_GENERATOR: SIZES: [[32], [64], [128], [256], [512]] # One size for each in feature map ASPECT_RATIOS: [[0.5, 1.0, 2.0]] # Three aspect ratios (same for all in feature maps) RPN: IN_FEATURES: ["p2", "p3", "p4", "p5", "p6"] PRE_NMS_TOPK_TRAIN: 2000 # Per FPN level PRE_NMS_TOPK_TEST: 1000 # Per FPN level # Detectron1 uses 2000 proposals per-batch, # (See "modeling/rpn/rpn_outputs.py" for details of this legacy issue) # which is approximately 1000 proposals per-image since the default batch size for FPN is 2. POST_NMS_TOPK_TRAIN: 1000 POST_NMS_TOPK_TEST: 1000 ROI_HEADS: NAME: "StandardROIHeads" IN_FEATURES: ["p2", "p3", "p4", "p5"] ROI_BOX_HEAD: NAME: "FastRCNNConvFCHead" NUM_FC: 2 POOLER_RESOLUTION: 7 ROI_MASK_HEAD: NAME: "MaskRCNNConvUpsampleHead" NUM_CONV: 4 POOLER_RESOLUTION: 14 TEACHER: MODEL: META_ARCHITECTURE: "GeneralizedRCNN" BACKBONE: NAME: "build_resnet_fpn_backbone" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"] ANCHOR_GENERATOR: SIZES: [[32], [64], [128], [256], [512]] # One size for each in feature map ASPECT_RATIOS: [[0.5, 1.0, 2.0]] # Three aspect ratios (same for all in feature maps) RPN: IN_FEATURES: ["p2", "p3", "p4", "p5", "p6"] PRE_NMS_TOPK_TRAIN: 2000 # Per FPN level PRE_NMS_TOPK_TEST: 1000 # Per FPN level # Detectron1 uses 2000 proposals per-batch, # (See "modeling/rpn/rpn_outputs.py" for details of this legacy issue) # which is approximately 1000 proposals per-image since the default batch size for FPN is 2. POST_NMS_TOPK_TRAIN: 1000 POST_NMS_TOPK_TEST: 1000 ROI_HEADS: NAME: "StandardROIHeads" IN_FEATURES: ["p2", "p3", "p4", "p5"] ROI_BOX_HEAD: NAME: "FastRCNNConvFCHead" NUM_FC: 2 POOLER_RESOLUTION: 7 ROI_MASK_HEAD: NAME: "MaskRCNNConvUpsampleHead" NUM_CONV: 4 POOLER_RESOLUTION: 14 DATASETS: TRAIN: ("coco_2017_train",) TEST: ("coco_2017_val",) SOLVER: IMS_PER_BATCH: 16 BASE_LR: 0.02 STEPS: (60000, 80000) MAX_ITER: 90000 INPUT: MIN_SIZE_TRAIN: (640, 672, 704, 736, 768, 800) VERSION: 2 ================================================ FILE: detection/configs/DKD/DKD-MV2-R50.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/DKD-MV2-R50 MODEL: BACKBONE: NAME: "build_mobilenetv2_fpn_backbone" FREEZE_AT: 0 WEIGHTS: "pretrained/mv2-r50.pth" MOBILENETV2: OUT_FEATURES: ["m2", "m3", "m4", "m5"] FPN: IN_FEATURES: ["m2", "m3", "m4", "m5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 50 KD: TYPE: "DKD" SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/configs/DKD/DKD-R18-R101.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/DKD-R18-R101 INPUT: FORMAT: 'RGB' MODEL: PIXEL_STD: [57.375, 57.120, 58.395] BACKBONE: NAME: "build_resnet_fpn_backbone_kd" WEIGHTS: "pretrained/r18-r101.pth" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] DEPTH: 18 RES2_OUT_CHANNELS: 64 FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 101 KD: TYPE: "DKD" SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/configs/DKD/DKD-R50-R101.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/DKD-R50-R101 MODEL: BACKBONE: NAME: "build_resnet_fpn_backbone_kd" WEIGHTS: "pretrained/r50-r101.pth" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] DEPTH: 50 FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 101 KD: TYPE: "DKD" SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/configs/DKD/ReviewDKD-MV2-R50.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/ReviewDKD-MV2-R50 MODEL: BACKBONE: NAME: "build_mobilenetv2_fpn_backbone" FREEZE_AT: 0 WEIGHTS: "pretrained/mv2-r50.pth" MOBILENETV2: OUT_FEATURES: ["m2", "m3", "m4", "m5"] FPN: IN_FEATURES: ["m2", "m3", "m4", "m5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 50 KD: TYPE: "ReviewDKD" REVIEWKD: LOSS_WEIGHT: 2.0 SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/configs/DKD/ReviewDKD-R18-R101.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/ReviewDKD-R18-R101 INPUT: FORMAT: 'RGB' MODEL: PIXEL_STD: [57.375, 57.120, 58.395] BACKBONE: NAME: "build_resnet_fpn_backbone_kd" WEIGHTS: "pretrained/r18-r101.pth" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] DEPTH: 18 RES2_OUT_CHANNELS: 64 FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 101 KD: TYPE: "ReviewDKD" REVIEWKD: LOSS_WEIGHT: 1.2 SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/configs/DKD/ReviewDKD-R50-R101.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/ReviewDKD-R50-R101 MODEL: BACKBONE: NAME: "build_resnet_fpn_backbone_kd" WEIGHTS: "pretrained/r50-r101.pth" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] DEPTH: 50 FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 101 KD: TYPE: "ReviewDKD" REVIEWKD: LOSS_WEIGHT: 1.0 SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/configs/ReviewKD/ReviewKD-MV2-R50-Mask.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/ReviewKD-MV2-R50-Mask MODEL: MASK_ON: True BACKBONE: NAME: "build_mobilenetv2_fpn_backbone" FREEZE_AT: 0 WEIGHTS: "pretrained/mv2-r50mask.pth" MOBILENETV2: OUT_FEATURES: ["m2", "m3", "m4", "m5"] FPN: IN_FEATURES: ["m2", "m3", "m4", "m5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 50 KD: TYPE: "ReviewKD" REVIEWKD: LOSS_WEIGHT: 1.0 SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/configs/ReviewKD/ReviewKD-MV2-R50.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/ReviewKD-MV2-R50 MODEL: BACKBONE: NAME: "build_mobilenetv2_fpn_backbone" FREEZE_AT: 0 WEIGHTS: "pretrained/mv2-r50.pth" MOBILENETV2: OUT_FEATURES: ["m2", "m3", "m4", "m5"] FPN: IN_FEATURES: ["m2", "m3", "m4", "m5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 50 KD: TYPE: "ReviewKD" REVIEWKD: LOSS_WEIGHT: 2.0 SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/configs/ReviewKD/ReviewKD-R18-R101-Mask.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/ReviewKD-R18-R101-Mask INPUT: FORMAT: 'RGB' MODEL: PIXEL_STD: [57.375, 57.120, 58.395] MASK_ON: True BACKBONE: NAME: "build_resnet_fpn_backbone_kd" WEIGHTS: "pretrained/r18-r101mask.pth" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] DEPTH: 18 RES2_OUT_CHANNELS: 64 FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 101 KD: TYPE: "ReviewKD" REVIEWKD: LOSS_WEIGHT: 1.5 SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/configs/ReviewKD/ReviewKD-R18-R101.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/ReviewKD-R18-R101 INPUT: FORMAT: 'RGB' MODEL: PIXEL_STD: [57.375, 57.120, 58.395] BACKBONE: NAME: "build_resnet_fpn_backbone_kd" WEIGHTS: "pretrained/r18-r101.pth" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] DEPTH: 18 RES2_OUT_CHANNELS: 64 FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 101 KD: TYPE: "ReviewKD" REVIEWKD: LOSS_WEIGHT: 1.2 SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/configs/ReviewKD/ReviewKD-R50-R101-Mask.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/ReviewKD-R50-R101-Mask MODEL: MASK_ON: True BACKBONE: NAME: "build_resnet_fpn_backbone_kd" WEIGHTS: "pretrained/r50-r101mask.pth" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] DEPTH: 50 FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 101 KD: TYPE: "ReviewKD" REVIEWKD: LOSS_WEIGHT: 0.8 SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/configs/ReviewKD/ReviewKD-R50-R101.yaml ================================================ _BASE_: "../Base-Distillation.yaml" OUTPUT_DIR: output/ReviewKD-R50-R101 MODEL: BACKBONE: NAME: "build_resnet_fpn_backbone_kd" WEIGHTS: "pretrained/r50-r101.pth" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] DEPTH: 50 FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"] PROPOSAL_GENERATOR: NAME: "RPN" ROI_HEADS: NAME: "StandardROIHeads" TEACHER: MODEL: RESNETS: DEPTH: 101 KD: TYPE: "ReviewKD" REVIEWKD: LOSS_WEIGHT: 1.0 SOLVER: IMS_PER_BATCH: 8 BASE_LR: 0.01 MAX_ITER: 180000 STEPS: - 120000 - 160000 ================================================ FILE: detection/model/__init__.py ================================================ import torch from .rcnn import RCNNKD from .config import add_distillation_cfg from .backbone import build_resnet_fpn_backbone_kd ================================================ FILE: detection/model/backbone/__init__.py ================================================ from .resnet import build_resnet_backbone_kd from .fpn import build_resnet_fpn_backbone_kd, build_mobilenetv2_fpn_backbone ================================================ FILE: detection/model/backbone/fpn.py ================================================ from .resnet import build_resnet_backbone_kd from .mobilenetv2 import build_mobilenetv2_backbone from detectron2.modeling.backbone import BACKBONE_REGISTRY, FPN from detectron2.modeling.backbone.fpn import LastLevelMaxPool from detectron2.layers import Conv2d, ShapeSpec, get_norm @BACKBONE_REGISTRY.register() def build_resnet_fpn_backbone_kd(cfg, input_shape: ShapeSpec): # add ResNet 18 """ Args: cfg: a detectron2 CfgNode Returns: backbone (Backbone): backbone module, must be a subclass of :class:`Backbone`. """ bottom_up = build_resnet_backbone_kd(cfg, input_shape) in_features = cfg.MODEL.FPN.IN_FEATURES out_channels = cfg.MODEL.FPN.OUT_CHANNELS backbone = FPN( bottom_up=bottom_up, in_features=in_features, out_channels=out_channels, norm=cfg.MODEL.FPN.NORM, top_block=LastLevelMaxPool(), fuse_type=cfg.MODEL.FPN.FUSE_TYPE, ) return backbone @BACKBONE_REGISTRY.register() def build_mobilenetv2_fpn_backbone(cfg, input_shape: ShapeSpec): """ Args: cfg: a detectron2 CfgNode Returns: backbone (Backbone): backbone module, must be a subclass of :class:`Backbone`. """ bottom_up = build_mobilenetv2_backbone(cfg, input_shape) in_features = cfg.MODEL.FPN.IN_FEATURES out_channels = cfg.MODEL.FPN.OUT_CHANNELS backbone = FPN( bottom_up=bottom_up, in_features=in_features, out_channels=out_channels, norm=cfg.MODEL.FPN.NORM, top_block=LastLevelMaxPool(), fuse_type=cfg.MODEL.FPN.FUSE_TYPE, ) return backbone ================================================ FILE: detection/model/backbone/mobilenetv2.py ================================================ """ Creates a MobileNetV2 Model as defined in: Mark Sandler, Andrew Howard, Menglong Zhu, Andrey Zhmoginov, Liang-Chieh Chen. (2018). MobileNetV2: Inverted Residuals and Linear Bottlenecks arXiv preprint arXiv:1801.04381. import from https://github.com/tonylins/pytorch-mobilenet-v2 """ import torch.nn as nn import math from detectron2.modeling.backbone import BACKBONE_REGISTRY from detectron2.modeling.backbone import Backbone, FPN from detectron2.modeling.backbone.fpn import LastLevelMaxPool from detectron2.layers import ( Conv2d, DeformConv, FrozenBatchNorm2d, ModulatedDeformConv, ShapeSpec, get_norm, ) __all__ = ['mobilenetv2'] def _make_divisible(v, divisor, min_value=None): """ This function is taken from the original tf repo. It ensures that all layers have a channel number that is divisible by 8 It can be seen here: https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py :param v: :param divisor: :param min_value: :return: """ if min_value is None: min_value = divisor new_v = max(min_value, int(v + divisor / 2) // divisor * divisor) # Make sure that round down does not go down by more than 10%. if new_v < 0.9 * v: new_v += divisor return new_v def conv_3x3_bn(inp, oup, stride, bn): return nn.Sequential( nn.Conv2d(inp, oup, 3, stride, 1, bias=False), get_norm(bn, oup), nn.ReLU6(inplace=True) ) def conv_1x1_bn(inp, oup): return nn.Sequential( nn.Conv2d(inp, oup, 1, 1, 0, bias=False), get_norm(bn, oup), nn.ReLU6(inplace=True) ) class InvertedResidual(nn.Module): def __init__(self, inp, oup, stride, expand_ratio, bn): super(InvertedResidual, self).__init__() assert stride in [1, 2] hidden_dim = round(inp * expand_ratio) self.identity = stride == 1 and inp == oup if expand_ratio == 1: self.conv = nn.Sequential( # dw nn.Conv2d(hidden_dim, hidden_dim, 3, stride, 1, groups=hidden_dim, bias=False), get_norm(bn, hidden_dim), nn.ReLU6(inplace=True), # pw-linear nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False), get_norm(bn, oup), ) else: self.conv = nn.Sequential( # pw nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False), get_norm(bn, hidden_dim), nn.ReLU6(inplace=True), # dw nn.Conv2d(hidden_dim, hidden_dim, 3, stride, 1, groups=hidden_dim, bias=False), get_norm(bn, hidden_dim), nn.ReLU6(inplace=True), # pw-linear nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False), get_norm(bn, oup), ) def forward(self, x): if self.identity: return x + self.conv(x) else: return self.conv(x) def freeze(self): for p in self.parameters(): p.requires_grad = False FrozenBatchNorm2d.convert_frozen_batchnorm(self) return self class MobileNetV2(Backbone): def __init__(self, cfg, input_shape, width_mult = 1.): super(MobileNetV2, self).__init__() self._out_features = cfg.MODEL.MOBILENETV2.OUT_FEATURES bn = cfg.MODEL.MOBILENETV2.NORM freeze_at = cfg.MODEL.BACKBONE.FREEZE_AT # setting of inverted residual blocks self.cfgs = [ # t, c, n, s [1, 16, 1, 1, ''], [6, 24, 2, 2, 'm2'], [6, 32, 3, 2, 'm3'], [6, 64, 4, 2, ''], [6, 96, 3, 1, 'm4'], [6, 160, 3, 2, ''], [6, 320, 1, 1, 'm5'], ] # building first layer input_channel = _make_divisible(32 * width_mult, 4 if width_mult == 0.1 else 8) layers = [conv_3x3_bn(input_shape.channels, input_channel, 2, bn)] if freeze_at >= 1: for p in layers[0].parameters(): p.requires_grad = False layers[0] = FrozenBatchNorm2d.convert_frozen_batchnorm(layers[0]) # building inverted residual blocks block = InvertedResidual self.stage_name = [''] self._out_feature_channels = {} self._out_feature_strides = {} cur_stride = 2 cur_stage = 2 for t, c, n, s, name in self.cfgs: output_channel = _make_divisible(c * width_mult, 4 if width_mult == 0.1 else 8) cur_stride = cur_stride * s for i in range(n): layers.append(block(input_channel, output_channel, s if i == 0 else 1, t, bn)) if cur_stage <= freeze_at : layers[-1].freeze() if name != '' and i == n-1: self._out_feature_channels[name] = output_channel self._out_feature_strides[name] = cur_stride cur_stage += 1 input_channel = output_channel self.stage_name.append(name if i == n-1 else '') self.features = nn.Sequential(*layers) # building last several layers # output_channel = _make_divisible(1280 * width_mult, 4 if width_mult == 0.1 else 8) if width_mult > 1.0 else 1280 # self.conv = conv_1x1_bn(input_channel, output_channel) # self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) # self.classifier = nn.Linear(output_channel, num_classes) self._initialize_weights() def forward(self, x): output = {} for i in range(len(self.features)): x = self.features[i](x) if self.stage_name[i] in self._out_features: output[self.stage_name[i]] = x return output ''' x = self.features(x) x = self.conv(x) x = self.avgpool(x) x = x.view(x.size(0), -1) x = self.classifier(x) return x ''' def _initialize_weights(self): for m in self.modules(): if isinstance(m, nn.Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2. / n)) if m.bias is not None: m.bias.data.zero_() elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_() elif isinstance(m, nn.Linear): m.weight.data.normal_(0, 0.01) m.bias.data.zero_() def output_shape(self): return { name: ShapeSpec( channels=self._out_feature_channels[name], stride=self._out_feature_strides[name] ) for name in self._out_features } @BACKBONE_REGISTRY.register() def build_mobilenetv2_backbone(cfg, input_shape): """ Constructs a MobileNet V2 model """ return MobileNetV2(cfg, input_shape) ================================================ FILE: detection/model/backbone/resnet.py ================================================ # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved import numpy as np import fvcore.nn.weight_init as weight_init import torch import torch.nn.functional as F from torch import nn from detectron2.layers import ( Conv2d, DeformConv, FrozenBatchNorm2d, ModulatedDeformConv, ShapeSpec, get_norm, ) from detectron2.modeling.backbone import Backbone, BACKBONE_REGISTRY __all__ = [ "ResNetBlockBase", "BottleneckBlock", "DeformBottleneckBlock", "BasicStem", "ResNet", "make_stage", "build_resnet_backbone", ] class ResNetBlockBase(nn.Module): def __init__(self, in_channels, out_channels, stride): """ The `__init__` method of any subclass should also contain these arguments. Args: in_channels (int): out_channels (int): stride (int): """ super().__init__() self.in_channels = in_channels self.out_channels = out_channels self.stride = stride def freeze(self): for p in self.parameters(): p.requires_grad = False FrozenBatchNorm2d.convert_frozen_batchnorm(self) return self class BasicBlock(ResNetBlockBase): def __init__( self, in_channels, out_channels, *, bottleneck_channels, stride=1, num_groups=1, norm="BN", stride_in_1x1=False, dilation=1, ): super().__init__(in_channels, out_channels, stride) if in_channels != out_channels: self.shortcut = Conv2d( in_channels, out_channels, kernel_size=1, stride=stride, bias=False, norm=get_norm(norm, out_channels), ) else: self.shortcut = None self.conv1 = Conv2d( in_channels, out_channels, kernel_size=3, stride=stride, padding=1 * dilation, bias=False, groups=num_groups, dilation=dilation, norm=get_norm(norm, out_channels), ) self.conv2 = Conv2d( out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False, groups=num_groups, dilation=1, norm=get_norm(norm, out_channels), ) for layer in [self.conv1, self.conv2, self.shortcut]: if layer is not None: # shortcut can be None weight_init.c2_msra_fill(layer) def forward(self, x): out = self.conv1(x) out = F.relu_(out) out = self.conv2(out) if self.shortcut is not None: shortcut = self.shortcut(x) else: shortcut = x out += shortcut out = F.relu_(out) return out class BottleneckBlock(ResNetBlockBase): def __init__( self, in_channels, out_channels, *, bottleneck_channels, stride=1, num_groups=1, norm="BN", stride_in_1x1=False, dilation=1, ): """ Args: norm (str or callable): a callable that takes the number of channels and return a `nn.Module`, or a pre-defined string (one of {"FrozenBN", "BN", "GN"}). stride_in_1x1 (bool): when stride==2, whether to put stride in the first 1x1 convolution or the bottleneck 3x3 convolution. """ super().__init__(in_channels, out_channels, stride) if in_channels != out_channels: self.shortcut = Conv2d( in_channels, out_channels, kernel_size=1, stride=stride, bias=False, norm=get_norm(norm, out_channels), ) else: self.shortcut = None # The original MSRA ResNet models have stride in the first 1x1 conv # The subsequent fb.torch.resnet and Caffe2 ResNe[X]t implementations have # stride in the 3x3 conv stride_1x1, stride_3x3 = (stride, 1) if stride_in_1x1 else (1, stride) self.conv1 = Conv2d( in_channels, bottleneck_channels, kernel_size=1, stride=stride_1x1, bias=False, norm=get_norm(norm, bottleneck_channels), ) self.conv2 = Conv2d( bottleneck_channels, bottleneck_channels, kernel_size=3, stride=stride_3x3, padding=1 * dilation, bias=False, groups=num_groups, dilation=dilation, norm=get_norm(norm, bottleneck_channels), ) self.conv3 = Conv2d( bottleneck_channels, out_channels, kernel_size=1, bias=False, norm=get_norm(norm, out_channels), ) for layer in [self.conv1, self.conv2, self.conv3, self.shortcut]: if layer is not None: # shortcut can be None weight_init.c2_msra_fill(layer) # Zero-initialize the last normalization in each residual branch, # so that at the beginning, the residual branch starts with zeros, # and each residual block behaves like an identity. # See Sec 5.1 in "Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour": # "For BN layers, the learnable scaling coefficient γ is initialized # to be 1, except for each residual block's last BN # where γ is initialized to be 0." # nn.init.constant_(self.conv3.norm.weight, 0) # TODO this somehow hurts performance when training GN models from scratch. # Add it as an option when we need to use this code to train a backbone. def forward(self, x): out = self.conv1(x) out = F.relu_(out) out = self.conv2(out) out = F.relu_(out) out = self.conv3(out) if self.shortcut is not None: shortcut = self.shortcut(x) else: shortcut = x out += shortcut out = F.relu_(out) return out class DeformBottleneckBlock(ResNetBlockBase): def __init__( self, in_channels, out_channels, *, bottleneck_channels, stride=1, num_groups=1, norm="BN", stride_in_1x1=False, dilation=1, deform_modulated=False, deform_num_groups=1, ): """ Similar to :class:`BottleneckBlock`, but with deformable conv in the 3x3 convolution. """ super().__init__(in_channels, out_channels, stride) self.deform_modulated = deform_modulated if in_channels != out_channels: self.shortcut = Conv2d( in_channels, out_channels, kernel_size=1, stride=stride, bias=False, norm=get_norm(norm, out_channels), ) else: self.shortcut = None stride_1x1, stride_3x3 = (stride, 1) if stride_in_1x1 else (1, stride) self.conv1 = Conv2d( in_channels, bottleneck_channels, kernel_size=1, stride=stride_1x1, bias=False, norm=get_norm(norm, bottleneck_channels), ) if deform_modulated: deform_conv_op = ModulatedDeformConv # offset channels are 2 or 3 (if with modulated) * kernel_size * kernel_size offset_channels = 27 else: deform_conv_op = DeformConv offset_channels = 18 self.conv2_offset = Conv2d( bottleneck_channels, offset_channels * deform_num_groups, kernel_size=3, stride=stride_3x3, padding=1 * dilation, dilation=dilation, ) self.conv2 = deform_conv_op( bottleneck_channels, bottleneck_channels, kernel_size=3, stride=stride_3x3, padding=1 * dilation, bias=False, groups=num_groups, dilation=dilation, deformable_groups=deform_num_groups, norm=get_norm(norm, bottleneck_channels), ) self.conv3 = Conv2d( bottleneck_channels, out_channels, kernel_size=1, bias=False, norm=get_norm(norm, out_channels), ) for layer in [self.conv1, self.conv2, self.conv3, self.shortcut]: if layer is not None: # shortcut can be None weight_init.c2_msra_fill(layer) nn.init.constant_(self.conv2_offset.weight, 0) nn.init.constant_(self.conv2_offset.bias, 0) def forward(self, x): out = self.conv1(x) out = F.relu_(out) if self.deform_modulated: offset_mask = self.conv2_offset(out) offset_x, offset_y, mask = torch.chunk(offset_mask, 3, dim=1) offset = torch.cat((offset_x, offset_y), dim=1) mask = mask.sigmoid() out = self.conv2(out, offset, mask) else: offset = self.conv2_offset(out) out = self.conv2(out, offset) out = F.relu_(out) out = self.conv3(out) if self.shortcut is not None: shortcut = self.shortcut(x) else: shortcut = x out += shortcut out = F.relu_(out) return out def make_stage(block_class, num_blocks, first_stride, **kwargs): """ Create a resnet stage by creating many blocks. Args: block_class (class): a subclass of ResNetBlockBase num_blocks (int): first_stride (int): the stride of the first block. The other blocks will have stride=1. A `stride` argument will be passed to the block constructor. kwargs: other arguments passed to the block constructor. Returns: list[nn.Module]: a list of block module. """ blocks = [] for i in range(num_blocks): blocks.append(block_class(stride=first_stride if i == 0 else 1, **kwargs)) kwargs["in_channels"] = kwargs["out_channels"] return blocks class BasicStem(nn.Module): def __init__(self, in_channels=3, out_channels=64, norm="BN"): """ Args: norm (str or callable): a callable that takes the number of channels and return a `nn.Module`, or a pre-defined string (one of {"FrozenBN", "BN", "GN"}). """ super().__init__() self.conv1 = Conv2d( in_channels, out_channels, kernel_size=7, stride=2, padding=3, bias=False, norm=get_norm(norm, out_channels), ) weight_init.c2_msra_fill(self.conv1) def forward(self, x): x = self.conv1(x) x = F.relu_(x) x = F.max_pool2d(x, kernel_size=3, stride=2, padding=1) return x @property def out_channels(self): return self.conv1.out_channels @property def stride(self): return 4 # = stride 2 conv -> stride 2 max pool class ResNet(Backbone): def __init__(self, stem, stages, num_classes=None, out_features=None): """ Args: stem (nn.Module): a stem module stages (list[list[ResNetBlock]]): several (typically 4) stages, each contains multiple :class:`ResNetBlockBase`. num_classes (None or int): if None, will not perform classification. out_features (list[str]): name of the layers whose outputs should be returned in forward. Can be anything in "stem", "linear", or "res2" ... If None, will return the output of the last layer. """ super(ResNet, self).__init__() self.stem = stem self.num_classes = num_classes current_stride = self.stem.stride self._out_feature_strides = {"stem": current_stride} self._out_feature_channels = {"stem": self.stem.out_channels} self.stages_and_names = [] for i, blocks in enumerate(stages): for block in blocks: assert isinstance(block, ResNetBlockBase), block curr_channels = block.out_channels stage = nn.Sequential(*blocks) name = "res" + str(i + 2) self.add_module(name, stage) self.stages_and_names.append((stage, name)) self._out_feature_strides[name] = current_stride = int( current_stride * np.prod([k.stride for k in blocks]) ) self._out_feature_channels[name] = blocks[-1].out_channels if num_classes is not None: self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) self.linear = nn.Linear(curr_channels, num_classes) # Sec 5.1 in "Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour": # "The 1000-way fully-connected layer is initialized by # drawing weights from a zero-mean Gaussian with standard deviation of 0.01." nn.init.normal_(self.linear.weight, std=0.01) name = "linear" if out_features is None: out_features = [name] self._out_features = out_features assert len(self._out_features) children = [x[0] for x in self.named_children()] for out_feature in self._out_features: assert out_feature in children, "Available children: {}".format(", ".join(children)) def forward(self, x): outputs = {} x = self.stem(x) if "stem" in self._out_features: outputs["stem"] = x for stage, name in self.stages_and_names: x = stage(x) if name in self._out_features: outputs[name] = x if self.num_classes is not None: x = self.avgpool(x) x = torch.flatten(x, 1) x = self.linear(x) if "linear" in self._out_features: outputs["linear"] = x return outputs def output_shape(self): return { name: ShapeSpec( channels=self._out_feature_channels[name], stride=self._out_feature_strides[name] ) for name in self._out_features } @BACKBONE_REGISTRY.register() def build_resnet_backbone_kd(cfg, input_shape): # add ResNet18 setting """ Create a ResNet instance from config. Returns: ResNet: a :class:`ResNet` instance. """ # need registration of new blocks/stems? norm = cfg.MODEL.RESNETS.NORM stem = BasicStem( in_channels=input_shape.channels, out_channels=cfg.MODEL.RESNETS.STEM_OUT_CHANNELS, norm=norm, ) freeze_at = cfg.MODEL.BACKBONE.FREEZE_AT if freeze_at >= 1: for p in stem.parameters(): p.requires_grad = False stem = FrozenBatchNorm2d.convert_frozen_batchnorm(stem) # fmt: off out_features = cfg.MODEL.RESNETS.OUT_FEATURES depth = cfg.MODEL.RESNETS.DEPTH num_groups = cfg.MODEL.RESNETS.NUM_GROUPS width_per_group = cfg.MODEL.RESNETS.WIDTH_PER_GROUP bottleneck_channels = num_groups * width_per_group in_channels = cfg.MODEL.RESNETS.STEM_OUT_CHANNELS out_channels = cfg.MODEL.RESNETS.RES2_OUT_CHANNELS stride_in_1x1 = cfg.MODEL.RESNETS.STRIDE_IN_1X1 res5_dilation = cfg.MODEL.RESNETS.RES5_DILATION deform_on_per_stage = cfg.MODEL.RESNETS.DEFORM_ON_PER_STAGE deform_modulated = cfg.MODEL.RESNETS.DEFORM_MODULATED deform_num_groups = cfg.MODEL.RESNETS.DEFORM_NUM_GROUPS # fmt: on assert res5_dilation in {1, 2}, "res5_dilation cannot be {}.".format(res5_dilation) num_blocks_per_stage = {18:[2,2,2,2], 50: [3, 4, 6, 3], 101: [3, 4, 23, 3], 152: [3, 8, 36, 3]}[depth] stages = [] # Avoid creating variables without gradients # It consumes extra memory and may cause allreduce to fail out_stage_idx = [{"res2": 2, "res3": 3, "res4": 4, "res5": 5}[f] for f in out_features] max_stage_idx = max(out_stage_idx) for idx, stage_idx in enumerate(range(2, max_stage_idx + 1)): dilation = res5_dilation if stage_idx == 5 else 1 first_stride = 1 if idx == 0 or (stage_idx == 5 and dilation == 2) else 2 stage_kargs = { "num_blocks": num_blocks_per_stage[idx], "first_stride": first_stride, "in_channels": in_channels, "bottleneck_channels": bottleneck_channels, "out_channels": out_channels, "num_groups": num_groups, "norm": norm, "stride_in_1x1": stride_in_1x1, "dilation": dilation, } if depth < 50: stage_kargs["block_class"] = BasicBlock elif deform_on_per_stage[idx]: stage_kargs["block_class"] = DeformBottleneckBlock stage_kargs["deform_modulated"] = deform_modulated stage_kargs["deform_num_groups"] = deform_num_groups else: stage_kargs["block_class"] = BottleneckBlock blocks = make_stage(**stage_kargs) in_channels = out_channels out_channels *= 2 bottleneck_channels *= 2 if freeze_at >= stage_idx: for block in blocks: block.freeze() stages.append(blocks) return ResNet(stem, stages, out_features=out_features) ================================================ FILE: detection/model/config.py ================================================ from detectron2.config import CfgNode as CN import numpy as np def add_distillation_cfg(cfg): cfg.MODEL.MOBILENETV2 = CN() # Debug cfg.MODEL.MOBILENETV2.DEBUG = 0 cfg.MODEL.MOBILENETV2.OUT_FEATURES = ['m2'] cfg.MODEL.MOBILENETV2.NORM = 'FrozenBN' cfg.KD = CN() cfg.KD.TYPE = "DKD" # ("DKD", "ReviewKD") # DKD cfg.KD.DKD = CN() cfg.KD.DKD.ALPHA = 1.0 cfg.KD.DKD.BETA = 0.25 cfg.KD.DKD.T = 1.0 # REVIEWKD cfg.KD.REVIEWKD = CN() cfg.KD.REVIEWKD.LOSS_WEIGHT = 1.0 add_teacher_cfg(cfg) def add_teacher_cfg(cfg): cfg.TEACHER = CN() cfg.TEACHER.KD = CN() cfg.TEACHER.KD.FEATURE_KD_MASK = 'None' # fine_grained_mask, gt_box_mask cfg.TEACHER.MODEL = CN() cfg.TEACHER.MODEL.LOAD_PROPOSALS = False cfg.TEACHER.MODEL.MASK_ON = False cfg.TEACHER.MODEL.KEYPOINT_ON = False cfg.TEACHER.MODEL.DEVICE = "cuda" cfg.TEACHER.MODEL.META_ARCHITECTURE = "GeneralizedRCNN" # Path (a file path, or URL like detectron2://.., https://..) to a checkpoint file # to be loaded to the model. You can find available models in the model zoo. cfg.TEACHER.MODEL.WEIGHTS = "" # Values to be used for image normalization (BGR order, since INPUT.FORMAT defaults to BGR). # To train on images of different number of channels, just set different mean & std. # Default values are the mean pixel value from ImageNet: [103.53, 116.28, 123.675] cfg.TEACHER.MODEL.PIXEL_MEAN = [103.530, 116.280, 123.675] # When using pre-trained models in Detectron1 or any MSRA models, # std has been absorbed into its conv1 weights, so the std needs to be set 1. # Otherwise, you can use [57.375, 57.120, 58.395] (ImageNet std) cfg.TEACHER.MODEL.PIXEL_STD = [1.0, 1.0, 1.0] # ----------------------------------------------------------------------------- # INPUT # ----------------------------------------------------------------------------- cfg.TEACHER.INPUT = CN() # Size of the smallest side of the image during training cfg.TEACHER.INPUT.MIN_SIZE_TRAIN = (800,) # Sample size of smallest side by choice or random selection from range give by # INPUT.MIN_SIZE_TRAIN cfg.TEACHER.INPUT.MIN_SIZE_TRAIN_SAMPLING = "choice" # Maximum size of the side of the image during training cfg.TEACHER.INPUT.MAX_SIZE_TRAIN = 1333 # Size of the smallest side of the image during testing. Set to zero to disable resize in testing. cfg.TEACHER.INPUT.MIN_SIZE_TEST = 800 # Maximum size of the side of the image during testing cfg.TEACHER.INPUT.MAX_SIZE_TEST = 1333 # Mode for flipping images used in data augmentation during training # choose one of ["horizontal, "vertical", "none"] cfg.TEACHER.INPUT.RANDOM_FLIP = "horizontal" # `True` if cropping is used for data augmentation during training cfg.TEACHER.INPUT.CROP = CN({"ENABLED": False}) # Cropping type. See documentation of `detectron2.data.transforms.RandomCrop` for explanation. cfg.TEACHER.INPUT.CROP.TYPE = "relative_range" # Size of crop in range (0, 1] if CROP.TYPE is "relative" or "relative_range" and in number of # pixels if CROP.TYPE is "absolute" cfg.TEACHER.INPUT.CROP.SIZE = [0.9, 0.9] # Whether the model needs RGB, YUV, HSV etc. # Should be one of the modes defined here, as we use PIL to read the image: # https://pillow.readthedocs.io/en/stable/handbook/concepts.html#concept-modes # with BGR being the one exception. One can set image format to BGR, we will # internally use RGB for conversion and flip the channels over cfg.TEACHER.INPUT.FORMAT = "BGR" # The ground truth mask format that the model will use. # Mask R-CNN supports either "polygon" or "bitmask" as ground truth. cfg.TEACHER.INPUT.MASK_FORMAT = "polygon" # alternative: "bitmask" # ----------------------------------------------------------------------------- # Dataset # ----------------------------------------------------------------------------- cfg.TEACHER.DATASETS = CN() # List of the dataset names for training. Must be registered in DatasetCatalog # Samples from these datasets will be merged and used as one dataset. cfg.TEACHER.DATASETS.TRAIN = () # List of the pre-computed proposal files for training, which must be consistent # with datasets listed in DATASETS.TRAIN. cfg.TEACHER.DATASETS.PROPOSAL_FILES_TRAIN = () # Number of top scoring precomputed proposals to keep for training cfg.TEACHER.DATASETS.PRECOMPUTED_PROPOSAL_TOPK_TRAIN = 2000 # List of the dataset names for testing. Must be registered in DatasetCatalog cfg.TEACHER.DATASETS.TEST = () # List of the pre-computed proposal files for test, which must be consistent # with datasets listed in DATASETS.TEST. cfg.TEACHER.DATASETS.PROPOSAL_FILES_TEST = () # Number of top scoring precomputed proposals to keep for test cfg.TEACHER.DATASETS.PRECOMPUTED_PROPOSAL_TOPK_TEST = 1000 # ----------------------------------------------------------------------------- # DataLoader # ----------------------------------------------------------------------------- cfg.TEACHER.DATALOADER = CN() # Number of data loading threads cfg.TEACHER.DATALOADER.NUM_WORKERS = 4 # If True, each batch should contain only images for which the aspect ratio # is compatible. This groups portrait images together, and landscape images # are not batched with portrait images. cfg.TEACHER.DATALOADER.ASPECT_RATIO_GROUPING = True # Options: TrainingSampler, RepeatFactorTrainingSampler cfg.TEACHER.DATALOADER.SAMPLER_TRAIN = "TrainingSampler" # Repeat threshold for RepeatFactorTrainingSampler cfg.TEACHER.DATALOADER.REPEAT_THRESHOLD = 0.0 # Tf True, when working on datasets that have instance annotations, the # training dataloader will filter out images without associated annotations cfg.TEACHER.DATALOADER.FILTER_EMPTY_ANNOTATIONS = True # ---------------------------------------------------------------------------- # # Backbone options # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.BACKBONE = CN() cfg.TEACHER.MODEL.BACKBONE.NAME = "build_resnet_backbone" # Freeze the first several stages so they are not trained. # There are 5 stages in ResNet. The first is a convolution, and the following # stages are each group of residual blocks. cfg.TEACHER.MODEL.BACKBONE.FREEZE_AT = 2 # ---------------------------------------------------------------------------- # # FPN options # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.FPN = CN() # Names of the input feature maps to be used by FPN # They must have contiguous power of 2 strides # e.g., ["res2", "res3", "res4", "res5"] cfg.TEACHER.MODEL.FPN.IN_FEATURES = [] cfg.TEACHER.MODEL.FPN.OUT_CHANNELS = 256 # Options: "" (no norm), "GN" cfg.TEACHER.MODEL.FPN.NORM = "" # Types for fusing the FPN top-down and lateral features. Can be either "sum" or "avg" cfg.TEACHER.MODEL.FPN.FUSE_TYPE = "sum" # ---------------------------------------------------------------------------- # # Proposal generator options # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.PROPOSAL_GENERATOR = CN() # Current proposal generators include "RPN", "RRPN" and "PrecomputedProposals" cfg.TEACHER.MODEL.PROPOSAL_GENERATOR.NAME = "RPN" # Proposal height and width both need to be greater than MIN_SIZE # (a the scale used during training or inference) cfg.TEACHER.MODEL.PROPOSAL_GENERATOR.MIN_SIZE = 0 # ---------------------------------------------------------------------------- # # Anchor generator options # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.ANCHOR_GENERATOR = CN() # The generator can be any name in the ANCHOR_GENERATOR registry cfg.TEACHER.MODEL.ANCHOR_GENERATOR.NAME = "DefaultAnchorGenerator" # Anchor sizes (i.e. sqrt of area) in absolute pixels w.r.t. the network input. # Format: list[list[float]]. SIZES[i] specifies the list of sizes to use for # IN_FEATURES[i]; len(SIZES) must be equal to len(IN_FEATURES) or 1. # When len(SIZES) == 1, SIZES[0] is used for all IN_FEATURES. cfg.TEACHER.MODEL.ANCHOR_GENERATOR.SIZES = [[32, 64, 128, 256, 512]] # Anchor aspect ratios. For each area given in `SIZES`, anchors with different aspect # ratios are generated by an anchor generator. # Format: list[list[float]]. ASPECT_RATIOS[i] specifies the list of aspect ratios (H/W) # to use for IN_FEATURES[i]; len(ASPECT_RATIOS) == len(IN_FEATURES) must be true, # or len(ASPECT_RATIOS) == 1 is true and aspect ratio list ASPECT_RATIOS[0] is used # for all IN_FEATURES. cfg.TEACHER.MODEL.ANCHOR_GENERATOR.ASPECT_RATIOS = [[0.5, 1.0, 2.0]] # Anchor angles. # list[list[float]], the angle in degrees, for each input feature map. # ANGLES[i] specifies the list of angles for IN_FEATURES[i]. cfg.TEACHER.MODEL.ANCHOR_GENERATOR.ANGLES = [[-90, 0, 90]] # Relative offset between the center of the first anchor and the top-left corner of the image # Value has to be in [0, 1). Recommend to use 0.5, which means half stride. # The value is not expected to affect model accuracy. cfg.TEACHER.MODEL.ANCHOR_GENERATOR.OFFSET = 0.0 # ---------------------------------------------------------------------------- # # RPN options # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.RPN = CN() cfg.TEACHER.MODEL.RPN.HEAD_NAME = "StandardRPNHead" # used by RPN_HEAD_REGISTRY # Names of the input feature maps to be used by RPN # e.g., ["p2", "p3", "p4", "p5", "p6"] for FPN cfg.TEACHER.MODEL.RPN.IN_FEATURES = ["res4"] # Remove RPN anchors that go outside the image by BOUNDARY_THRESH pixels # Set to -1 or a large value, e.g. 100000, to disable pruning anchors cfg.TEACHER.MODEL.RPN.BOUNDARY_THRESH = -1 # IOU overlap ratios [BG_IOU_THRESHOLD, FG_IOU_THRESHOLD] # Minimum overlap required between an anchor and ground-truth box for the # (anchor, gt box) pair to be a positive example (IoU >= FG_IOU_THRESHOLD # ==> positive RPN example: 1) # Maximum overlap allowed between an anchor and ground-truth box for the # (anchor, gt box) pair to be a negative examples (IoU < BG_IOU_THRESHOLD # ==> negative RPN example: 0) # Anchors with overlap in between (BG_IOU_THRESHOLD <= IoU < FG_IOU_THRESHOLD) # are ignored (-1) cfg.TEACHER.MODEL.RPN.IOU_THRESHOLDS = [0.3, 0.7] cfg.TEACHER.MODEL.RPN.IOU_LABELS = [0, -1, 1] # Number of regions per image used to train RPN cfg.TEACHER.MODEL.RPN.BATCH_SIZE_PER_IMAGE = 256 # Target fraction of foreground (positive) examples per RPN minibatch cfg.TEACHER.MODEL.RPN.POSITIVE_FRACTION = 0.5 # Options are: "smooth_l1", "giou" cfg.TEACHER.MODEL.RPN.BBOX_REG_LOSS_TYPE = "smooth_l1" cfg.TEACHER.MODEL.RPN.BBOX_REG_LOSS_WEIGHT = 1.0 # Weights on (dx, dy, dw, dh) for normalizing RPN anchor regression targets cfg.TEACHER.MODEL.RPN.BBOX_REG_WEIGHTS = (1.0, 1.0, 1.0, 1.0) # The transition point from L1 to L2 loss. Set to 0.0 to make the loss simply L1. cfg.TEACHER.MODEL.RPN.SMOOTH_L1_BETA = 0.0 cfg.TEACHER.MODEL.RPN.LOSS_WEIGHT = 1.0 # Number of top scoring RPN proposals to keep before applying NMS # When FPN is used, this is *per FPN level* (not total) cfg.TEACHER.MODEL.RPN.PRE_NMS_TOPK_TRAIN = 12000 cfg.TEACHER.MODEL.RPN.PRE_NMS_TOPK_TEST = 6000 # Number of top scoring RPN proposals to keep after applying NMS # When FPN is used, this limit is applied per level and then again to the union # of proposals from all levels # NOTE: When FPN is used, the meaning of this config is different from Detectron1. # It means per-batch topk in Detectron1, but per-image topk here. # See the "find_top_rpn_proposals" function for details. cfg.TEACHER.MODEL.RPN.POST_NMS_TOPK_TRAIN = 2000 cfg.TEACHER.MODEL.RPN.POST_NMS_TOPK_TEST = 1000 # NMS threshold used on RPN proposals cfg.TEACHER.MODEL.RPN.NMS_THRESH = 0.7 # Set this to -1 to use the same number of output channels as input channels. cfg.TEACHER.MODEL.RPN.CONV_DIMS = [-1] # ---------------------------------------------------------------------------- # # ROI HEADS options # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.ROI_HEADS = CN() cfg.TEACHER.MODEL.ROI_HEADS.NAME = "Res5ROIHeads" # Number of foreground classes cfg.TEACHER.MODEL.ROI_HEADS.NUM_CLASSES = 80 # Names of the input feature maps to be used by ROI heads # Currently all heads (box, mask, ...) use the same input feature map list # e.g., ["p2", "p3", "p4", "p5"] is commonly used for FPN cfg.TEACHER.MODEL.ROI_HEADS.IN_FEATURES = ["res4"] # IOU overlap ratios [IOU_THRESHOLD] # Overlap threshold for an RoI to be considered background (if < IOU_THRESHOLD) # Overlap threshold for an RoI to be considered foreground (if >= IOU_THRESHOLD) cfg.TEACHER.MODEL.ROI_HEADS.IOU_THRESHOLDS = [0.5] cfg.TEACHER.MODEL.ROI_HEADS.IOU_LABELS = [0, 1] # RoI minibatch size *per image* (number of regions of interest [ROIs]) # Total number of RoIs per training minibatch = # ROI_HEADS.BATCH_SIZE_PER_IMAGE * SOLVER.IMS_PER_BATCH # E.g., a common configuration is: 512 * 16 = 8192 cfg.TEACHER.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 512 # Target fraction of RoI minibatch that is labeled foreground (i.e. class > 0) cfg.TEACHER.MODEL.ROI_HEADS.POSITIVE_FRACTION = 0.25 # Only used on test mode # Minimum score threshold (assuming scores in a [0, 1] range); a value chosen to # balance obtaining high recall with not having too many low precision # detections that will slow down inference post processing steps (like NMS) # A default threshold of 0.0 increases AP by ~0.2-0.3 but significantly slows down # inference. cfg.TEACHER.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.05 # Overlap threshold used for non-maximum suppression (suppress boxes with # IoU >= this threshold) cfg.TEACHER.MODEL.ROI_HEADS.NMS_THRESH_TEST = 0.5 # If True, augment proposals with ground-truth boxes before sampling proposals to # train ROI heads. cfg.TEACHER.MODEL.ROI_HEADS.PROPOSAL_APPEND_GT = True # ---------------------------------------------------------------------------- # # Box Head # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.ROI_BOX_HEAD = CN() # C4 don't use head name option # Options for non-C4 models: FastRCNNConvFCHead, cfg.TEACHER.MODEL.ROI_BOX_HEAD.NAME = "" # Options are: "smooth_l1", "giou" cfg.TEACHER.MODEL.ROI_BOX_HEAD.BBOX_REG_LOSS_TYPE = "smooth_l1" # The final scaling coefficient on the box regression loss, used to balance the magnitude of its # gradients with other losses in the model. See also `MODEL.ROI_KEYPOINT_HEAD.LOSS_WEIGHT`. cfg.TEACHER.MODEL.ROI_BOX_HEAD.BBOX_REG_LOSS_WEIGHT = 1.0 # Default weights on (dx, dy, dw, dh) for normalizing bbox regression targets # These are empirically chosen to approximately lead to unit variance targets cfg.TEACHER.MODEL.ROI_BOX_HEAD.BBOX_REG_WEIGHTS = (10.0, 10.0, 5.0, 5.0) # The transition point from L1 to L2 loss. Set to 0.0 to make the loss simply L1. cfg.TEACHER.MODEL.ROI_BOX_HEAD.SMOOTH_L1_BETA = 0.0 cfg.TEACHER.MODEL.ROI_BOX_HEAD.POOLER_RESOLUTION = 14 cfg.TEACHER.MODEL.ROI_BOX_HEAD.POOLER_SAMPLING_RATIO = 0 # Type of pooling operation applied to the incoming feature map for each RoI cfg.TEACHER.MODEL.ROI_BOX_HEAD.POOLER_TYPE = "ROIAlignV2" cfg.TEACHER.MODEL.ROI_BOX_HEAD.NUM_FC = 0 # Hidden layer dimension for FC layers in the RoI box head cfg.TEACHER.MODEL.ROI_BOX_HEAD.FC_DIM = 1024 cfg.TEACHER.MODEL.ROI_BOX_HEAD.NUM_CONV = 0 # Channel dimension for Conv layers in the RoI box head cfg.TEACHER.MODEL.ROI_BOX_HEAD.CONV_DIM = 256 # Normalization method for the convolution layers. # Options: "" (no norm), "GN", "SyncBN". cfg.TEACHER.MODEL.ROI_BOX_HEAD.NORM = "" # Whether to use class agnostic for bbox regression cfg.TEACHER.MODEL.ROI_BOX_HEAD.CLS_AGNOSTIC_BBOX_REG = False # If true, RoI heads use bounding boxes predicted by the box head rather than proposal boxes. cfg.TEACHER.MODEL.ROI_BOX_HEAD.TRAIN_ON_PRED_BOXES = False # ---------------------------------------------------------------------------- # # Cascaded Box Head # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.ROI_BOX_CASCADE_HEAD = CN() # The number of cascade stages is implicitly defined by the length of the following two configs. cfg.TEACHER.MODEL.ROI_BOX_CASCADE_HEAD.BBOX_REG_WEIGHTS = ( (10.0, 10.0, 5.0, 5.0), (20.0, 20.0, 10.0, 10.0), (30.0, 30.0, 15.0, 15.0), ) cfg.TEACHER.MODEL.ROI_BOX_CASCADE_HEAD.IOUS = (0.5, 0.6, 0.7) # ---------------------------------------------------------------------------- # # Mask Head # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.ROI_MASK_HEAD = CN() cfg.TEACHER.MODEL.ROI_MASK_HEAD.NAME = "MaskRCNNConvUpsampleHead" cfg.TEACHER.MODEL.ROI_MASK_HEAD.POOLER_RESOLUTION = 14 cfg.TEACHER.MODEL.ROI_MASK_HEAD.POOLER_SAMPLING_RATIO = 0 cfg.TEACHER.MODEL.ROI_MASK_HEAD.NUM_CONV = 0 # The number of convs in the mask head cfg.TEACHER.MODEL.ROI_MASK_HEAD.CONV_DIM = 256 # Normalization method for the convolution layers. # Options: "" (no norm), "GN", "SyncBN". cfg.TEACHER.MODEL.ROI_MASK_HEAD.NORM = "" # Whether to use class agnostic for mask prediction cfg.TEACHER.MODEL.ROI_MASK_HEAD.CLS_AGNOSTIC_MASK = False # Type of pooling operation applied to the incoming feature map for each RoI cfg.TEACHER.MODEL.ROI_MASK_HEAD.POOLER_TYPE = "ROIAlignV2" # ---------------------------------------------------------------------------- # # Keypoint Head # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.ROI_KEYPOINT_HEAD = CN() cfg.TEACHER.MODEL.ROI_KEYPOINT_HEAD.NAME = "KRCNNConvDeconvUpsampleHead" cfg.TEACHER.MODEL.ROI_KEYPOINT_HEAD.POOLER_RESOLUTION = 14 cfg.TEACHER.MODEL.ROI_KEYPOINT_HEAD.POOLER_SAMPLING_RATIO = 0 cfg.TEACHER.MODEL.ROI_KEYPOINT_HEAD.CONV_DIMS = tuple(512 for _ in range(8)) cfg.TEACHER.MODEL.ROI_KEYPOINT_HEAD.NUM_KEYPOINTS = 17 # 17 is the number of keypoints in COCO. # Images with too few (or no) keypoints are excluded from training. cfg.TEACHER.MODEL.ROI_KEYPOINT_HEAD.MIN_KEYPOINTS_PER_IMAGE = 1 # Normalize by the total number of visible keypoints in the minibatch if True. # Otherwise, normalize by the total number of keypoints that could ever exist # in the minibatch. # The keypoint softmax loss is only calculated on visible keypoints. # Since the number of visible keypoints can vary significantly between # minibatches, this has the effect of up-weighting the importance of # minibatches with few visible keypoints. (Imagine the extreme case of # only one visible keypoint versus N: in the case of N, each one # contributes 1/N to the gradient compared to the single keypoint # determining the gradient direction). Instead, we can normalize the # loss by the total number of keypoints, if it were the case that all # keypoints were visible in a full minibatch. (Returning to the example, # this means that the one visible keypoint contributes as much as each # of the N keypoints.) cfg.TEACHER.MODEL.ROI_KEYPOINT_HEAD.NORMALIZE_LOSS_BY_VISIBLE_KEYPOINTS = True # Multi-task loss weight to use for keypoints # Recommended values: # - use 1.0 if NORMALIZE_LOSS_BY_VISIBLE_KEYPOINTS is True # - use 4.0 if NORMALIZE_LOSS_BY_VISIBLE_KEYPOINTS is False cfg.TEACHER.MODEL.ROI_KEYPOINT_HEAD.LOSS_WEIGHT = 1.0 # Type of pooling operation applied to the incoming feature map for each RoI cfg.TEACHER.MODEL.ROI_KEYPOINT_HEAD.POOLER_TYPE = "ROIAlignV2" # ---------------------------------------------------------------------------- # # Semantic Segmentation Head # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.SEM_SEG_HEAD = CN() cfg.TEACHER.MODEL.SEM_SEG_HEAD.NAME = "SemSegFPNHead" cfg.TEACHER.MODEL.SEM_SEG_HEAD.IN_FEATURES = ["p2", "p3", "p4", "p5"] # Label in the semantic segmentation ground truth that is ignored, i.e., no loss is calculated for # the correposnding pixel. cfg.TEACHER.MODEL.SEM_SEG_HEAD.IGNORE_VALUE = 255 # Number of classes in the semantic segmentation head cfg.TEACHER.MODEL.SEM_SEG_HEAD.NUM_CLASSES = 54 # Number of channels in the 3x3 convs inside semantic-FPN heads. cfg.TEACHER.MODEL.SEM_SEG_HEAD.CONVS_DIM = 128 # Outputs from semantic-FPN heads are up-scaled to the COMMON_STRIDE stride. cfg.TEACHER.MODEL.SEM_SEG_HEAD.COMMON_STRIDE = 4 # Normalization method for the convolution layers. Options: "" (no norm), "GN". cfg.TEACHER.MODEL.SEM_SEG_HEAD.NORM = "GN" cfg.TEACHER.MODEL.SEM_SEG_HEAD.LOSS_WEIGHT = 1.0 cfg.TEACHER.MODEL.PANOPTIC_FPN = CN() # Scaling of all losses from instance detection / segmentation head. cfg.TEACHER.MODEL.PANOPTIC_FPN.INSTANCE_LOSS_WEIGHT = 1.0 # options when combining instance & semantic segmentation outputs cfg.TEACHER.MODEL.PANOPTIC_FPN.COMBINE = CN({"ENABLED": True}) # "COMBINE.ENABLED" is deprecated & not used cfg.TEACHER.MODEL.PANOPTIC_FPN.COMBINE.OVERLAP_THRESH = 0.5 cfg.TEACHER.MODEL.PANOPTIC_FPN.COMBINE.STUFF_AREA_LIMIT = 4096 cfg.TEACHER.MODEL.PANOPTIC_FPN.COMBINE.INSTANCES_CONFIDENCE_THRESH = 0.5 # ---------------------------------------------------------------------------- # # RetinaNet Head # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.RETINANET = CN() # This is the number of foreground classes. cfg.TEACHER.MODEL.RETINANET.NUM_CLASSES = 80 cfg.TEACHER.MODEL.RETINANET.IN_FEATURES = ["p3", "p4", "p5", "p6", "p7"] # Convolutions to use in the cls and bbox tower # NOTE: this doesn't include the last conv for logits cfg.TEACHER.MODEL.RETINANET.NUM_CONVS = 4 # IoU overlap ratio [bg, fg] for labeling anchors. # Anchors with < bg are labeled negative (0) # Anchors with >= bg and < fg are ignored (-1) # Anchors with >= fg are labeled positive (1) cfg.TEACHER.MODEL.RETINANET.IOU_THRESHOLDS = [0.4, 0.5] cfg.TEACHER.MODEL.RETINANET.IOU_LABELS = [0, -1, 1] # Prior prob for rare case (i.e. foreground) at the beginning of training. # This is used to set the bias for the logits layer of the classifier subnet. # This improves training stability in the case of heavy class imbalance. cfg.TEACHER.MODEL.RETINANET.PRIOR_PROB = 0.01 # Inference cls score threshold, only anchors with score > INFERENCE_TH are # considered for inference (to improve speed) cfg.TEACHER.MODEL.RETINANET.SCORE_THRESH_TEST = 0.05 # Select topk candidates before NMS cfg.TEACHER.MODEL.RETINANET.TOPK_CANDIDATES_TEST = 1000 cfg.TEACHER.MODEL.RETINANET.NMS_THRESH_TEST = 0.5 # Weights on (dx, dy, dw, dh) for normalizing Retinanet anchor regression targets cfg.TEACHER.MODEL.RETINANET.BBOX_REG_WEIGHTS = (1.0, 1.0, 1.0, 1.0) # Loss parameters cfg.TEACHER.MODEL.RETINANET.FOCAL_LOSS_GAMMA = 2.0 cfg.TEACHER.MODEL.RETINANET.FOCAL_LOSS_ALPHA = 0.25 cfg.TEACHER.MODEL.RETINANET.SMOOTH_L1_LOSS_BETA = 0.1 # Options are: "smooth_l1", "giou" cfg.TEACHER.MODEL.RETINANET.BBOX_REG_LOSS_TYPE = "smooth_l1" # One of BN, SyncBN, FrozenBN, GN # Only supports GN until unshared norm is implemented cfg.TEACHER.MODEL.RETINANET.NORM = "" # ---------------------------------------------------------------------------- # # ResNe[X]t options (ResNets = {ResNet, ResNeXt} # Note that parts of a resnet may be used for both the backbone and the head # These options apply to both # ---------------------------------------------------------------------------- # cfg.TEACHER.MODEL.RESNETS = CN() cfg.TEACHER.MODEL.RESNETS.DEPTH = 50 cfg.TEACHER.MODEL.RESNETS.OUT_FEATURES = ["res4"] # res4 for C4 backbone, res2..5 for FPN backbone # Number of groups to use; 1 ==> ResNet; > 1 ==> ResNeXt cfg.TEACHER.MODEL.RESNETS.NUM_GROUPS = 1 # Options: FrozenBN, GN, "SyncBN", "BN" cfg.TEACHER.MODEL.RESNETS.NORM = "FrozenBN" # Baseline width of each group. # Scaling this parameters will scale the width of all bottleneck layers. cfg.TEACHER.MODEL.RESNETS.WIDTH_PER_GROUP = 64 # Place the stride 2 conv on the 1x1 filter # Use True only for the original MSRA ResNet; use False for C2 and Torch models cfg.TEACHER.MODEL.RESNETS.STRIDE_IN_1X1 = True # Apply dilation in stage "res5" cfg.TEACHER.MODEL.RESNETS.RES5_DILATION = 1 # Output width of res2. Scaling this parameters will scale the width of all 1x1 convs in ResNet # For R18 and R34, this needs to be set to 64 cfg.TEACHER.MODEL.RESNETS.RES2_OUT_CHANNELS = 256 cfg.TEACHER.MODEL.RESNETS.STEM_OUT_CHANNELS = 64 # Apply Deformable Convolution in stages # Specify if apply deform_conv on Res2, Res3, Res4, Res5 cfg.TEACHER.MODEL.RESNETS.DEFORM_ON_PER_STAGE = [False, False, False, False] # Use True to use modulated deform_conv (DeformableV2, https://arxiv.org/abs/1811.11168); # Use False for DeformableV1. cfg.TEACHER.MODEL.RESNETS.DEFORM_MODULATED = False # Number of groups in deformable conv. cfg.TEACHER.MODEL.RESNETS.DEFORM_NUM_GROUPS = 1 # ---------------------------------------------------------------------------- # # Solver # ---------------------------------------------------------------------------- # cfg.TEACHER.SOLVER = CN() # See detectron2/solver/build.py for LR scheduler options cfg.TEACHER.SOLVER.LR_SCHEDULER_NAME = "WarmupMultiStepLR" cfg.TEACHER.SOLVER.MAX_ITER = 40000 cfg.TEACHER.SOLVER.BASE_LR = 0.001 cfg.TEACHER.SOLVER.MOMENTUM = 0.9 cfg.TEACHER.SOLVER.NESTEROV = False cfg.TEACHER.SOLVER.WEIGHT_DECAY = 0.0001 # The weight decay that's applied to parameters of normalization layers # (typically the affine transformation) cfg.TEACHER.SOLVER.WEIGHT_DECAY_NORM = 0.0 cfg.TEACHER.SOLVER.GAMMA = 0.1 # The iteration number to decrease learning rate by GAMMA. cfg.TEACHER.SOLVER.STEPS = (30000,) cfg.TEACHER.SOLVER.WARMUP_FACTOR = 1.0 / 1000 cfg.TEACHER.SOLVER.WARMUP_ITERS = 1000 cfg.TEACHER.SOLVER.WARMUP_METHOD = "linear" # Save a checkpoint after every this number of iterations cfg.TEACHER.SOLVER.CHECKPOINT_PERIOD = 5000 # Number of images per batch across all machines. This is also the number # of training images per step (i.e. per iteration). If we use 16 GPUs # and IMS_PER_BATCH = 32, each GPU will see 2 images per batch. # May be adjusted automatically if REFERENCE_WORLD_SIZE is set. cfg.TEACHER.SOLVER.IMS_PER_BATCH = 16 # The reference number of workers (GPUs) this config is meant to train with. # It takes no effect when set to 0. # With a non-zero value, it will be used by DefaultTrainer to compute a desired # per-worker batch size, and then scale the other related configs (total batch size, # learning rate, etc) to match the per-worker batch size. # See documentation of `DefaultTrainer.auto_scale_workers` for details: cfg.TEACHER.SOLVER.REFERENCE_WORLD_SIZE = 0 # Detectron v1 (and previous detection code) used a 2x higher LR and 0 WD for # biases. This is not useful (at least for recent models). You should avoid # changing these and they exist only to reproduce Detectron v1 training if # desired. cfg.TEACHER.SOLVER.BIAS_LR_FACTOR = 1.0 cfg.TEACHER.SOLVER.WEIGHT_DECAY_BIAS = cfg.TEACHER.SOLVER.WEIGHT_DECAY # Gradient clipping cfg.TEACHER.SOLVER.CLIP_GRADIENTS = CN({"ENABLED": False}) # Type of gradient clipping, currently 2 values are supported: # - "value": the absolute values of elements of each gradients are clipped # - "norm": the norm of the gradient for each parameter is clipped thus # affecting all elements in the parameter cfg.TEACHER.SOLVER.CLIP_GRADIENTS.CLIP_TYPE = "value" # Maximum absolute value used for clipping gradients cfg.TEACHER.SOLVER.CLIP_GRADIENTS.CLIP_VALUE = 1.0 # Floating point number p for L-p norm to be used with the "norm" # gradient clipping type; for L-inf, please specify .inf cfg.TEACHER.SOLVER.CLIP_GRADIENTS.NORM_TYPE = 2.0 # Enable automatic mixed precision for training # Note that this does not change model's inference behavior. # To use AMP in inference, run inference under autocast() cfg.TEACHER.SOLVER.AMP = CN({"ENABLED": False}) # ---------------------------------------------------------------------------- # # Specific test options # ---------------------------------------------------------------------------- # cfg.TEACHER.TEST = CN() # For end-to-end tests to verify the expected accuracy. # Each item is [task, metric, value, tolerance] # e.g.: [['bbox', 'AP', 38.5, 0.2]] cfg.TEACHER.TEST.EXPECTED_RESULTS = [] # The period (in terms of steps) to evaluate the model during training. # Set to 0 to disable. cfg.TEACHER.TEST.EVAL_PERIOD = 0 # The sigmas used to calculate keypoint OKS. See http://cocodataset.org/#keypoints-eval # When empty, it will use the defaults in COCO. # Otherwise it should be a list[float] with the same length as ROI_KEYPOINT_HEAD.NUM_KEYPOINTS. cfg.TEACHER.TEST.KEYPOINT_OKS_SIGMAS = [] # Maximum number of detections to return per image during inference (100 is # based on the limit established for the COCO dataset). cfg.TEACHER.TEST.DETECTIONS_PER_IMAGE = 100 cfg.TEACHER.TEST.AUG = CN({"ENABLED": False}) cfg.TEACHER.TEST.AUG.MIN_SIZES = (400, 500, 600, 700, 800, 900, 1000, 1100, 1200) cfg.TEACHER.TEST.AUG.MAX_SIZE = 4000 cfg.TEACHER.TEST.AUG.FLIP = True cfg.TEACHER.TEST.PRECISE_BN = CN({"ENABLED": False}) cfg.TEACHER.TEST.PRECISE_BN.NUM_ITER = 200 # ---------------------------------------------------------------------------- # # Misc options # ---------------------------------------------------------------------------- # # Directory where output files are written cfg.TEACHER.OUTPUT_DIR = "./output" # Set seed to negative to fully randomize everything. # Set seed to positive to use a fixed seed. Note that a fixed seed increases # reproducibility but does not guarantee fully deterministic behavior. # Disabling all parallelism further increases reproducibility. cfg.TEACHER.SEED = -1 # Benchmark different cudnn algorithms. # If input images have very different sizes, this option will have large overhead # for about 10k iterations. It usually hurts total time, but can benefit for certain models. # If input images have the same or similar sizes, benchmark is often helpful. cfg.TEACHER.CUDNN_BENCHMARK = False # The period (in terms of steps) for minibatch visualization at train time. # Set to 0 to disable. cfg.TEACHER.VIS_PERIOD = 0 # global config is for quick hack purposes. # You can set them in command line or config files, # and access it with: # # from detectron2.config import global_cfg # print(global_cfg.HACK) # # Do not commit any configs into it. cfg.TEACHER.GLOBAL = CN() cfg.TEACHER.GLOBAL.HACK = 1.0 ================================================ FILE: detection/model/rcnn.py ================================================ # Copyright (c) Facebook, Inc. and its affiliates. import logging import numpy as np from typing import Dict, List, Optional, Tuple import torch from torch import nn from detectron2.config import configurable from detectron2.data.detection_utils import convert_image_to_rgb from detectron2.structures import ImageList, Instances from detectron2.utils.events import get_event_storage from detectron2.utils.logger import log_first_n from detectron2.modeling.backbone import Backbone, build_backbone from detectron2.modeling.postprocessing import detector_postprocess from detectron2.modeling.proposal_generator import build_proposal_generator from detectron2.modeling.roi_heads import build_roi_heads from detectron2.modeling.meta_arch.build import META_ARCH_REGISTRY from mdistiller.distillers.DKD import dkd_loss from .teacher import build_teacher from .reviewkd import build_kd_trans, hcl __all__ = ["RCNNKD", "ProposalNetwork"] def rcnn_dkd_loss(stu_predictions, tea_predictions, gt_classes, alpha, beta, temperature): stu_logits, stu_bbox_offsets = stu_predictions tea_logits, tea_bbox_offsets = tea_predictions gt_classes = torch.cat(tuple(gt_classes), 0).reshape(-1) loss_dkd = dkd_loss(stu_logits, tea_logits, gt_classes, alpha, beta, temperature) return { 'loss_dkd': loss_dkd, } @META_ARCH_REGISTRY.register() class RCNNKD(nn.Module): """ Generalized R-CNN. Any models that contains the following three components: 1. Per-image feature extraction (aka backbone) 2. Region proposal generation 3. Per-region feature extraction and prediction """ @configurable def __init__( self, *, backbone: Backbone, proposal_generator: nn.Module, roi_heads: nn.Module, pixel_mean: Tuple[float], pixel_std: Tuple[float], teacher_pixel_mean: Tuple[float], teacher_pixel_std: Tuple[float], teacher: nn.Module, kd_args, input_format: Optional[str] = None, teacher_input_format: Optional[str] = None, vis_period: int = 0, ): """ Args: backbone: a backbone module, must follow detectron2's backbone interface proposal_generator: a module that generates proposals using backbone features roi_heads: a ROI head that performs per-region computation pixel_mean, pixel_std: list or tuple with #channels element, representing the per-channel mean and std to be used to normalize the input image input_format: describe the meaning of channels of input. Needed by visualization vis_period: the period to run visualization. Set to 0 to disable. """ super().__init__() self.backbone = backbone self.proposal_generator = proposal_generator self.roi_heads = roi_heads self.teacher = teacher self.kd_args = kd_args if self.kd_args.TYPE in ("ReviewKD", "ReviewDKD"): self.kd_trans = build_kd_trans(self.kd_args) self.input_format = input_format self.teacher_input_format = teacher_input_format self.vis_period = vis_period if vis_period > 0: assert input_format is not None, "input_format is required for visualization!" self.register_buffer("pixel_mean", torch.tensor(pixel_mean).view(-1, 1, 1), False) self.register_buffer("pixel_std", torch.tensor(pixel_std).view(-1, 1, 1), False) self.register_buffer("teacher_pixel_mean", torch.tensor(teacher_pixel_mean).view(-1, 1, 1), False) self.register_buffer("teacher_pixel_std", torch.tensor(teacher_pixel_std).view(-1, 1, 1), False) assert ( self.pixel_mean.shape == self.pixel_std.shape ), f"{self.pixel_mean} and {self.pixel_std} have different shapes!" @classmethod def from_config(cls, cfg): backbone = build_backbone(cfg) return { "backbone": backbone, "proposal_generator": build_proposal_generator(cfg, backbone.output_shape()), "roi_heads": build_roi_heads(cfg, backbone.output_shape()), "input_format": cfg.INPUT.FORMAT, "vis_period": cfg.VIS_PERIOD, "pixel_mean": cfg.MODEL.PIXEL_MEAN, "pixel_std": cfg.MODEL.PIXEL_STD, "kd_args": cfg.KD, "teacher": build_teacher(cfg), "teacher_input_format": cfg.TEACHER.INPUT.FORMAT, "teacher_pixel_mean": cfg.TEACHER.MODEL.PIXEL_MEAN, "teacher_pixel_std": cfg.TEACHER.MODEL.PIXEL_STD, } @property def device(self): return self.pixel_mean.device def visualize_training(self, batched_inputs, proposals): """ A function used to visualize images and proposals. It shows ground truth bounding boxes on the original image and up to 20 top-scoring predicted object proposals on the original image. Users can implement different visualization functions for different models. Args: batched_inputs (list): a list that contains input to the model. proposals (list): a list that contains predicted proposals. Both batched_inputs and proposals should have the same length. """ from detectron2.utils.visualizer import Visualizer storage = get_event_storage() max_vis_prop = 20 for input, prop in zip(batched_inputs, proposals): img = input["image"] img = convert_image_to_rgb(img.permute(1, 2, 0), self.input_format) v_gt = Visualizer(img, None) v_gt = v_gt.overlay_instances(boxes=input["instances"].gt_boxes) anno_img = v_gt.get_image() box_size = min(len(prop.proposal_boxes), max_vis_prop) v_pred = Visualizer(img, None) v_pred = v_pred.overlay_instances( boxes=prop.proposal_boxes[0:box_size].tensor.cpu().numpy() ) prop_img = v_pred.get_image() vis_img = np.concatenate((anno_img, prop_img), axis=1) vis_img = vis_img.transpose(2, 0, 1) vis_name = "Left: GT bounding boxes; Right: Predicted proposals" storage.put_image(vis_name, vis_img) break # only visualize one image in a batch def forward_pure_roi_head(self, roi_head, features, proposals): features = [features[f] for f in roi_head.box_in_features] box_features = roi_head.box_pooler(features, [x.proposal_boxes for x in proposals]) box_features = roi_head.box_head(box_features) predictions = roi_head.box_predictor(box_features) return predictions def forward(self, batched_inputs: Tuple[Dict[str, torch.Tensor]]): """ Args: batched_inputs: a list, batched outputs of :class:`DatasetMapper` . Each item in the list contains the inputs for one image. For now, each item in the list is a dict that contains: * image: Tensor, image in (C, H, W) format. * instances (optional): groundtruth :class:`Instances` * proposals (optional): :class:`Instances`, precomputed proposals. Other information that's included in the original dicts, such as: * "height", "width" (int): the output resolution of the model, used in inference. See :meth:`postprocess` for details. Returns: list[dict]: Each dict is the output for one input image. The dict contains one key "instances" whose value is a :class:`Instances`. The :class:`Instances` object has the following keys: "pred_boxes", "pred_classes", "scores", "pred_masks", "pred_keypoints" """ if not self.training: return self.inference(batched_inputs) images = self.preprocess_image(batched_inputs) if "instances" in batched_inputs[0]: gt_instances = [x["instances"].to(self.device) for x in batched_inputs] else: gt_instances = None features = self.backbone(images.tensor) losses = {} if self.proposal_generator is not None: proposals, proposal_losses = self.proposal_generator(images, features, gt_instances) else: assert "proposals" in batched_inputs[0] proposals = [x["proposals"].to(self.device) for x in batched_inputs] proposal_losses = {} sampled_proposals, detector_losses = self.roi_heads(images, features, proposals, gt_instances) if self.kd_args.TYPE == "DKD": teacher_images = self.teacher_preprocess_image(batched_inputs) t_features = self.teacher.backbone(teacher_images.tensor) stu_predictions = self.forward_pure_roi_head(self.roi_heads, features, sampled_proposals) tea_predictions = self.forward_pure_roi_head(self.teacher.roi_heads, t_features, sampled_proposals) detector_losses.update(rcnn_dkd_loss( stu_predictions, tea_predictions, [x.gt_classes for x in sampled_proposals], self.kd_args.DKD.ALPHA, self.kd_args.DKD.BETA, self.kd_args.DKD.T)) elif self.kd_args.TYPE == "ReviewKD": teacher_images = self.teacher_preprocess_image(batched_inputs) t_features = self.teacher.backbone(teacher_images.tensor) t_features = [t_features[f] for f in t_features] s_features = [features[f] for f in features] s_features = self.kd_trans(s_features) losses['loss_reviewkd'] = hcl(s_features, t_features) * self.kd_args.REVIEWKD.LOSS_WEIGHT elif self.kd_args.TYPE == "ReviewDKD": teacher_images = self.teacher_preprocess_image(batched_inputs) t_features = self.teacher.backbone(teacher_images.tensor) # dkd loss stu_predictions = self.forward_pure_roi_head(self.roi_heads, features, sampled_proposals) tea_predictions = self.forward_pure_roi_head(self.teacher.roi_heads, t_features, sampled_proposals) detector_losses.update(rcnn_dkd_loss( stu_predictions, tea_predictions, [x.gt_classes for x in sampled_proposals], self.kd_args.DKD.ALPHA, self.kd_args.DKD.BETA, self.kd_args.DKD.T)) # reviewkd loss t_features = [t_features[f] for f in t_features] s_features = [features[f] for f in features] s_features = self.kd_trans(s_features) losses['loss_reviewkd'] = hcl(s_features, t_features) * self.kd_args.REVIEWKD.LOSS_WEIGHT else: raise NotImplementedError(self.kd_args.TYPE) if self.vis_period > 0: storage = get_event_storage() if storage.iter % self.vis_period == 0: self.visualize_training(batched_inputs, proposals) losses.update(detector_losses) losses.update(proposal_losses) return losses def inference( self, batched_inputs: Tuple[Dict[str, torch.Tensor]], detected_instances: Optional[List[Instances]] = None, do_postprocess: bool = True, ): """ Run inference on the given inputs. Args: batched_inputs (list[dict]): same as in :meth:`forward` detected_instances (None or list[Instances]): if not None, it contains an `Instances` object per image. The `Instances` object contains "pred_boxes" and "pred_classes" which are known boxes in the image. The inference will then skip the detection of bounding boxes, and only predict other per-ROI outputs. do_postprocess (bool): whether to apply post-processing on the outputs. Returns: When do_postprocess=True, same as in :meth:`forward`. Otherwise, a list[Instances] containing raw network outputs. """ assert not self.training images = self.preprocess_image(batched_inputs) features = self.backbone(images.tensor) if detected_instances is None: if self.proposal_generator is not None: proposals, _ = self.proposal_generator(images, features, None) else: assert "proposals" in batched_inputs[0] proposals = [x["proposals"].to(self.device) for x in batched_inputs] results, _ = self.roi_heads(images, features, proposals, None) else: detected_instances = [x.to(self.device) for x in detected_instances] results = self.roi_heads.forward_with_given_boxes(features, detected_instances) if do_postprocess: assert not torch.jit.is_scripting(), "Scripting is not supported for postprocess." return RCNNKD._postprocess(results, batched_inputs, images.image_sizes) else: return results def preprocess_image(self, batched_inputs: Tuple[Dict[str, torch.Tensor]]): """ Normalize, pad and batch the input images. """ images = [x["image"].to(self.device) for x in batched_inputs] images = [(x - self.pixel_mean) / self.pixel_std for x in images] images = ImageList.from_tensors(images, self.backbone.size_divisibility) return images def teacher_preprocess_image(self, batched_inputs: Tuple[Dict[str, torch.Tensor]]): """ Normalize, pad and batch the input images. """ images = [x["image"].to(self.device) for x in batched_inputs] images = [(x - self.teacher_pixel_mean) / self.teacher_pixel_std for x in images] if self.input_format != self.teacher_input_format: images = [x.index_select(0,torch.LongTensor([2,1,0]).to(self.device)) for x in images] images = ImageList.from_tensors(images, self.backbone.size_divisibility) return images @staticmethod def _postprocess(instances, batched_inputs: Tuple[Dict[str, torch.Tensor]], image_sizes): """ Rescale the output instances to the target size. """ # note: private function; subject to changes processed_results = [] for results_per_image, input_per_image, image_size in zip( instances, batched_inputs, image_sizes ): height = input_per_image.get("height", image_size[0]) width = input_per_image.get("width", image_size[1]) r = detector_postprocess(results_per_image, height, width) processed_results.append({"instances": r}) return processed_results ================================================ FILE: detection/model/reviewkd.py ================================================ import torch from torch import nn import torch.nn.functional as F class ABF(nn.Module): def __init__(self, in_channel, mid_channel, out_channel, fuse): super(ABF, self).__init__() self.conv1 = nn.Sequential( nn.Conv2d(in_channel, mid_channel, kernel_size=1, bias=False), nn.BatchNorm2d(mid_channel), ) self.conv2 = nn.Sequential( nn.Conv2d(mid_channel, out_channel,kernel_size=3,stride=1,padding=1,bias=False), nn.BatchNorm2d(out_channel), ) if fuse: self.att_conv = nn.Sequential( nn.Conv2d(mid_channel*2, 2, kernel_size=1), nn.Sigmoid(), ) else: self.att_conv = None nn.init.kaiming_uniform_(self.conv1[0].weight, a=1) # pyre-ignore nn.init.kaiming_uniform_(self.conv2[0].weight, a=1) # pyre-ignore def forward(self, x, y=None, shape=None): n,_,h,w = x.shape # transform student features x = self.conv1(x) if self.att_conv is not None: # upsample residual features shape = x.shape[-2:] y = F.interpolate(y, shape, mode="nearest") # fusion z = torch.cat([x, y], dim=1) z = self.att_conv(z) x = (x * z[:,0].view(n,1,h,w) + y * z[:,1].view(n,1,h,w)) # output y = self.conv2(x) return y, x class ReviewKD(nn.Module): def __init__( self, in_channels, out_channels, mid_channel ): super(ReviewKD, self).__init__() abfs = nn.ModuleList() for idx, in_channel in enumerate(in_channels): abfs.append(ABF(in_channel, mid_channel, out_channels[idx], idx < len(in_channels)-1)) self.abfs = abfs[::-1] def forward(self, student_features): x = student_features[::-1] results = [] out_features, res_features = self.abfs[0](x[0]) results.append(out_features) for features, abf in zip(x[1:], self.abfs[1:]): out_features, res_features = abf(features, res_features) results.insert(0, out_features) return results def build_kd_trans(cfg): in_channels = [256,256,256,256,256] out_channels = [256,256,256,256,256] mid_channel = 256 model = ReviewKD(in_channels, out_channels, mid_channel) return model def hcl(fstudent, fteacher): loss_all = 0.0 for fs, ft in zip(fstudent, fteacher): n,c,h,w = fs.shape loss = F.mse_loss(fs, ft, reduction='mean') cnt = 1.0 tot = 1.0 for l in [4,2,1]: if l >=h: continue tmpfs = F.adaptive_avg_pool2d(fs, (l,l)) tmpft = F.adaptive_avg_pool2d(ft, (l,l)) cnt /= 2.0 loss += F.mse_loss(tmpfs, tmpft, reduction='mean') * cnt tot += cnt loss = loss / tot loss_all = loss_all + loss return loss_all ================================================ FILE: detection/model/teacher/__init__.py ================================================ from .teacher import build_teacher ================================================ FILE: detection/model/teacher/teacher.py ================================================ from detectron2.modeling.backbone import build_backbone from detectron2.modeling.proposal_generator import build_proposal_generator from detectron2.modeling.roi_heads import build_roi_heads from detectron2.checkpoint import DetectionCheckpointer from torch import nn class Teacher(nn.Module): def __init__(self, backbone, proposal_generator, roi_heads): super().__init__() self.backbone = backbone self.proposal_generator = proposal_generator self.roi_heads = roi_heads def build_teacher(cfg): teacher_cfg = cfg.TEACHER backbone = build_backbone(teacher_cfg) if not 'Retina' in teacher_cfg.MODEL.META_ARCHITECTURE: proposal_generator = build_proposal_generator(teacher_cfg, backbone.output_shape()) roi_heads = build_roi_heads(teacher_cfg, backbone.output_shape()) else: proposal_generator = None roi_heads = None teacher = Teacher(backbone, proposal_generator, roi_heads) for param in teacher.parameters(): param.requires_grad = False return teacher ================================================ FILE: detection/train_net.py ================================================ #!/usr/bin/env python # Copyright (c) Facebook, Inc. and its affiliates. """ A main training script. This scripts reads a given config file and runs the training or evaluation. It is an entry point that is made to train standard models in detectron2. In order to let one script support training of many models, this script contains logic that are specific to these built-in models and therefore may not be suitable for your own project. For example, your research project perhaps only needs a single "evaluator". Therefore, we recommend you to use detectron2 as an library and take this file as an example of how to use the library. You may want to write your own script with your datasets and other customizations. """ import logging import os from collections import OrderedDict import torch import detectron2.utils.comm as comm from detectron2.checkpoint import DetectionCheckpointer from detectron2.config import get_cfg from detectron2.data import MetadataCatalog from detectron2.engine import DefaultTrainer, default_argument_parser, default_setup, hooks, launch from detectron2.evaluation import ( CityscapesInstanceEvaluator, CityscapesSemSegEvaluator, COCOEvaluator, COCOPanopticEvaluator, DatasetEvaluators, LVISEvaluator, PascalVOCDetectionEvaluator, SemSegEvaluator, verify_results, ) from detectron2.modeling import GeneralizedRCNNWithTTA from model import add_distillation_cfg from model import RCNNKD class Trainer(DefaultTrainer): """ We use the "DefaultTrainer" which contains pre-defined default logic for standard training workflow. They may not work for you, especially if you are working on a new research project. In that case you can write your own training loop. You can use "tools/plain_train_net.py" as an example. """ @classmethod def build_evaluator(cls, cfg, dataset_name, output_folder=None): """ Create evaluator(s) for a given dataset. This uses the special metadata "evaluator_type" associated with each builtin dataset. For your own dataset, you can simply create an evaluator manually in your script and do not have to worry about the hacky if-else logic here. """ if output_folder is None: output_folder = os.path.join(cfg.OUTPUT_DIR, "inference") evaluator_list = [] evaluator_type = MetadataCatalog.get(dataset_name).evaluator_type if evaluator_type in ["sem_seg", "coco_panoptic_seg"]: evaluator_list.append( SemSegEvaluator( dataset_name, distributed=True, output_dir=output_folder, ) ) if evaluator_type in ["coco", "coco_panoptic_seg"]: evaluator_list.append(COCOEvaluator(dataset_name, output_dir=output_folder)) if evaluator_type == "coco_panoptic_seg": evaluator_list.append(COCOPanopticEvaluator(dataset_name, output_folder)) if evaluator_type == "cityscapes_instance": assert ( torch.cuda.device_count() >= comm.get_rank() ), "CityscapesEvaluator currently do not work with multiple machines." return CityscapesInstanceEvaluator(dataset_name) if evaluator_type == "cityscapes_sem_seg": assert ( torch.cuda.device_count() >= comm.get_rank() ), "CityscapesEvaluator currently do not work with multiple machines." return CityscapesSemSegEvaluator(dataset_name) elif evaluator_type == "pascal_voc": return PascalVOCDetectionEvaluator(dataset_name) elif evaluator_type == "lvis": return LVISEvaluator(dataset_name, output_dir=output_folder) if len(evaluator_list) == 0: raise NotImplementedError( "no Evaluator for the dataset {} with the type {}".format( dataset_name, evaluator_type ) ) elif len(evaluator_list) == 1: return evaluator_list[0] return DatasetEvaluators(evaluator_list) @classmethod def test_with_TTA(cls, cfg, model): logger = logging.getLogger("detectron2.trainer") # In the end of training, run an evaluation with TTA # Only support some R-CNN models. logger.info("Running inference with test-time augmentation ...") model = GeneralizedRCNNWithTTA(cfg, model) evaluators = [ cls.build_evaluator( cfg, name, output_folder=os.path.join(cfg.OUTPUT_DIR, "inference_TTA") ) for name in cfg.DATASETS.TEST ] res = cls.test(cfg, model, evaluators) res = OrderedDict({k + "_TTA": v for k, v in res.items()}) return res def setup(args): """ Create configs and perform basic setups. """ cfg = get_cfg() add_distillation_cfg(cfg) cfg.merge_from_file(args.config_file) cfg.merge_from_list(args.opts) cfg.freeze() default_setup(cfg, args) return cfg def main(args): cfg = setup(args) if args.eval_only: model = Trainer.build_model(cfg) DetectionCheckpointer(model, save_dir=cfg.OUTPUT_DIR).resume_or_load( cfg.MODEL.WEIGHTS, resume=args.resume ) res = Trainer.test(cfg, model) if cfg.TEST.AUG.ENABLED: res.update(Trainer.test_with_TTA(cfg, model)) if comm.is_main_process(): verify_results(cfg, res) return res """ If you'd like to do anything fancier than the standard training logic, consider writing your own training loop (see plain_train_net.py) or subclassing the trainer. """ trainer = Trainer(cfg) trainer.resume_or_load(resume=args.resume) if cfg.TEST.AUG.ENABLED: trainer.register_hooks( [hooks.EvalHook(0, lambda: trainer.test_with_TTA(cfg, trainer.model))] ) return trainer.train() if __name__ == "__main__": args = default_argument_parser().parse_args() print("Command Line Args:", args) launch( main, args.num_gpus, num_machines=args.num_machines, machine_rank=args.machine_rank, dist_url=args.dist_url, args=(args,), ) ================================================ FILE: mdistiller/__init__.py ================================================ ================================================ FILE: mdistiller/dataset/__init__.py ================================================ from .cifar100 import get_cifar100_dataloaders, get_cifar100_dataloaders_sample from .imagenet import get_imagenet_dataloaders, get_imagenet_dataloaders_sample from .tiny_imagenet import get_tinyimagenet_dataloader, get_tinyimagenet_dataloader_sample def get_dataset(cfg): if cfg.DATASET.TYPE == "cifar100": if cfg.DISTILLER.TYPE == "CRD": train_loader, val_loader, num_data = get_cifar100_dataloaders_sample( batch_size=cfg.SOLVER.BATCH_SIZE, val_batch_size=cfg.DATASET.TEST.BATCH_SIZE, num_workers=cfg.DATASET.NUM_WORKERS, k=cfg.CRD.NCE.K, mode=cfg.CRD.MODE, ) else: train_loader, val_loader, num_data = get_cifar100_dataloaders( batch_size=cfg.SOLVER.BATCH_SIZE, val_batch_size=cfg.DATASET.TEST.BATCH_SIZE, num_workers=cfg.DATASET.NUM_WORKERS, ) num_classes = 100 elif cfg.DATASET.TYPE == "imagenet": if cfg.DISTILLER.TYPE == "CRD": train_loader, val_loader, num_data = get_imagenet_dataloaders_sample( batch_size=cfg.SOLVER.BATCH_SIZE, val_batch_size=cfg.DATASET.TEST.BATCH_SIZE, num_workers=cfg.DATASET.NUM_WORKERS, k=cfg.CRD.NCE.K, ) else: train_loader, val_loader, num_data = get_imagenet_dataloaders( batch_size=cfg.SOLVER.BATCH_SIZE, val_batch_size=cfg.DATASET.TEST.BATCH_SIZE, num_workers=cfg.DATASET.NUM_WORKERS, ) num_classes = 1000 elif cfg.DATASET.TYPE == "tiny_imagenet": if cfg.DISTILLER.TYPE in ("CRD", "CRDKD"): train_loader, val_loader, num_data = get_tinyimagenet_dataloader_sample( batch_size=cfg.SOLVER.BATCH_SIZE, val_batch_size=cfg.DATASET.TEST.BATCH_SIZE, num_workers=cfg.DATASET.NUM_WORKERS, k=cfg.CRD.NCE.K, ) else: train_loader, val_loader, num_data = get_tinyimagenet_dataloader( batch_size=cfg.SOLVER.BATCH_SIZE, val_batch_size=cfg.DATASET.TEST.BATCH_SIZE, num_workers=cfg.DATASET.NUM_WORKERS, ) num_classes = 200 else: raise NotImplementedError(cfg.DATASET.TYPE) return train_loader, val_loader, num_data, num_classes ================================================ FILE: mdistiller/dataset/cifar100.py ================================================ import os import numpy as np from torch.utils.data import DataLoader from torchvision import datasets, transforms from PIL import Image def get_data_folder(): data_folder = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../data") if not os.path.isdir(data_folder): os.makedirs(data_folder) return data_folder class CIFAR100Instance(datasets.CIFAR100): """CIFAR100Instance Dataset.""" def __getitem__(self, index): img, target = super().__getitem__(index) return img, target, index # CIFAR-100 for CRD class CIFAR100InstanceSample(datasets.CIFAR100): """ CIFAR100Instance+Sample Dataset """ def __init__( self, root, train=True, transform=None, target_transform=None, download=False, k=4096, mode="exact", is_sample=True, percent=1.0, ): super().__init__( root=root, train=train, download=download, transform=transform, target_transform=target_transform, ) self.k = k self.mode = mode self.is_sample = is_sample num_classes = 100 num_samples = len(self.data) label = self.targets self.cls_positive = [[] for i in range(num_classes)] for i in range(num_samples): self.cls_positive[label[i]].append(i) self.cls_negative = [[] for i in range(num_classes)] for i in range(num_classes): for j in range(num_classes): if j == i: continue self.cls_negative[i].extend(self.cls_positive[j]) self.cls_positive = [ np.asarray(self.cls_positive[i]) for i in range(num_classes) ] self.cls_negative = [ np.asarray(self.cls_negative[i]) for i in range(num_classes) ] if 0 < percent < 1: n = int(len(self.cls_negative[0]) * percent) self.cls_negative = [ np.random.permutation(self.cls_negative[i])[0:n] for i in range(num_classes) ] self.cls_positive = np.asarray(self.cls_positive) self.cls_negative = np.asarray(self.cls_negative) def __getitem__(self, index): img, target = self.data[index], self.targets[index] # doing this so that it is consistent with all other datasets # to return a PIL Image img = Image.fromarray(img) if self.transform is not None: img = self.transform(img) if self.target_transform is not None: target = self.target_transform(target) if not self.is_sample: # directly return return img, target, index else: # sample contrastive examples if self.mode == "exact": pos_idx = index elif self.mode == "relax": pos_idx = np.random.choice(self.cls_positive[target], 1) pos_idx = pos_idx[0] else: raise NotImplementedError(self.mode) replace = True if self.k > len(self.cls_negative[target]) else False neg_idx = np.random.choice( self.cls_negative[target], self.k, replace=replace ) sample_idx = np.hstack((np.asarray([pos_idx]), neg_idx)) return img, target, index, sample_idx def get_cifar100_train_transform(): train_transform = transforms.Compose( [ transforms.RandomCrop(32, padding=4), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize((0.5071, 0.4867, 0.4408), (0.2675, 0.2565, 0.2761)), ] ) return train_transform def get_cifar100_test_transform(): return transforms.Compose( [ transforms.ToTensor(), transforms.Normalize((0.5071, 0.4867, 0.4408), (0.2675, 0.2565, 0.2761)), ] ) def get_cifar100_dataloaders(batch_size, val_batch_size, num_workers): data_folder = get_data_folder() train_transform = get_cifar100_train_transform() test_transform = get_cifar100_test_transform() train_set = CIFAR100Instance( root=data_folder, download=True, train=True, transform=train_transform ) num_data = len(train_set) test_set = datasets.CIFAR100( root=data_folder, download=True, train=False, transform=test_transform ) train_loader = DataLoader( train_set, batch_size=batch_size, shuffle=True, num_workers=num_workers ) test_loader = DataLoader( test_set, batch_size=val_batch_size, shuffle=False, num_workers=1, ) return train_loader, test_loader, num_data # CIFAR-100 for CRD def get_cifar100_dataloaders_sample( batch_size, val_batch_size, num_workers, k, mode="exact" ): data_folder = get_data_folder() train_transform = get_cifar100_train_transform() test_transform = get_cifar100_test_transform() train_set = CIFAR100InstanceSample( root=data_folder, download=True, train=True, transform=train_transform, k=k, mode=mode, is_sample=True, percent=1.0, ) num_data = len(train_set) test_set = datasets.CIFAR100( root=data_folder, download=True, train=False, transform=test_transform ) train_loader = DataLoader( train_set, batch_size=batch_size, shuffle=True, num_workers=num_workers ) test_loader = DataLoader( test_set, batch_size=val_batch_size, shuffle=False, num_workers=num_workers, ) return train_loader, test_loader, num_data ================================================ FILE: mdistiller/dataset/imagenet.py ================================================ import os import numpy as np import torch from torchvision.datasets import ImageFolder import torchvision.transforms as transforms data_folder = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../data/imagenet') class ImageNet(ImageFolder): def __getitem__(self, index): img, target = super().__getitem__(index) return img, target, index class ImageNetInstanceSample(ImageNet): """: Folder datasets which returns (img, label, index, contrast_index): """ def __init__(self, folder, transform=None, target_transform=None, is_sample=False, k=4096): super().__init__(folder, transform=transform) self.k = k self.is_sample = is_sample if self.is_sample: print('preparing contrastive data...') num_classes = 1000 num_samples = len(self.samples) label = np.zeros(num_samples, dtype=np.int32) for i in range(num_samples): _, target = self.samples[i] label[i] = target self.cls_positive = [[] for i in range(num_classes)] for i in range(num_samples): self.cls_positive[label[i]].append(i) self.cls_negative = [[] for i in range(num_classes)] for i in range(num_classes): for j in range(num_classes): if j == i: continue self.cls_negative[i].extend(self.cls_positive[j]) self.cls_positive = [np.asarray(self.cls_positive[i], dtype=np.int32) for i in range(num_classes)] self.cls_negative = [np.asarray(self.cls_negative[i], dtype=np.int32) for i in range(num_classes)] print('done.') def __getitem__(self, index): """ Args: index (int): Index Returns: tuple: (image, target) where target is class_index of the target class. """ img, target, index = super().__getitem__(index) if self.is_sample: # sample contrastive examples pos_idx = index neg_idx = np.random.choice(self.cls_negative[target], self.k, replace=True) sample_idx = np.hstack((np.asarray([pos_idx]), neg_idx)) return img, target, index, sample_idx else: return img, target, index def get_imagenet_train_transform(mean, std): normalize = transforms.Normalize(mean=mean, std=std) train_transform = transforms.Compose( [ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), normalize, ] ) return train_transform def get_imagenet_test_transform(mean, std): normalize = transforms.Normalize(mean=mean, std=std) test_transform = transforms.Compose( [ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), normalize, ] ) return test_transform def get_imagenet_dataloaders(batch_size, val_batch_size, num_workers, mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]): train_transform = get_imagenet_train_transform(mean, std) train_folder = os.path.join(data_folder, 'train') train_set = ImageNet(train_folder, transform=train_transform) num_data = len(train_set) train_loader = torch.utils.data.DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=num_workers, pin_memory=True) test_loader = get_imagenet_val_loader(val_batch_size, mean, std) return train_loader, test_loader, num_data def get_imagenet_dataloaders_sample(batch_size, val_batch_size, num_workers, k=4096, mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]): train_transform = get_imagenet_train_transform(mean, std) train_folder = os.path.join(data_folder, 'train') train_set = ImageNetInstanceSample(train_folder, transform=train_transform, is_sample=True, k=k) num_data = len(train_set) train_loader = torch.utils.data.DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=num_workers, pin_memory=True) test_loader = get_imagenet_val_loader(val_batch_size, mean, std) return train_loader, test_loader, num_data def get_imagenet_val_loader(val_batch_size, mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]): test_transform = get_imagenet_test_transform(mean, std) test_folder = os.path.join(data_folder, 'val') test_set = ImageFolder(test_folder, transform=test_transform) test_loader = torch.utils.data.DataLoader(test_set, batch_size=val_batch_size, shuffle=False, num_workers=16, pin_memory=True) return test_loader ================================================ FILE: mdistiller/dataset/tiny_imagenet.py ================================================ import os from torch.utils.data import DataLoader from torchvision import datasets from torchvision import transforms import numpy as np data_folder = os.path.join( os.path.dirname(os.path.abspath(__file__)), "../../data/tiny-imagenet-200" ) class ImageFolderInstance(datasets.ImageFolder): def __getitem__(self, index): path, target = self.imgs[index] img = self.loader(path) if self.transform is not None: img = self.transform(img) return img, target, index class ImageFolderInstanceSample(ImageFolderInstance): """: Folder datasets which returns (img, label, index, contrast_index): """ def __init__(self, folder, transform=None, target_transform=None, is_sample=False, k=4096): super().__init__(folder, transform=transform) self.k = k self.is_sample = is_sample if self.is_sample: num_classes = 200 num_samples = len(self.samples) label = np.zeros(num_samples, dtype=np.int32) for i in range(num_samples): img, target = self.samples[i] label[i] = target self.cls_positive = [[] for i in range(num_classes)] for i in range(num_samples): self.cls_positive[label[i]].append(i) self.cls_negative = [[] for i in range(num_classes)] for i in range(num_classes): for j in range(num_classes): if j == i: continue self.cls_negative[i].extend(self.cls_positive[j]) self.cls_positive = [np.asarray(self.cls_positive[i], dtype=np.int32) for i in range(num_classes)] self.cls_negative = [np.asarray(self.cls_negative[i], dtype=np.int32) for i in range(num_classes)] print('dataset initialized!') def __getitem__(self, index): """ Args: index (int): Index Returns: tuple: (image, target) where target is class_index of the target class. """ img, target, index = super().__getitem__(index) if self.is_sample: # sample contrastive examples pos_idx = index neg_idx = np.random.choice(self.cls_negative[target], self.k, replace=True) sample_idx = np.hstack((np.asarray([pos_idx]), neg_idx)) return img, target, index, sample_idx else: return img, target, index def get_tinyimagenet_dataloader(batch_size, val_batch_size, num_workers): """Data Loader for tiny-imagenet""" train_transform = transforms.Compose([ transforms.RandomRotation(20), transforms.RandomHorizontalFlip(0.5), transforms.ToTensor(), transforms.Normalize([0.4802, 0.4481, 0.3975], [0.2302, 0.2265, 0.2262]), ]) test_transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize([0.4802, 0.4481, 0.3975], [0.2302, 0.2265, 0.2262]), ]) train_folder = os.path.join(data_folder, "train") test_folder = os.path.join(data_folder, "val") train_set = ImageFolderInstance(train_folder, transform=train_transform) num_data = len(train_set) test_set = datasets.ImageFolder(test_folder, transform=test_transform) train_loader = DataLoader( train_set, batch_size=batch_size, shuffle=True, num_workers=num_workers ) test_loader = DataLoader( test_set, batch_size=val_batch_size, shuffle=False, num_workers=1 ) return train_loader, test_loader, num_data def get_tinyimagenet_dataloader_sample(batch_size, val_batch_size, num_workers, k): """Data Loader for tiny-imagenet""" train_transform = transforms.Compose([ transforms.RandomRotation(20), transforms.RandomHorizontalFlip(0.5), transforms.ToTensor(), transforms.Normalize([0.4802, 0.4481, 0.3975], [0.2302, 0.2265, 0.2262]), ]) test_transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize([0.4802, 0.4481, 0.3975], [0.2302, 0.2265, 0.2262]), ]) train_folder = os.path.join(data_folder, "train") test_folder = os.path.join(data_folder, "val") train_set = ImageFolderInstanceSample(train_folder, transform=train_transform, is_sample=True, k=k) num_data = len(train_set) test_set = datasets.ImageFolder(test_folder, transform=test_transform) train_loader = DataLoader( train_set, batch_size=batch_size, shuffle=True, num_workers=num_workers ) test_loader = DataLoader( test_set, batch_size=val_batch_size, shuffle=False, num_workers=1 ) return train_loader, test_loader, num_data ================================================ FILE: mdistiller/distillers/AT.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F from ._base import Distiller def single_stage_at_loss(f_s, f_t, p): def _at(feat, p): return F.normalize(feat.pow(p).mean(1).reshape(feat.size(0), -1)) s_H, t_H = f_s.shape[2], f_t.shape[2] if s_H > t_H: f_s = F.adaptive_avg_pool2d(f_s, (t_H, t_H)) elif s_H < t_H: f_t = F.adaptive_avg_pool2d(f_t, (s_H, s_H)) return (_at(f_s, p) - _at(f_t, p)).pow(2).mean() def at_loss(g_s, g_t, p): return sum([single_stage_at_loss(f_s, f_t, p) for f_s, f_t in zip(g_s, g_t)]) class AT(Distiller): """ Paying More Attention to Attention: Improving the Performance of Convolutional Neural Networks via Attention Transfer src code: https://github.com/szagoruyko/attention-transfer """ def __init__(self, student, teacher, cfg): super(AT, self).__init__(student, teacher) self.p = cfg.AT.P self.ce_loss_weight = cfg.AT.LOSS.CE_WEIGHT self.feat_loss_weight = cfg.AT.LOSS.FEAT_WEIGHT def forward_train(self, image, target, **kwargs): logits_student, feature_student = self.student(image) with torch.no_grad(): _, feature_teacher = self.teacher(image) # losses loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_feat = self.feat_loss_weight * at_loss( feature_student["feats"][1:], feature_teacher["feats"][1:], self.p ) losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_feat, } return logits_student, losses_dict ================================================ FILE: mdistiller/distillers/CRD.py ================================================ import torch from torch import nn import torch.nn.functional as F import math from ._base import Distiller class CRD(Distiller): """Contrastive Representation Distillation""" def __init__(self, student, teacher, cfg, num_data): super(CRD, self).__init__(student, teacher) self.ce_loss_weight = cfg.CRD.LOSS.CE_WEIGHT self.feat_loss_weight = cfg.CRD.LOSS.FEAT_WEIGHT self.init_crd_modules( cfg.CRD.FEAT.STUDENT_DIM, cfg.CRD.FEAT.TEACHER_DIM, cfg.CRD.FEAT.DIM, num_data, cfg.CRD.NCE.K, cfg.CRD.NCE.MOMENTUM, cfg.CRD.NCE.TEMPERATURE, ) def init_crd_modules( self, feat_s_channel, feat_t_channel, feat_dim, num_data, k=16384, momentum=0.5, temperature=0.07, ): self.embed_s = Embed(feat_s_channel, feat_dim) self.embed_t = Embed(feat_t_channel, feat_dim) self.contrast = ContrastMemory(feat_dim, num_data, k, temperature, momentum) self.criterion_s = ContrastLoss(num_data) self.criterion_t = ContrastLoss(num_data) def get_learnable_parameters(self): return ( super().get_learnable_parameters() + list(self.embed_s.parameters()) + list(self.embed_t.parameters()) ) def get_extra_parameters(self): params = ( list(self.embed_s.parameters()) + list(self.embed_t.parameters()) + list(self.contrast.buffers()) ) num_p = 0 for p in params: num_p += p.numel() return num_p def crd_loss(self, f_s, f_t, idx, contrast_idx): f_s = self.embed_s(f_s) f_t = self.embed_t(f_t) out_s, out_t = self.contrast(f_s, f_t, idx, contrast_idx) s_loss = self.criterion_s(out_s) t_loss = self.criterion_t(out_t) return s_loss + t_loss def forward_train(self, image, target, index, contrastive_index, **kwargs): logits_student, feature_student = self.student(image) with torch.no_grad(): _, feature_teacher = self.teacher(image) # losses loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_crd = self.feat_loss_weight * self.crd_loss( feature_student["pooled_feat"], feature_teacher["pooled_feat"], index, contrastive_index, ) losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_crd, } return logits_student, losses_dict class Normalize(nn.Module): """normalization layer""" def __init__(self, power=2): super(Normalize, self).__init__() self.power = power def forward(self, x): norm = x.pow(self.power).sum(1, keepdim=True).pow(1.0 / self.power) out = x.div(norm) return out class Embed(nn.Module): """Embedding module""" def __init__(self, dim_in=1024, dim_out=128): super(Embed, self).__init__() self.linear = nn.Linear(dim_in, dim_out) self.l2norm = Normalize(2) def forward(self, x): x = x.reshape(x.shape[0], -1) x = self.linear(x) x = self.l2norm(x) return x class ContrastLoss(nn.Module): """contrastive loss""" def __init__(self, num_data): super(ContrastLoss, self).__init__() self.num_data = num_data def forward(self, x): eps = 1e-7 bsz = x.shape[0] m = x.size(1) - 1 # noise distribution Pn = 1 / float(self.num_data) # loss for positive pair P_pos = x.select(1, 0) log_D1 = torch.div(P_pos, P_pos.add(m * Pn + eps)).log_() # loss for K negative pair P_neg = x.narrow(1, 1, m) log_D0 = torch.div(P_neg.clone().fill_(m * Pn), P_neg.add(m * Pn + eps)).log_() loss = -(log_D1.sum(0) + log_D0.view(-1, 1).sum(0)) / bsz return loss class ContrastMemory(nn.Module): """memory buffer that supplies large amount of negative samples.""" def __init__(self, inputSize, output_size, K, T=0.07, momentum=0.5): super(ContrastMemory, self).__init__() self.n_lem = output_size self.unigrams = torch.ones(self.n_lem) self.multinomial = AliasMethod(self.unigrams) self.multinomial.cuda() self.K = K self.register_buffer("params", torch.tensor([K, T, -1, -1, momentum])) stdv = 1.0 / math.sqrt(inputSize / 3) self.register_buffer( "memory_v1", torch.rand(output_size, inputSize).mul_(2 * stdv).add_(-stdv) ) self.register_buffer( "memory_v2", torch.rand(output_size, inputSize).mul_(2 * stdv).add_(-stdv) ) def forward(self, v1, v2, y, idx=None): K = int(self.params[0].item()) T = self.params[1].item() Z_v1 = self.params[2].item() Z_v2 = self.params[3].item() momentum = self.params[4].item() batchSize = v1.size(0) outputSize = self.memory_v1.size(0) inputSize = self.memory_v1.size(1) # original score computation if idx is None: idx = self.multinomial.draw(batchSize * (self.K + 1)).view(batchSize, -1) idx.select(1, 0).copy_(y.data) # sample weight_v1 = torch.index_select(self.memory_v1, 0, idx.view(-1)).detach() weight_v1 = weight_v1.view(batchSize, K + 1, inputSize) out_v2 = torch.bmm(weight_v1, v2.view(batchSize, inputSize, 1)) out_v2 = torch.exp(torch.div(out_v2, T)) # sample weight_v2 = torch.index_select(self.memory_v2, 0, idx.view(-1)).detach() weight_v2 = weight_v2.view(batchSize, K + 1, inputSize) out_v1 = torch.bmm(weight_v2, v1.view(batchSize, inputSize, 1)) out_v1 = torch.exp(torch.div(out_v1, T)) # set Z if haven't been set yet if Z_v1 < 0: self.params[2] = out_v1.mean() * outputSize Z_v1 = self.params[2].clone().detach().item() # print("normalization constant Z_v1 is set to {:.1f}".format(Z_v1)) if Z_v2 < 0: self.params[3] = out_v2.mean() * outputSize Z_v2 = self.params[3].clone().detach().item() # print("normalization constant Z_v2 is set to {:.1f}".format(Z_v2)) # compute out_v1, out_v2 out_v1 = torch.div(out_v1, Z_v1).contiguous() out_v2 = torch.div(out_v2, Z_v2).contiguous() # update memory with torch.no_grad(): l_pos = torch.index_select(self.memory_v1, 0, y.view(-1)) l_pos.mul_(momentum) l_pos.add_(torch.mul(v1, 1 - momentum)) l_norm = l_pos.pow(2).sum(1, keepdim=True).pow(0.5) updated_v1 = l_pos.div(l_norm) self.memory_v1.index_copy_(0, y, updated_v1) ab_pos = torch.index_select(self.memory_v2, 0, y.view(-1)) ab_pos.mul_(momentum) ab_pos.add_(torch.mul(v2, 1 - momentum)) ab_norm = ab_pos.pow(2).sum(1, keepdim=True).pow(0.5) updated_v2 = ab_pos.div(ab_norm) self.memory_v2.index_copy_(0, y, updated_v2) return out_v1, out_v2 class AliasMethod(object): """ From: https://hips.seas.harvard.edu/blog/2013/03/03/the-alias-method-efficient-sampling-with-many-discrete-outcomes/ """ def __init__(self, probs): if probs.sum() > 1: probs.div_(probs.sum()) K = len(probs) self.prob = torch.zeros(K) self.alias = torch.LongTensor([0] * K) # Sort the data into the outcomes with probabilities # that are larger and smaller than 1/K. smaller = [] larger = [] for kk, prob in enumerate(probs): self.prob[kk] = K * prob if self.prob[kk] < 1.0: smaller.append(kk) else: larger.append(kk) # Loop though and create little binary mixtures that # appropriately allocate the larger outcomes over the # overall uniform mixture. while len(smaller) > 0 and len(larger) > 0: small = smaller.pop() large = larger.pop() self.alias[small] = large self.prob[large] = (self.prob[large] - 1.0) + self.prob[small] if self.prob[large] < 1.0: smaller.append(large) else: larger.append(large) for last_one in smaller + larger: self.prob[last_one] = 1 def cuda(self): self.prob = self.prob.cuda() self.alias = self.alias.cuda() def draw(self, N): """Draw N samples from multinomial""" K = self.alias.size(0) kk = torch.zeros(N, dtype=torch.long, device=self.prob.device).random_(0, K) prob = self.prob.index_select(0, kk) alias = self.alias.index_select(0, kk) # b is whether a random number is greater than q b = torch.bernoulli(prob) oq = kk.mul(b.long()) oj = alias.mul((1 - b).long()) return oq + oj ================================================ FILE: mdistiller/distillers/DKD.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F from ._base import Distiller def dkd_loss(logits_student, logits_teacher, target, alpha, beta, temperature): gt_mask = _get_gt_mask(logits_student, target) other_mask = _get_other_mask(logits_student, target) pred_student = F.softmax(logits_student / temperature, dim=1) pred_teacher = F.softmax(logits_teacher / temperature, dim=1) pred_student = cat_mask(pred_student, gt_mask, other_mask) pred_teacher = cat_mask(pred_teacher, gt_mask, other_mask) log_pred_student = torch.log(pred_student) tckd_loss = ( F.kl_div(log_pred_student, pred_teacher, size_average=False) * (temperature**2) / target.shape[0] ) pred_teacher_part2 = F.softmax( logits_teacher / temperature - 1000.0 * gt_mask, dim=1 ) log_pred_student_part2 = F.log_softmax( logits_student / temperature - 1000.0 * gt_mask, dim=1 ) nckd_loss = ( F.kl_div(log_pred_student_part2, pred_teacher_part2, size_average=False) * (temperature**2) / target.shape[0] ) return alpha * tckd_loss + beta * nckd_loss def _get_gt_mask(logits, target): target = target.reshape(-1) mask = torch.zeros_like(logits).scatter_(1, target.unsqueeze(1), 1).bool() return mask def _get_other_mask(logits, target): target = target.reshape(-1) mask = torch.ones_like(logits).scatter_(1, target.unsqueeze(1), 0).bool() return mask def cat_mask(t, mask1, mask2): t1 = (t * mask1).sum(dim=1, keepdims=True) t2 = (t * mask2).sum(1, keepdims=True) rt = torch.cat([t1, t2], dim=1) return rt class DKD(Distiller): """Decoupled Knowledge Distillation(CVPR 2022)""" def __init__(self, student, teacher, cfg): super(DKD, self).__init__(student, teacher) self.ce_loss_weight = cfg.DKD.CE_WEIGHT self.alpha = cfg.DKD.ALPHA self.beta = cfg.DKD.BETA self.temperature = cfg.DKD.T self.warmup = cfg.DKD.WARMUP def forward_train(self, image, target, **kwargs): logits_student, _ = self.student(image) with torch.no_grad(): logits_teacher, _ = self.teacher(image) # losses loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_dkd = min(kwargs["epoch"] / self.warmup, 1.0) * dkd_loss( logits_student, logits_teacher, target, self.alpha, self.beta, self.temperature, ) losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_dkd, } return logits_student, losses_dict ================================================ FILE: mdistiller/distillers/FitNet.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F from ._base import Distiller from ._common import ConvReg, get_feat_shapes class FitNet(Distiller): """FitNets: Hints for Thin Deep Nets""" def __init__(self, student, teacher, cfg): super(FitNet, self).__init__(student, teacher) self.ce_loss_weight = cfg.FITNET.LOSS.CE_WEIGHT self.feat_loss_weight = cfg.FITNET.LOSS.FEAT_WEIGHT self.hint_layer = cfg.FITNET.HINT_LAYER feat_s_shapes, feat_t_shapes = get_feat_shapes( self.student, self.teacher, cfg.FITNET.INPUT_SIZE ) self.conv_reg = ConvReg( feat_s_shapes[self.hint_layer], feat_t_shapes[self.hint_layer] ) def get_learnable_parameters(self): return super().get_learnable_parameters() + list(self.conv_reg.parameters()) def get_extra_parameters(self): num_p = 0 for p in self.conv_reg.parameters(): num_p += p.numel() return num_p def forward_train(self, image, target, **kwargs): logits_student, feature_student = self.student(image) with torch.no_grad(): _, feature_teacher = self.teacher(image) # losses loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) f_s = self.conv_reg(feature_student["feats"][self.hint_layer]) loss_feat = self.feat_loss_weight * F.mse_loss( f_s, feature_teacher["feats"][self.hint_layer] ) losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_feat, } return logits_student, losses_dict ================================================ FILE: mdistiller/distillers/KD.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F from ._base import Distiller def kd_loss(logits_student, logits_teacher, temperature): log_pred_student = F.log_softmax(logits_student / temperature, dim=1) pred_teacher = F.softmax(logits_teacher / temperature, dim=1) loss_kd = F.kl_div(log_pred_student, pred_teacher, reduction="none").sum(1).mean() loss_kd *= temperature**2 return loss_kd class KD(Distiller): """Distilling the Knowledge in a Neural Network""" def __init__(self, student, teacher, cfg): super(KD, self).__init__(student, teacher) self.temperature = cfg.KD.TEMPERATURE self.ce_loss_weight = cfg.KD.LOSS.CE_WEIGHT self.kd_loss_weight = cfg.KD.LOSS.KD_WEIGHT def forward_train(self, image, target, **kwargs): logits_student, _ = self.student(image) with torch.no_grad(): logits_teacher, _ = self.teacher(image) # losses loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_kd = self.kd_loss_weight * kd_loss( logits_student, logits_teacher, self.temperature ) losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_kd, } return logits_student, losses_dict ================================================ FILE: mdistiller/distillers/KDSVD.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F from ._base import Distiller def kdsvd_loss(g_s, g_t, k): v_sb = None v_tb = None losses = [] for i, f_s, f_t in zip(range(len(g_s)), g_s, g_t): u_t, s_t, v_t = svd(f_t, k) u_s, s_s, v_s = svd(f_s, k + 3) v_s, v_t = align_rsv(v_s, v_t) s_t = s_t.unsqueeze(1) v_t = v_t * s_t v_s = v_s * s_t if i > 0: s_rbf = torch.exp(-(v_s.unsqueeze(2) - v_sb.unsqueeze(1)).pow(2) / 8) t_rbf = torch.exp(-(v_t.unsqueeze(2) - v_tb.unsqueeze(1)).pow(2) / 8) l2loss = (s_rbf - t_rbf.detach()).pow(2) l2loss = torch.where( torch.isfinite(l2loss), l2loss, torch.zeros_like(l2loss) ) losses.append(l2loss.sum()) v_tb = v_t v_sb = v_s bsz = g_s[0].shape[0] losses = [l / bsz for l in losses] return sum(losses) def svd(feat, n=1): size = feat.shape assert len(size) == 4 x = feat.view(size[0], size[1] * size[2], size[3]).float() u, s, v = torch.svd(x) u = removenan(u) s = removenan(s) v = removenan(v) if n > 0: u = F.normalize(u[:, :, :n], dim=1) s = F.normalize(s[:, :n], dim=1) v = F.normalize(v[:, :, :n], dim=1) return u, s, v def removenan(x): x = torch.where(torch.isfinite(x), x, torch.zeros_like(x)) return x def align_rsv(a, b): cosine = torch.matmul(a.transpose(-2, -1), b) max_abs_cosine, _ = torch.max(torch.abs(cosine), 1, keepdim=True) mask = torch.where( torch.eq(max_abs_cosine, torch.abs(cosine)), torch.sign(cosine), torch.zeros_like(cosine), ) a = torch.matmul(a, mask) return a, b class KDSVD(Distiller): """ Self-supervised Knowledge Distillation using Singular Value Decomposition original Tensorflow code: https://github.com/sseung0703/SSKD_SVD """ def __init__(self, student, teacher, cfg): super(KDSVD, self).__init__(student, teacher) self.k = cfg.KDSVD.K self.ce_loss_weight = cfg.KDSVD.LOSS.CE_WEIGHT self.feat_loss_weight = cfg.KDSVD.LOSS.FEAT_WEIGHT def forward_train(self, image, target, **kwargs): logits_student, feature_student = self.student(image) with torch.no_grad(): _, feature_teacher = self.teacher(image) loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_feat = self.feat_loss_weight * kdsvd_loss( feature_student["feats"][1:], feature_teacher["feats"][1:], self.k ) losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_feat, } return logits_student, losses_dict ================================================ FILE: mdistiller/distillers/NST.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F from ._base import Distiller def nst_loss(g_s, g_t): return sum([single_stage_nst_loss(f_s, f_t) for f_s, f_t in zip(g_s, g_t)]) def single_stage_nst_loss(f_s, f_t): s_H, t_H = f_s.shape[2], f_t.shape[2] if s_H > t_H: f_s = F.adaptive_avg_pool2d(f_s, (t_H, t_H)) elif s_H < t_H: f_t = F.adaptive_avg_pool2d(f_t, (s_H, s_H)) f_s = f_s.view(f_s.shape[0], f_s.shape[1], -1) f_s = F.normalize(f_s, dim=2) f_t = f_t.view(f_t.shape[0], f_t.shape[1], -1) f_t = F.normalize(f_t, dim=2) return ( poly_kernel(f_t, f_t).mean().detach() + poly_kernel(f_s, f_s).mean() - 2 * poly_kernel(f_s, f_t).mean() ) def poly_kernel(a, b): a = a.unsqueeze(1) b = b.unsqueeze(2) res = (a * b).sum(-1).pow(2) return res class NST(Distiller): """ Like What You Like: Knowledge Distill via Neuron Selectivity Transfer """ def __init__(self, student, teacher, cfg): super(NST, self).__init__(student, teacher) self.ce_loss_weight = cfg.NST.LOSS.CE_WEIGHT self.feat_loss_weight = cfg.NST.LOSS.FEAT_WEIGHT def forward_train(self, image, target, **kwargs): logits_student, feature_student = self.student(image) with torch.no_grad(): _, feature_teacher = self.teacher(image) # losses loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_feat = self.feat_loss_weight * nst_loss( feature_student["feats"][1:], feature_teacher["feats"][1:] ) losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_feat, } return logits_student, losses_dict ================================================ FILE: mdistiller/distillers/OFD.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F from scipy.stats import norm import numpy as np import math from ._base import Distiller def feat_loss(source, target, margin): margin = margin.to(source) loss = ( (source - margin) ** 2 * ((source > margin) & (target <= margin)).float() + (source - target) ** 2 * ((source > target) & (target > margin) & (target <= 0)).float() + (source - target) ** 2 * (target > 0).float() ) return torch.abs(loss).mean(dim=0).sum() class ConnectorConvBN(nn.Module): def __init__(self, s_channels, t_channels, kernel_size=1): super(ConnectorConvBN, self).__init__() self.s_channels = s_channels self.t_channels = t_channels self.connectors = nn.ModuleList( self._make_conenctors(s_channels, t_channels, kernel_size) ) def _make_conenctors(self, s_channels, t_channels, kernel_size): assert len(s_channels) == len(t_channels), "unequal length of feat list" connectors = nn.ModuleList( [ self._build_feature_connector(t, s, kernel_size) for t, s in zip(t_channels, s_channels) ] ) return connectors def _build_feature_connector(self, t_channel, s_channel, kernel_size): C = [ nn.Conv2d( s_channel, t_channel, kernel_size=kernel_size, stride=1, padding=(kernel_size - 1) // 2, bias=False, ), nn.BatchNorm2d(t_channel), ] for m in C: if isinstance(m, nn.Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2.0 / n)) elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_() return nn.Sequential(*C) def forward(self, g_s): out = [] for i in range(len(g_s)): out.append(self.connectors[i](g_s[i])) return out class OFD(Distiller): def __init__(self, student, teacher, cfg): super(OFD, self).__init__(student, teacher) self.ce_loss_weight = cfg.OFD.LOSS.CE_WEIGHT self.feat_loss_weight = cfg.OFD.LOSS.FEAT_WEIGHT self.init_ofd_modules( tea_channels=self.teacher.get_stage_channels()[1:], stu_channels=self.student.get_stage_channels()[1:], bn_before_relu=self.teacher.get_bn_before_relu(), kernel_size=cfg.OFD.CONNECTOR.KERNEL_SIZE, ) def init_ofd_modules( self, tea_channels, stu_channels, bn_before_relu, kernel_size=1 ): tea_channels, stu_channels = self._align_list(tea_channels, stu_channels) self.connectors = ConnectorConvBN( stu_channels, tea_channels, kernel_size=kernel_size ) self.margins = [] for idx, bn in enumerate(bn_before_relu): margin = [] std = bn.weight.data mean = bn.bias.data for (s, m) in zip(std, mean): s = abs(s.item()) m = m.item() if norm.cdf(-m / s) > 0.001: margin.append( -s * math.exp(-((m / s) ** 2) / 2) / math.sqrt(2 * math.pi) / norm.cdf(-m / s) + m ) else: margin.append(-3 * s) margin = torch.FloatTensor(margin).to(std.device) self.margins.append(margin.unsqueeze(1).unsqueeze(2).unsqueeze(0).detach()) def get_learnable_parameters(self): return super().get_learnable_parameters() + list(self.connectors.parameters()) def train(self, mode=True): # teacher as eval mode by default if not isinstance(mode, bool): raise ValueError("training mode is expected to be boolean") self.training = mode for module in self.children(): module.train(mode) return self def get_extra_parameters(self): num_p = 0 for p in self.connectors.parameters(): num_p += p.numel() return num_p def forward_train(self, image, target, **kwargs): logits_student, feature_student = self.student(image) with torch.no_grad(): _, feature_teacher = self.teacher(image) # losses loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_feat = self.feat_loss_weight * self.ofd_loss( feature_student["preact_feats"][1:], feature_teacher["preact_feats"][1:] ) losses_dict = {"loss_ce": loss_ce, "loss_kd": loss_feat} return logits_student, losses_dict def ofd_loss(self, feature_student, feature_teacher): feature_student, feature_teacher = self._align_list( feature_student, feature_teacher ) feature_student = [ self.connectors.connectors[idx](feat) for idx, feat in enumerate(feature_student) ] loss_distill = 0 feat_num = len(feature_student) for i in range(feat_num): loss_distill = loss_distill + feat_loss( feature_student[i], F.adaptive_avg_pool2d( feature_teacher[i], feature_student[i].shape[-2:] ).detach(), self.margins[i], ) / 2 ** (feat_num - i - 1) return loss_distill def _align_list(self, *input_list): min_len = min([len(l) for l in input_list]) return [l[-min_len:] for l in input_list] ================================================ FILE: mdistiller/distillers/PKT.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F from ._base import Distiller def pkt_loss(f_s, f_t, eps=1e-7): # Normalize each vector by its norm output_net_norm = torch.sqrt(torch.sum(f_s**2, dim=1, keepdim=True)) f_s = f_s / (output_net_norm + eps) f_s[f_s != f_s] = 0 target_net_norm = torch.sqrt(torch.sum(f_t**2, dim=1, keepdim=True)) f_t = f_t / (target_net_norm + eps) f_t[f_t != f_t] = 0 # Calculate the cosine similarity model_similarity = torch.mm(f_s, f_s.transpose(0, 1)) target_similarity = torch.mm(f_t, f_t.transpose(0, 1)) # Scale cosine similarity to 0..1 model_similarity = (model_similarity + 1.0) / 2.0 target_similarity = (target_similarity + 1.0) / 2.0 # Transform them into probabilities model_similarity = model_similarity / torch.sum( model_similarity, dim=1, keepdim=True ) target_similarity = target_similarity / torch.sum( target_similarity, dim=1, keepdim=True ) # Calculate the KL-divergence loss = torch.mean( target_similarity * torch.log((target_similarity + eps) / (model_similarity + eps)) ) return loss class PKT(Distiller): """ Probabilistic Knowledge Transfer for deep representation learning Code from: https://github.com/passalis/probabilistic_kt """ def __init__(self, student, teacher, cfg): super(PKT, self).__init__(student, teacher) self.ce_loss_weight = cfg.PKT.LOSS.CE_WEIGHT self.feat_loss_weight = cfg.PKT.LOSS.FEAT_WEIGHT def forward_train(self, image, target, **kwargs): logits_student, feature_student = self.student(image) with torch.no_grad(): _, feature_teacher = self.teacher(image) # lossess loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_feat = self.feat_loss_weight * pkt_loss( feature_student["pooled_feat"], feature_teacher["pooled_feat"] ) losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_feat, } return logits_student, losses_dict ================================================ FILE: mdistiller/distillers/RKD.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F from ._base import Distiller def _pdist(e, squared, eps): e_square = e.pow(2).sum(dim=1) prod = e @ e.t() res = (e_square.unsqueeze(1) + e_square.unsqueeze(0) - 2 * prod).clamp(min=eps) if not squared: res = res.sqrt() res = res.clone() res[range(len(e)), range(len(e))] = 0 return res def rkd_loss(f_s, f_t, squared=False, eps=1e-12, distance_weight=25, angle_weight=50): stu = f_s.view(f_s.shape[0], -1) tea = f_t.view(f_t.shape[0], -1) # RKD distance loss with torch.no_grad(): t_d = _pdist(tea, squared, eps) mean_td = t_d[t_d > 0].mean() t_d = t_d / mean_td d = _pdist(stu, squared, eps) mean_d = d[d > 0].mean() d = d / mean_d loss_d = F.smooth_l1_loss(d, t_d) # RKD Angle loss with torch.no_grad(): td = tea.unsqueeze(0) - tea.unsqueeze(1) norm_td = F.normalize(td, p=2, dim=2) t_angle = torch.bmm(norm_td, norm_td.transpose(1, 2)).view(-1) sd = stu.unsqueeze(0) - stu.unsqueeze(1) norm_sd = F.normalize(sd, p=2, dim=2) s_angle = torch.bmm(norm_sd, norm_sd.transpose(1, 2)).view(-1) loss_a = F.smooth_l1_loss(s_angle, t_angle) loss = distance_weight * loss_d + angle_weight * loss_a return loss class RKD(Distiller): """Relational Knowledge Disitllation, CVPR2019""" def __init__(self, student, teacher, cfg): super(RKD, self).__init__(student, teacher) self.distance_weight = cfg.RKD.DISTANCE_WEIGHT self.angle_weight = cfg.RKD.ANGLE_WEIGHT self.ce_loss_weight = cfg.RKD.LOSS.CE_WEIGHT self.feat_loss_weight = cfg.RKD.LOSS.FEAT_WEIGHT self.eps = cfg.RKD.PDIST.EPSILON self.squared = cfg.RKD.PDIST.SQUARED def forward_train(self, image, target, **kwargs): logits_student, feature_student = self.student(image) with torch.no_grad(): _, feature_teacher = self.teacher(image) # losses loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_rkd = self.feat_loss_weight * rkd_loss( feature_student["pooled_feat"], feature_teacher["pooled_feat"], self.squared, self.eps, self.distance_weight, self.angle_weight, ) losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_rkd, } return logits_student, losses_dict ================================================ FILE: mdistiller/distillers/ReviewKD.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim import math import pdb from ._base import Distiller def hcl_loss(fstudent, fteacher): loss_all = 0.0 for fs, ft in zip(fstudent, fteacher): n, c, h, w = fs.shape loss = F.mse_loss(fs, ft, reduction="mean") cnt = 1.0 tot = 1.0 for l in [4, 2, 1]: if l >= h: continue tmpfs = F.adaptive_avg_pool2d(fs, (l, l)) tmpft = F.adaptive_avg_pool2d(ft, (l, l)) cnt /= 2.0 loss += F.mse_loss(tmpfs, tmpft, reduction="mean") * cnt tot += cnt loss = loss / tot loss_all = loss_all + loss return loss_all class ReviewKD(Distiller): def __init__(self, student, teacher, cfg): super(ReviewKD, self).__init__(student, teacher) self.shapes = cfg.REVIEWKD.SHAPES self.out_shapes = cfg.REVIEWKD.OUT_SHAPES in_channels = cfg.REVIEWKD.IN_CHANNELS out_channels = cfg.REVIEWKD.OUT_CHANNELS self.ce_loss_weight = cfg.REVIEWKD.CE_WEIGHT self.reviewkd_loss_weight = cfg.REVIEWKD.REVIEWKD_WEIGHT self.warmup_epochs = cfg.REVIEWKD.WARMUP_EPOCHS self.stu_preact = cfg.REVIEWKD.STU_PREACT self.max_mid_channel = cfg.REVIEWKD.MAX_MID_CHANNEL abfs = nn.ModuleList() mid_channel = min(512, in_channels[-1]) for idx, in_channel in enumerate(in_channels): abfs.append( ABF( in_channel, mid_channel, out_channels[idx], idx < len(in_channels) - 1, ) ) self.abfs = abfs[::-1] def get_learnable_parameters(self): return super().get_learnable_parameters() + list(self.abfs.parameters()) def get_extra_parameters(self): num_p = 0 for p in self.abfs.parameters(): num_p += p.numel() return num_p def forward_train(self, image, target, **kwargs): logits_student, features_student = self.student(image) with torch.no_grad(): logits_teacher, features_teacher = self.teacher(image) # get features if self.stu_preact: x = features_student["preact_feats"] + [ features_student["pooled_feat"].unsqueeze(-1).unsqueeze(-1) ] else: x = features_student["feats"] + [ features_student["pooled_feat"].unsqueeze(-1).unsqueeze(-1) ] x = x[::-1] results = [] out_features, res_features = self.abfs[0](x[0], out_shape=self.out_shapes[0]) results.append(out_features) for features, abf, shape, out_shape in zip( x[1:], self.abfs[1:], self.shapes[1:], self.out_shapes[1:] ): out_features, res_features = abf(features, res_features, shape, out_shape) results.insert(0, out_features) features_teacher = features_teacher["preact_feats"][1:] + [ features_teacher["pooled_feat"].unsqueeze(-1).unsqueeze(-1) ] # losses loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_reviewkd = ( self.reviewkd_loss_weight * min(kwargs["epoch"] / self.warmup_epochs, 1.0) * hcl_loss(results, features_teacher) ) losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_reviewkd, } return logits_student, losses_dict class ABF(nn.Module): def __init__(self, in_channel, mid_channel, out_channel, fuse): super(ABF, self).__init__() self.conv1 = nn.Sequential( nn.Conv2d(in_channel, mid_channel, kernel_size=1, bias=False), nn.BatchNorm2d(mid_channel), ) self.conv2 = nn.Sequential( nn.Conv2d( mid_channel, out_channel, kernel_size=3, stride=1, padding=1, bias=False ), nn.BatchNorm2d(out_channel), ) if fuse: self.att_conv = nn.Sequential( nn.Conv2d(mid_channel * 2, 2, kernel_size=1), nn.Sigmoid(), ) else: self.att_conv = None nn.init.kaiming_uniform_(self.conv1[0].weight, a=1) # pyre-ignore nn.init.kaiming_uniform_(self.conv2[0].weight, a=1) # pyre-ignore def forward(self, x, y=None, shape=None, out_shape=None): n, _, h, w = x.shape # transform student features x = self.conv1(x) if self.att_conv is not None: # upsample residual features y = F.interpolate(y, (shape, shape), mode="nearest") # fusion z = torch.cat([x, y], dim=1) z = self.att_conv(z) x = x * z[:, 0].view(n, 1, h, w) + y * z[:, 1].view(n, 1, h, w) # output if x.shape[-1] != out_shape: x = F.interpolate(x, (out_shape, out_shape), mode="nearest") y = self.conv2(x) return y, x ================================================ FILE: mdistiller/distillers/SP.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F from ._base import Distiller def sp_loss(g_s, g_t): return sum([similarity_loss(f_s, f_t) for f_s, f_t in zip(g_s, g_t)]) def similarity_loss(f_s, f_t): bsz = f_s.shape[0] f_s = f_s.view(bsz, -1) f_t = f_t.view(bsz, -1) G_s = torch.mm(f_s, torch.t(f_s)) G_s = torch.nn.functional.normalize(G_s) G_t = torch.mm(f_t, torch.t(f_t)) G_t = torch.nn.functional.normalize(G_t) G_diff = G_t - G_s loss = (G_diff * G_diff).view(-1, 1).sum(0) / (bsz * bsz) return loss class SP(Distiller): """Similarity-Preserving Knowledge Distillation, ICCV2019""" def __init__(self, student, teacher, cfg): super(SP, self).__init__(student, teacher) self.ce_loss_weight = cfg.SP.LOSS.CE_WEIGHT self.feat_loss_weight = cfg.SP.LOSS.FEAT_WEIGHT def forward_train(self, image, target, **kwargs): logits_student, feature_student = self.student(image) with torch.no_grad(): _, feature_teacher = self.teacher(image) # losses loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_feat = self.feat_loss_weight * sp_loss( [feature_student["feats"][-1]], [feature_teacher["feats"][-1]] ) losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_feat, } return logits_student, losses_dict ================================================ FILE: mdistiller/distillers/VID.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F import numpy as np from ._base import Distiller from ._common import get_feat_shapes def conv1x1(in_channels, out_channels, stride=1): return nn.Conv2d( in_channels, out_channels, kernel_size=1, padding=0, bias=False, stride=stride ) def vid_loss(regressor, log_scale, f_s, f_t, eps=1e-5): # pool for dimentsion match s_H, t_H = f_s.shape[2], f_t.shape[2] if s_H > t_H: f_s = F.adaptive_avg_pool2d(f_s, (t_H, t_H)) elif s_H < t_H: f_t = F.adaptive_avg_pool2d(f_t, (s_H, s_H)) else: pass pred_mean = regressor(f_s) pred_var = torch.log(1.0 + torch.exp(log_scale)) + eps pred_var = pred_var.view(1, -1, 1, 1).to(pred_mean) neg_log_prob = 0.5 * ((pred_mean - f_t) ** 2 / pred_var + torch.log(pred_var)) loss = torch.mean(neg_log_prob) return loss class VID(Distiller): """ Variational Information Distillation for Knowledge Transfer (CVPR 2019), code from author: https://github.com/ssahn0215/variational-information-distillation """ def __init__(self, student, teacher, cfg): super(VID, self).__init__(student, teacher) self.ce_loss_weight = cfg.VID.LOSS.CE_WEIGHT self.feat_loss_weight = cfg.VID.LOSS.FEAT_WEIGHT self.init_pred_var = cfg.VID.INIT_PRED_VAR self.eps = cfg.VID.EPS feat_s_shapes, feat_t_shapes = get_feat_shapes( self.student, self.teacher, cfg.VID.INPUT_SIZE ) feat_s_channels = [s[1] for s in feat_s_shapes[1:]] feat_t_channels = [s[1] for s in feat_t_shapes[1:]] self.init_vid_modules(feat_s_channels, feat_t_channels) def init_vid_modules(self, feat_s_shapes, feat_t_shapes): self.regressors = nn.ModuleList() self.log_scales = [] for s, t in zip(feat_s_shapes, feat_t_shapes): regressor = nn.Sequential( conv1x1(s, t), nn.ReLU(), conv1x1(t, t), nn.ReLU(), conv1x1(t, t) ) self.regressors.append(regressor) log_scale = torch.nn.Parameter( np.log(np.exp(self.init_pred_var - self.eps) - 1.0) * torch.ones(t) ) self.log_scales.append(log_scale) def get_learnable_parameters(self): parameters = super().get_learnable_parameters() for regressor in self.regressors: parameters += list(regressor.parameters()) return parameters def get_extra_parameters(self): num_p = 0 for regressor in self.regressors: for p in regressor.parameters(): num_p += p.numel() return num_p def forward_train(self, image, target, **kwargs): logits_student, feature_student = self.student(image) with torch.no_grad(): _, feature_teacher = self.teacher(image) # losses loss_ce = self.ce_loss_weight * F.cross_entropy(logits_student, target) loss_vid = 0 for i in range(len(feature_student["feats"][1:])): loss_vid += vid_loss( self.regressors[i], self.log_scales[i], feature_student["feats"][1:][i], feature_teacher["feats"][1:][i], self.eps, ) loss_vid = self.feat_loss_weight * loss_vid losses_dict = { "loss_ce": loss_ce, "loss_kd": loss_vid, } return logits_student, losses_dict ================================================ FILE: mdistiller/distillers/__init__.py ================================================ from ._base import Vanilla from .KD import KD from .AT import AT from .OFD import OFD from .RKD import RKD from .FitNet import FitNet from .KDSVD import KDSVD from .CRD import CRD from .NST import NST from .PKT import PKT from .SP import SP from .VID import VID from .ReviewKD import ReviewKD from .DKD import DKD distiller_dict = { "NONE": Vanilla, "KD": KD, "AT": AT, "OFD": OFD, "RKD": RKD, "FITNET": FitNet, "KDSVD": KDSVD, "CRD": CRD, "NST": NST, "PKT": PKT, "SP": SP, "VID": VID, "REVIEWKD": ReviewKD, "DKD": DKD, } ================================================ FILE: mdistiller/distillers/_base.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F class Distiller(nn.Module): def __init__(self, student, teacher): super(Distiller, self).__init__() self.student = student self.teacher = teacher def train(self, mode=True): # teacher as eval mode by default if not isinstance(mode, bool): raise ValueError("training mode is expected to be boolean") self.training = mode for module in self.children(): module.train(mode) self.teacher.eval() return self def get_learnable_parameters(self): # if the method introduces extra parameters, re-impl this function return [v for k, v in self.student.named_parameters()] def get_extra_parameters(self): # calculate the extra parameters introduced by the distiller return 0 def forward_train(self, **kwargs): # training function for the distillation method raise NotImplementedError() def forward_test(self, image): return self.student(image)[0] def forward(self, **kwargs): if self.training: return self.forward_train(**kwargs) return self.forward_test(kwargs["image"]) class Vanilla(nn.Module): def __init__(self, student): super(Vanilla, self).__init__() self.student = student def get_learnable_parameters(self): return [v for k, v in self.student.named_parameters()] def forward_train(self, image, target, **kwargs): logits_student, _ = self.student(image) loss = F.cross_entropy(logits_student, target) return logits_student, {"ce": loss} def forward(self, **kwargs): if self.training: return self.forward_train(**kwargs) return self.forward_test(kwargs["image"]) def forward_test(self, image): return self.student(image)[0] ================================================ FILE: mdistiller/distillers/_common.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F class ConvReg(nn.Module): """Convolutional regression""" def __init__(self, s_shape, t_shape, use_relu=True): super(ConvReg, self).__init__() self.use_relu = use_relu s_N, s_C, s_H, s_W = s_shape t_N, t_C, t_H, t_W = t_shape if s_H == 2 * t_H: self.conv = nn.Conv2d(s_C, t_C, kernel_size=3, stride=2, padding=1) elif s_H * 2 == t_H: self.conv = nn.ConvTranspose2d(s_C, t_C, kernel_size=4, stride=2, padding=1) elif s_H >= t_H: self.conv = nn.Conv2d(s_C, t_C, kernel_size=(1 + s_H - t_H, 1 + s_W - t_W)) else: raise NotImplemented("student size {}, teacher size {}".format(s_H, t_H)) self.bn = nn.BatchNorm2d(t_C) self.relu = nn.ReLU(inplace=True) def forward(self, x): x = self.conv(x) if self.use_relu: return self.relu(self.bn(x)) else: return self.bn(x) def get_feat_shapes(student, teacher, input_size): data = torch.randn(1, 3, *input_size) with torch.no_grad(): _, feat_s = student(data) _, feat_t = teacher(data) feat_s_shapes = [f.shape for f in feat_s["feats"]] feat_t_shapes = [f.shape for f in feat_t["feats"]] return feat_s_shapes, feat_t_shapes ================================================ FILE: mdistiller/engine/__init__.py ================================================ from .trainer import BaseTrainer, CRDTrainer, DOT, CRDDOT trainer_dict = { "base": BaseTrainer, "crd": CRDTrainer, "dot": DOT, "crd_dot": CRDDOT, } ================================================ FILE: mdistiller/engine/cfg.py ================================================ from yacs.config import CfgNode as CN from .utils import log_msg def show_cfg(cfg): dump_cfg = CN() dump_cfg.EXPERIMENT = cfg.EXPERIMENT dump_cfg.DATASET = cfg.DATASET dump_cfg.DISTILLER = cfg.DISTILLER dump_cfg.SOLVER = cfg.SOLVER dump_cfg.LOG = cfg.LOG if cfg.DISTILLER.TYPE in cfg: dump_cfg.update({cfg.DISTILLER.TYPE: cfg.get(cfg.DISTILLER.TYPE)}) print(log_msg("CONFIG:\n{}".format(dump_cfg.dump()), "INFO")) CFG = CN() # Experiment CFG.EXPERIMENT = CN() CFG.EXPERIMENT.PROJECT = "distill" CFG.EXPERIMENT.NAME = "" CFG.EXPERIMENT.TAG = "default" # Dataset CFG.DATASET = CN() CFG.DATASET.TYPE = "cifar100" CFG.DATASET.NUM_WORKERS = 2 CFG.DATASET.TEST = CN() CFG.DATASET.TEST.BATCH_SIZE = 64 # Distiller CFG.DISTILLER = CN() CFG.DISTILLER.TYPE = "NONE" # Vanilla as default CFG.DISTILLER.TEACHER = "ResNet50" CFG.DISTILLER.STUDENT = "resnet32" # Solver CFG.SOLVER = CN() CFG.SOLVER.TRAINER = "base" CFG.SOLVER.BATCH_SIZE = 64 CFG.SOLVER.EPOCHS = 240 CFG.SOLVER.LR = 0.05 CFG.SOLVER.LR_DECAY_STAGES = [150, 180, 210] CFG.SOLVER.LR_DECAY_RATE = 0.1 CFG.SOLVER.WEIGHT_DECAY = 0.0001 CFG.SOLVER.MOMENTUM = 0.9 CFG.SOLVER.TYPE = "SGD" # Log CFG.LOG = CN() CFG.LOG.TENSORBOARD_FREQ = 500 CFG.LOG.SAVE_CHECKPOINT_FREQ = 40 CFG.LOG.PREFIX = "./output" CFG.LOG.WANDB = True # Distillation Methods # KD CFG CFG.KD = CN() CFG.KD.TEMPERATURE = 4 CFG.KD.LOSS = CN() CFG.KD.LOSS.CE_WEIGHT = 0.1 CFG.KD.LOSS.KD_WEIGHT = 0.9 # AT CFG CFG.AT = CN() CFG.AT.P = 2 CFG.AT.LOSS = CN() CFG.AT.LOSS.CE_WEIGHT = 1.0 CFG.AT.LOSS.FEAT_WEIGHT = 1000.0 # RKD CFG CFG.RKD = CN() CFG.RKD.DISTANCE_WEIGHT = 25 CFG.RKD.ANGLE_WEIGHT = 50 CFG.RKD.LOSS = CN() CFG.RKD.LOSS.CE_WEIGHT = 1.0 CFG.RKD.LOSS.FEAT_WEIGHT = 1.0 CFG.RKD.PDIST = CN() CFG.RKD.PDIST.EPSILON = 1e-12 CFG.RKD.PDIST.SQUARED = False # FITNET CFG CFG.FITNET = CN() CFG.FITNET.HINT_LAYER = 2 # (0, 1, 2, 3, 4) CFG.FITNET.INPUT_SIZE = (32, 32) CFG.FITNET.LOSS = CN() CFG.FITNET.LOSS.CE_WEIGHT = 1.0 CFG.FITNET.LOSS.FEAT_WEIGHT = 100.0 # KDSVD CFG CFG.KDSVD = CN() CFG.KDSVD.K = 1 CFG.KDSVD.LOSS = CN() CFG.KDSVD.LOSS.CE_WEIGHT = 1.0 CFG.KDSVD.LOSS.FEAT_WEIGHT = 1.0 # OFD CFG CFG.OFD = CN() CFG.OFD.LOSS = CN() CFG.OFD.LOSS.CE_WEIGHT = 1.0 CFG.OFD.LOSS.FEAT_WEIGHT = 0.001 CFG.OFD.CONNECTOR = CN() CFG.OFD.CONNECTOR.KERNEL_SIZE = 1 # NST CFG CFG.NST = CN() CFG.NST.LOSS = CN() CFG.NST.LOSS.CE_WEIGHT = 1.0 CFG.NST.LOSS.FEAT_WEIGHT = 50.0 # PKT CFG CFG.PKT = CN() CFG.PKT.LOSS = CN() CFG.PKT.LOSS.CE_WEIGHT = 1.0 CFG.PKT.LOSS.FEAT_WEIGHT = 30000.0 # SP CFG CFG.SP = CN() CFG.SP.LOSS = CN() CFG.SP.LOSS.CE_WEIGHT = 1.0 CFG.SP.LOSS.FEAT_WEIGHT = 3000.0 # VID CFG CFG.VID = CN() CFG.VID.LOSS = CN() CFG.VID.LOSS.CE_WEIGHT = 1.0 CFG.VID.LOSS.FEAT_WEIGHT = 1.0 CFG.VID.EPS = 1e-5 CFG.VID.INIT_PRED_VAR = 5.0 CFG.VID.INPUT_SIZE = (32, 32) # CRD CFG CFG.CRD = CN() CFG.CRD.MODE = "exact" # ("exact", "relax") CFG.CRD.FEAT = CN() CFG.CRD.FEAT.DIM = 128 CFG.CRD.FEAT.STUDENT_DIM = 256 CFG.CRD.FEAT.TEACHER_DIM = 256 CFG.CRD.LOSS = CN() CFG.CRD.LOSS.CE_WEIGHT = 1.0 CFG.CRD.LOSS.FEAT_WEIGHT = 0.8 CFG.CRD.NCE = CN() CFG.CRD.NCE.K = 16384 CFG.CRD.NCE.MOMENTUM = 0.5 CFG.CRD.NCE.TEMPERATURE = 0.07 # ReviewKD CFG CFG.REVIEWKD = CN() CFG.REVIEWKD.CE_WEIGHT = 1.0 CFG.REVIEWKD.REVIEWKD_WEIGHT = 1.0 CFG.REVIEWKD.WARMUP_EPOCHS = 20 CFG.REVIEWKD.SHAPES = [1, 8, 16, 32] CFG.REVIEWKD.OUT_SHAPES = [1, 8, 16, 32] CFG.REVIEWKD.IN_CHANNELS = [64, 128, 256, 256] CFG.REVIEWKD.OUT_CHANNELS = [64, 128, 256, 256] CFG.REVIEWKD.MAX_MID_CHANNEL = 512 CFG.REVIEWKD.STU_PREACT = False # DKD(Decoupled Knowledge Distillation) CFG CFG.DKD = CN() CFG.DKD.CE_WEIGHT = 1.0 CFG.DKD.ALPHA = 1.0 CFG.DKD.BETA = 8.0 CFG.DKD.T = 4.0 CFG.DKD.WARMUP = 20 # DOT CFG CFG.SOLVER.DOT = CN() CFG.SOLVER.DOT.DELTA = 0.075 ================================================ FILE: mdistiller/engine/dot.py ================================================ import math import torch from torch import Tensor import torch.optim._functional as F from torch.optim.optimizer import Optimizer, required from typing import List, Optional def check_in(t, l): for i in l: if t is i: return True return False def dot(params: List[Tensor], d_p_list: List[Tensor], momentum_buffer_list: List[Optional[Tensor]], kd_grad_buffer: List[Optional[Tensor]], kd_momentum_buffer: List[Optional[Tensor]], kd_params: List[Tensor], *, weight_decay: float, momentum: float, momentum_kd: float, lr: float, dampening: float): for i, param in enumerate(params): d_p = d_p_list[i] if weight_decay != 0: d_p = d_p.add(param, alpha=weight_decay) if momentum != 0: buf = momentum_buffer_list[i] if buf is None: buf = torch.clone(d_p).detach() momentum_buffer_list[i] = buf elif check_in(param, kd_params): buf.mul_(momentum).add_(d_p, alpha=1 - dampening) else: buf.mul_((momentum_kd + momentum) / 2.).add_(d_p, alpha=1 - dampening) d_p = buf # update params with task-loss grad param.add_(d_p, alpha=-lr) for i, (d_p, buf, p) in enumerate(zip(kd_grad_buffer, kd_momentum_buffer, kd_params)): # update params with kd-loss grad if buf is None: buf = torch.clone(d_p).detach() kd_momentum_buffer[i] = buf elif check_in(p, params): buf.mul_(momentum_kd).add_(d_p, alpha=1 - dampening) else: if weight_decay != 0: d_p = d_p.add(p, alpha=weight_decay) buf.mul_((momentum_kd + momentum) / 2.).add_(d_p, alpha=1 - dampening) p.add_(buf, alpha=-lr) class DistillationOrientedTrainer(Optimizer): r""" Distillation-Oriented Trainer Usage: ... optimizer = DistillationOrientedTrainer() optimizer.zero_grad(set_to_none=True) loss_kd.backward(retain_graph=True) optimizer.step_kd() # get kd-grad and update kd-momentum optimizer.zero_grad(set_to_none=True) loss_task.backward() optimizer.step() # get task-grad and update tast-momentum, then update params. ... """ def __init__( self, params, lr=required, momentum=0, momentum_kd=0, dampening=0, weight_decay=0): if lr is not required and lr < 0.0: raise ValueError("Invalid learning rate: {}".format(lr)) if momentum < 0.0: raise ValueError("Invalid momentum value: {}".format(momentum)) if momentum_kd < 0.0: raise ValueError("Invalid momentum kd value: {}".format(momentum_kd)) if weight_decay < 0.0: raise ValueError("Invalid weight_decay value: {}".format(weight_decay)) defaults = dict(lr=lr, momentum=momentum, momentum_kd=momentum_kd, dampening=dampening, weight_decay=weight_decay) self.kd_grad_buffer = [] self.kd_grad_params = [] self.kd_momentum_buffer = [] super(DistillationOrientedTrainer, self).__init__(params, defaults) @torch.no_grad() def step_kd(self, closure=None): loss = None if closure is not None: with torch.enable_grad(): loss = closure() assert len(self.param_groups) == 1, "Only implement for one-group params." for group in self.param_groups: params_with_grad = [] d_p_list = [] momentum_kd_buffer_list = [] weight_decay = group['weight_decay'] dampening = group['dampening'] lr = group['lr'] for p in group['params']: if p.grad is not None: params_with_grad.append(p) d_p_list.append(p.grad) state = self.state[p] if 'momentum_kd_buffer' not in state: momentum_kd_buffer_list.append(None) else: momentum_kd_buffer_list.append(state['momentum_kd_buffer']) self.kd_momentum_buffer = momentum_kd_buffer_list self.kd_grad_buffer = d_p_list self.kd_grad_params = params_with_grad return loss @torch.no_grad() def step(self, closure=None): loss = None if closure is not None: with torch.enable_grad(): loss = closure() assert len(self.param_groups) == 1, "Only implement for one-group params." for group in self.param_groups: params_with_grad = [] d_p_list = [] momentum_buffer_list = [] weight_decay = group['weight_decay'] momentum = group['momentum'] momentum_kd = group['momentum_kd'] dampening = group['dampening'] lr = group['lr'] for p in group['params']: if p.grad is not None: params_with_grad.append(p) d_p_list.append(p.grad) state = self.state[p] if 'momentum_buffer' not in state: momentum_buffer_list.append(None) else: momentum_buffer_list.append(state['momentum_buffer']) dot(params_with_grad, d_p_list, momentum_buffer_list, self.kd_grad_buffer, self.kd_momentum_buffer, self.kd_grad_params, weight_decay=weight_decay, momentum=momentum, momentum_kd=momentum_kd, lr=lr, dampening=dampening) # update momentum_buffers in state for p, momentum_buffer in zip(params_with_grad, momentum_buffer_list): state = self.state[p] state['momentum_buffer'] = momentum_buffer for p, momentum_kd_buffer in zip(self.kd_grad_params, self.kd_momentum_buffer): state = self.state[p] state['momentum_kd_buffer'] = momentum_kd_buffer self.kd_grad_buffer = [] self.kd_grad_params = [] self.kd_momentum_buffer = [] return loss ================================================ FILE: mdistiller/engine/trainer.py ================================================ import os import time from tqdm import tqdm import torch import torch.nn as nn import torch.optim as optim from collections import OrderedDict import getpass from tensorboardX import SummaryWriter from .utils import ( AverageMeter, accuracy, validate, adjust_learning_rate, save_checkpoint, load_checkpoint, log_msg, ) from .dot import DistillationOrientedTrainer class BaseTrainer(object): def __init__(self, experiment_name, distiller, train_loader, val_loader, cfg): self.cfg = cfg self.distiller = distiller self.train_loader = train_loader self.val_loader = val_loader self.optimizer = self.init_optimizer(cfg) self.best_acc = -1 username = getpass.getuser() # init loggers self.log_path = os.path.join(cfg.LOG.PREFIX, experiment_name) if not os.path.exists(self.log_path): os.makedirs(self.log_path) self.tf_writer = SummaryWriter(os.path.join(self.log_path, "train.events")) def init_optimizer(self, cfg): if cfg.SOLVER.TYPE == "SGD": optimizer = optim.SGD( self.distiller.module.get_learnable_parameters(), lr=cfg.SOLVER.LR, momentum=cfg.SOLVER.MOMENTUM, weight_decay=cfg.SOLVER.WEIGHT_DECAY, ) else: raise NotImplementedError(cfg.SOLVER.TYPE) return optimizer def log(self, lr, epoch, log_dict): # tensorboard log for k, v in log_dict.items(): self.tf_writer.add_scalar(k, v, epoch) self.tf_writer.flush() # wandb log if self.cfg.LOG.WANDB: import wandb wandb.log({"current lr": lr}) wandb.log(log_dict) if log_dict["test_acc"] > self.best_acc: self.best_acc = log_dict["test_acc"] if self.cfg.LOG.WANDB: wandb.run.summary["best_acc"] = self.best_acc # worklog.txt with open(os.path.join(self.log_path, "worklog.txt"), "a") as writer: lines = [ "-" * 25 + os.linesep, "epoch: {}".format(epoch) + os.linesep, "lr: {:.2f}".format(float(lr)) + os.linesep, ] for k, v in log_dict.items(): lines.append("{}: {:.2f}".format(k, v) + os.linesep) lines.append("-" * 25 + os.linesep) writer.writelines(lines) def train(self, resume=False): epoch = 1 if resume: state = load_checkpoint(os.path.join(self.log_path, "latest")) epoch = state["epoch"] + 1 self.distiller.load_state_dict(state["model"]) self.optimizer.load_state_dict(state["optimizer"]) self.best_acc = state["best_acc"] while epoch < self.cfg.SOLVER.EPOCHS + 1: self.train_epoch(epoch) epoch += 1 print(log_msg("Best accuracy:{}".format(self.best_acc), "EVAL")) with open(os.path.join(self.log_path, "worklog.txt"), "a") as writer: writer.write("best_acc\t" + "{:.2f}".format(float(self.best_acc))) def train_epoch(self, epoch): lr = adjust_learning_rate(epoch, self.cfg, self.optimizer) train_meters = { "training_time": AverageMeter(), "data_time": AverageMeter(), "losses": AverageMeter(), "top1": AverageMeter(), "top5": AverageMeter(), } num_iter = len(self.train_loader) pbar = tqdm(range(num_iter)) # train loops self.distiller.train() for idx, data in enumerate(self.train_loader): msg = self.train_iter(data, epoch, train_meters) pbar.set_description(log_msg(msg, "TRAIN")) pbar.update() pbar.close() # validate test_acc, test_acc_top5, test_loss = validate(self.val_loader, self.distiller) # log log_dict = OrderedDict( { "train_acc": train_meters["top1"].avg, "train_loss": train_meters["losses"].avg, "test_acc": test_acc, "test_acc_top5": test_acc_top5, "test_loss": test_loss, } ) self.log(lr, epoch, log_dict) # saving checkpoint state = { "epoch": epoch, "model": self.distiller.state_dict(), "optimizer": self.optimizer.state_dict(), "best_acc": self.best_acc, } student_state = {"model": self.distiller.module.student.state_dict()} save_checkpoint(state, os.path.join(self.log_path, "latest")) save_checkpoint( student_state, os.path.join(self.log_path, "student_latest") ) if epoch % self.cfg.LOG.SAVE_CHECKPOINT_FREQ == 0: save_checkpoint( state, os.path.join(self.log_path, "epoch_{}".format(epoch)) ) save_checkpoint( student_state, os.path.join(self.log_path, "student_{}".format(epoch)), ) # update the best if test_acc >= self.best_acc: save_checkpoint(state, os.path.join(self.log_path, "best")) save_checkpoint( student_state, os.path.join(self.log_path, "student_best") ) def train_iter(self, data, epoch, train_meters): self.optimizer.zero_grad() train_start_time = time.time() image, target, index = data train_meters["data_time"].update(time.time() - train_start_time) image = image.float() image = image.cuda(non_blocking=True) target = target.cuda(non_blocking=True) index = index.cuda(non_blocking=True) # forward preds, losses_dict = self.distiller(image=image, target=target, epoch=epoch) # backward loss = sum([l.mean() for l in losses_dict.values()]) loss.backward() self.optimizer.step() train_meters["training_time"].update(time.time() - train_start_time) # collect info batch_size = image.size(0) acc1, acc5 = accuracy(preds, target, topk=(1, 5)) train_meters["losses"].update(loss.cpu().detach().numpy().mean(), batch_size) train_meters["top1"].update(acc1[0], batch_size) train_meters["top5"].update(acc5[0], batch_size) # print info msg = "Epoch:{}| Time(data):{:.3f}| Time(train):{:.3f}| Loss:{:.4f}| Top-1:{:.3f}| Top-5:{:.3f}".format( epoch, train_meters["data_time"].avg, train_meters["training_time"].avg, train_meters["losses"].avg, train_meters["top1"].avg, train_meters["top5"].avg, ) return msg class CRDTrainer(BaseTrainer): def train_iter(self, data, epoch, train_meters): self.optimizer.zero_grad() train_start_time = time.time() image, target, index, contrastive_index = data train_meters["data_time"].update(time.time() - train_start_time) image = image.float() image = image.cuda(non_blocking=True) target = target.cuda(non_blocking=True) index = index.cuda(non_blocking=True) contrastive_index = contrastive_index.cuda(non_blocking=True) # forward preds, losses_dict = self.distiller( image=image, target=target, index=index, contrastive_index=contrastive_index ) # backward loss = sum([l.mean() for l in losses_dict.values()]) loss.backward() self.optimizer.step() train_meters["training_time"].update(time.time() - train_start_time) # collect info batch_size = image.size(0) acc1, acc5 = accuracy(preds, target, topk=(1, 5)) train_meters["losses"].update(loss.cpu().detach().numpy().mean(), batch_size) train_meters["top1"].update(acc1[0], batch_size) train_meters["top5"].update(acc5[0], batch_size) # print info msg = "Epoch:{}| Time(data):{:.3f}| Time(train):{:.3f}| Loss:{:.4f}| Top-1:{:.3f}| Top-5:{:.3f}".format( epoch, train_meters["data_time"].avg, train_meters["training_time"].avg, train_meters["losses"].avg, train_meters["top1"].avg, train_meters["top5"].avg, ) return msg class DOT(BaseTrainer): def init_optimizer(self, cfg): if cfg.SOLVER.TYPE == "SGD": m_task = cfg.SOLVER.MOMENTUM - cfg.SOLVER.DOT.DELTA m_kd = cfg.SOLVER.MOMENTUM + cfg.SOLVER.DOT.DELTA optimizer = DistillationOrientedTrainer( self.distiller.module.get_learnable_parameters(), lr=cfg.SOLVER.LR, momentum=m_task, momentum_kd=m_kd, weight_decay=cfg.SOLVER.WEIGHT_DECAY, ) else: raise NotImplementedError(cfg.SOLVER.TYPE) return optimizer def train(self, resume=False): epoch = 1 if resume: state = load_checkpoint(os.path.join(self.log_path, "latest")) epoch = state["epoch"] + 1 self.distiller.load_state_dict(state["model"]) self.optimizer.load_state_dict(state["optimizer"]) self.best_acc = state["best_acc"] while epoch < self.cfg.SOLVER.EPOCHS + 1: self.train_epoch(epoch) epoch += 1 print(log_msg("Best accuracy:{}".format(self.best_acc), "EVAL")) with open(os.path.join(self.log_path, "worklog.txt"), "a") as writer: writer.write("best_acc\t" + "{:.2f}".format(float(self.best_acc))) def train_iter(self, data, epoch, train_meters): train_start_time = time.time() image, target, index = data train_meters["data_time"].update(time.time() - train_start_time) image = image.float() image = image.cuda(non_blocking=True) target = target.cuda(non_blocking=True) index = index.cuda(non_blocking=True) # forward preds, losses_dict = self.distiller(image=image, target=target, epoch=epoch) # dot backward loss_ce, loss_kd = losses_dict['loss_ce'].mean(), losses_dict['loss_kd'].mean() self.optimizer.zero_grad(set_to_none=True) loss_kd.backward(retain_graph=True) self.optimizer.step_kd() self.optimizer.zero_grad(set_to_none=True) loss_ce.backward() self.optimizer.step() train_meters["training_time"].update(time.time() - train_start_time) # collect info batch_size = image.size(0) acc1, acc5 = accuracy(preds, target, topk=(1, 5)) train_meters["losses"].update((loss_ce + loss_kd).cpu().detach().numpy().mean(), batch_size) train_meters["top1"].update(acc1[0], batch_size) train_meters["top5"].update(acc5[0], batch_size) # print info msg = "Epoch:{}| Time(data):{:.3f}| Time(train):{:.3f}| Loss:{:.4f}| Top-1:{:.3f}| Top-5:{:.3f}".format( epoch, train_meters["data_time"].avg, train_meters["training_time"].avg, train_meters["losses"].avg, train_meters["top1"].avg, train_meters["top5"].avg, ) return msg class CRDDOT(BaseTrainer): def init_optimizer(self, cfg): if cfg.SOLVER.TYPE == "SGD": m_task = cfg.SOLVER.MOMENTUM - cfg.SOLVER.DOT.DELTA m_kd = cfg.SOLVER.MOMENTUM + cfg.SOLVER.DOT.DELTA optimizer = DistillationOrientedTrainer( self.distiller.module.get_learnable_parameters(), lr=cfg.SOLVER.LR, momentum=m_task, momentum_kd=m_kd, weight_decay=cfg.SOLVER.WEIGHT_DECAY, ) else: raise NotImplementedError(cfg.SOLVER.TYPE) return optimizer def train(self, resume=False): epoch = 1 if resume: state = load_checkpoint(os.path.join(self.log_path, "latest")) epoch = state["epoch"] + 1 self.distiller.load_state_dict(state["model"]) self.optimizer.load_state_dict(state["optimizer"]) self.best_acc = state["best_acc"] while epoch < self.cfg.SOLVER.EPOCHS + 1: self.train_epoch(epoch) epoch += 1 print(log_msg("Best accuracy:{}".format(self.best_acc), "EVAL")) with open(os.path.join(self.log_path, "worklog.txt"), "a") as writer: writer.write("best_acc\t" + "{:.2f}".format(float(self.best_acc))) def train_iter(self, data, epoch, train_meters): self.optimizer.zero_grad() train_start_time = time.time() image, target, index, contrastive_index = data train_meters["data_time"].update(time.time() - train_start_time) image = image.float() image = image.cuda(non_blocking=True) target = target.cuda(non_blocking=True) index = index.cuda(non_blocking=True) contrastive_index = contrastive_index.cuda(non_blocking=True) # forward preds, losses_dict = self.distiller( image=image, target=target, index=index, contrastive_index=contrastive_index ) # dot backward loss_ce, loss_kd = losses_dict['loss_ce'].mean(), losses_dict['loss_kd'].mean() self.optimizer.zero_grad(set_to_none=True) loss_kd.backward(retain_graph=True) self.optimizer.step_kd() self.optimizer.zero_grad(set_to_none=True) loss_ce.backward() # self.optimizer.step((1 - epoch / 240.)) self.optimizer.step() train_meters["training_time"].update(time.time() - train_start_time) # collect info batch_size = image.size(0) acc1, acc5 = accuracy(preds, target, topk=(1, 5)) train_meters["losses"].update((loss_ce + loss_kd).cpu().detach().numpy().mean(), batch_size) train_meters["top1"].update(acc1[0], batch_size) train_meters["top5"].update(acc5[0], batch_size) # print info msg = "Epoch:{}| Time(data):{:.3f}| Time(train):{:.3f}| Loss:{:.4f}| Top-1:{:.3f}| Top-5:{:.3f}".format( epoch, train_meters["data_time"].avg, train_meters["training_time"].avg, train_meters["losses"].avg, train_meters["top1"].avg, train_meters["top5"].avg, ) return msg ================================================ FILE: mdistiller/engine/utils.py ================================================ import os import torch import torch.nn as nn import numpy as np import sys import time from tqdm import tqdm class AverageMeter(object): """Computes and stores the average and current value""" def __init__(self): self.reset() def reset(self): self.val = 0 self.avg = 0 self.sum = 0 self.count = 0 def update(self, val, n=1): self.val = val self.sum += val * n self.count += n self.avg = self.sum / self.count def validate(val_loader, distiller): batch_time, losses, top1, top5 = [AverageMeter() for _ in range(4)] criterion = nn.CrossEntropyLoss() num_iter = len(val_loader) pbar = tqdm(range(num_iter)) distiller.eval() with torch.no_grad(): start_time = time.time() for idx, (image, target) in enumerate(val_loader): image = image.float() image = image.cuda(non_blocking=True) target = target.cuda(non_blocking=True) output = distiller(image=image) loss = criterion(output, target) acc1, acc5 = accuracy(output, target, topk=(1, 5)) batch_size = image.size(0) losses.update(loss.cpu().detach().numpy().mean(), batch_size) top1.update(acc1[0], batch_size) top5.update(acc5[0], batch_size) # measure elapsed time batch_time.update(time.time() - start_time) start_time = time.time() msg = "Top-1:{top1.avg:.3f}| Top-5:{top5.avg:.3f}".format( top1=top1, top5=top5 ) pbar.set_description(log_msg(msg, "EVAL")) pbar.update() pbar.close() return top1.avg, top5.avg, losses.avg def log_msg(msg, mode="INFO"): color_map = { "INFO": 36, "TRAIN": 32, "EVAL": 31, } msg = "\033[{}m[{}] {}\033[0m".format(color_map[mode], mode, msg) return msg def adjust_learning_rate(epoch, cfg, optimizer): steps = np.sum(epoch > np.asarray(cfg.SOLVER.LR_DECAY_STAGES)) if steps > 0: new_lr = cfg.SOLVER.LR * (cfg.SOLVER.LR_DECAY_RATE**steps) for param_group in optimizer.param_groups: param_group["lr"] = new_lr return new_lr return cfg.SOLVER.LR def accuracy(output, target, topk=(1,)): with torch.no_grad(): maxk = max(topk) batch_size = target.size(0) _, pred = output.topk(maxk, 1, True, True) pred = pred.t() correct = pred.eq(target.reshape(1, -1).expand_as(pred)) res = [] for k in topk: correct_k = correct[:k].reshape(-1).float().sum(0, keepdim=True) res.append(correct_k.mul_(100.0 / batch_size)) return res def save_checkpoint(obj, path): with open(path, "wb") as f: torch.save(obj, f) def load_checkpoint(path): with open(path, "rb") as f: return torch.load(f, map_location="cpu") ================================================ FILE: mdistiller/models/__init__.py ================================================ from .cifar import cifar_model_dict, tiny_imagenet_model_dict from .imagenet import imagenet_model_dict ================================================ FILE: mdistiller/models/cifar/ShuffleNetv1.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F class ShuffleBlock(nn.Module): def __init__(self, groups): super(ShuffleBlock, self).__init__() self.groups = groups def forward(self, x): """Channel shuffle: [N,C,H,W] -> [N,g,C/g,H,W] -> [N,C/g,g,H,w] -> [N,C,H,W]""" N, C, H, W = x.size() g = self.groups return x.reshape(N, g, C // g, H, W).permute(0, 2, 1, 3, 4).reshape(N, C, H, W) class Bottleneck(nn.Module): def __init__(self, in_planes, out_planes, stride, groups, is_last=False): super(Bottleneck, self).__init__() self.is_last = is_last self.stride = stride mid_planes = int(out_planes / 4) g = 1 if in_planes == 24 else groups self.conv1 = nn.Conv2d( in_planes, mid_planes, kernel_size=1, groups=g, bias=False ) self.bn1 = nn.BatchNorm2d(mid_planes) self.shuffle1 = ShuffleBlock(groups=g) self.conv2 = nn.Conv2d( mid_planes, mid_planes, kernel_size=3, stride=stride, padding=1, groups=mid_planes, bias=False, ) self.bn2 = nn.BatchNorm2d(mid_planes) self.conv3 = nn.Conv2d( mid_planes, out_planes, kernel_size=1, groups=groups, bias=False ) self.bn3 = nn.BatchNorm2d(out_planes) self.shortcut = nn.Sequential() if stride == 2: self.shortcut = nn.Sequential(nn.AvgPool2d(3, stride=2, padding=1)) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = self.shuffle1(out) out = F.relu(self.bn2(self.conv2(out))) out = self.bn3(self.conv3(out)) res = self.shortcut(x) preact = torch.cat([out, res], 1) if self.stride == 2 else out + res out = F.relu(preact) # out = F.relu(torch.cat([out, res], 1)) if self.stride == 2 else F.relu(out+res) if self.is_last: return out, preact else: return out class ShuffleNet(nn.Module): def __init__(self, cfg, num_classes=10): super(ShuffleNet, self).__init__() out_planes = cfg["out_planes"] num_blocks = cfg["num_blocks"] groups = cfg["groups"] self.conv1 = nn.Conv2d(3, 24, kernel_size=1, bias=False) self.bn1 = nn.BatchNorm2d(24) self.in_planes = 24 self.layer1 = self._make_layer(out_planes[0], num_blocks[0], groups) self.layer2 = self._make_layer(out_planes[1], num_blocks[1], groups) self.layer3 = self._make_layer(out_planes[2], num_blocks[2], groups) self.linear = nn.Linear(out_planes[2], num_classes) # self.stage_channels = out_channels def _make_layer(self, out_planes, num_blocks, groups): layers = [] for i in range(num_blocks): stride = 2 if i == 0 else 1 cat_planes = self.in_planes if i == 0 else 0 layers.append( Bottleneck( self.in_planes, out_planes - cat_planes, stride=stride, groups=groups, is_last=(i == num_blocks - 1), ) ) self.in_planes = out_planes return nn.Sequential(*layers) def get_feat_modules(self): feat_m = nn.ModuleList([]) feat_m.append(self.conv1) feat_m.append(self.bn1) feat_m.append(self.layer1) feat_m.append(self.layer2) feat_m.append(self.layer3) return feat_m def get_bn_before_relu(self): raise NotImplementedError( 'ShuffleNet currently is not supported for "Overhaul" teacher' ) def forward( self, x, ): out = F.relu(self.bn1(self.conv1(x))) f0 = out out, f1_pre = self.layer1(out) f1 = out out, f2_pre = self.layer2(out) f2 = out out, f3_pre = self.layer3(out) f3 = out out = F.avg_pool2d(out, 4) out = out.reshape(out.size(0), -1) f4 = out out = self.linear(out) feats = {} feats["feats"] = [f0, f1, f2, f3] feats["preact_feats"] = [f0, f1_pre, f2_pre, f3_pre] feats["pooled_feat"] = f4 return out, feats def ShuffleV1(**kwargs): cfg = {"out_planes": [240, 480, 960], "num_blocks": [4, 8, 4], "groups": 3} return ShuffleNet(cfg, **kwargs) if __name__ == "__main__": x = torch.randn(2, 3, 32, 32) net = ShuffleV1(num_classes=100) import time a = time.time() logit, feats = net(x) b = time.time() print(b - a) for f in feats["feats"]: print(f.shape, f.min().item()) print(logit.shape) ================================================ FILE: mdistiller/models/cifar/ShuffleNetv2.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F class ShuffleBlock(nn.Module): def __init__(self, groups=2): super(ShuffleBlock, self).__init__() self.groups = groups def forward(self, x): """Channel shuffle: [N,C,H,W] -> [N,g,C/g,H,W] -> [N,C/g,g,H,w] -> [N,C,H,W]""" N, C, H, W = x.size() g = self.groups return x.reshape(N, g, C // g, H, W).permute(0, 2, 1, 3, 4).reshape(N, C, H, W) class SplitBlock(nn.Module): def __init__(self, ratio): super(SplitBlock, self).__init__() self.ratio = ratio def forward(self, x): c = int(x.size(1) * self.ratio) return x[:, :c, :, :], x[:, c:, :, :] class BasicBlock(nn.Module): def __init__(self, in_channels, split_ratio=0.5, is_last=False): super(BasicBlock, self).__init__() self.is_last = is_last self.split = SplitBlock(split_ratio) in_channels = int(in_channels * split_ratio) self.conv1 = nn.Conv2d(in_channels, in_channels, kernel_size=1, bias=False) self.bn1 = nn.BatchNorm2d(in_channels) self.conv2 = nn.Conv2d( in_channels, in_channels, kernel_size=3, stride=1, padding=1, groups=in_channels, bias=False, ) self.bn2 = nn.BatchNorm2d(in_channels) self.conv3 = nn.Conv2d(in_channels, in_channels, kernel_size=1, bias=False) self.bn3 = nn.BatchNorm2d(in_channels) self.shuffle = ShuffleBlock() def forward(self, x): x1, x2 = self.split(x) out = F.relu(self.bn1(self.conv1(x2))) out = self.bn2(self.conv2(out)) preact = self.bn3(self.conv3(out)) out = F.relu(preact) # out = F.relu(self.bn3(self.conv3(out))) preact = torch.cat([x1, preact], 1) out = torch.cat([x1, out], 1) out = self.shuffle(out) if self.is_last: return out, preact else: return out class DownBlock(nn.Module): def __init__(self, in_channels, out_channels): super(DownBlock, self).__init__() mid_channels = out_channels // 2 # left self.conv1 = nn.Conv2d( in_channels, in_channels, kernel_size=3, stride=2, padding=1, groups=in_channels, bias=False, ) self.bn1 = nn.BatchNorm2d(in_channels) self.conv2 = nn.Conv2d(in_channels, mid_channels, kernel_size=1, bias=False) self.bn2 = nn.BatchNorm2d(mid_channels) # right self.conv3 = nn.Conv2d(in_channels, mid_channels, kernel_size=1, bias=False) self.bn3 = nn.BatchNorm2d(mid_channels) self.conv4 = nn.Conv2d( mid_channels, mid_channels, kernel_size=3, stride=2, padding=1, groups=mid_channels, bias=False, ) self.bn4 = nn.BatchNorm2d(mid_channels) self.conv5 = nn.Conv2d(mid_channels, mid_channels, kernel_size=1, bias=False) self.bn5 = nn.BatchNorm2d(mid_channels) self.shuffle = ShuffleBlock() def forward(self, x): # left out1 = self.bn1(self.conv1(x)) out1 = F.relu(self.bn2(self.conv2(out1))) # right out2 = F.relu(self.bn3(self.conv3(x))) out2 = self.bn4(self.conv4(out2)) out2 = F.relu(self.bn5(self.conv5(out2))) # concat out = torch.cat([out1, out2], 1) out = self.shuffle(out) return out class ShuffleNetV2(nn.Module): def __init__(self, net_size, num_classes=10): super(ShuffleNetV2, self).__init__() out_channels = configs[net_size]["out_channels"] num_blocks = configs[net_size]["num_blocks"] # self.conv1 = nn.Conv2d(3, 24, kernel_size=3, # stride=1, padding=1, bias=False) self.conv1 = nn.Conv2d(3, 24, kernel_size=1, bias=False) self.bn1 = nn.BatchNorm2d(24) self.in_channels = 24 self.layer1 = self._make_layer(out_channels[0], num_blocks[0]) self.layer2 = self._make_layer(out_channels[1], num_blocks[1]) self.layer3 = self._make_layer(out_channels[2], num_blocks[2]) self.conv2 = nn.Conv2d( out_channels[2], out_channels[3], kernel_size=1, stride=1, padding=0, bias=False, ) self.bn2 = nn.BatchNorm2d(out_channels[3]) self.linear = nn.Linear(out_channels[3], num_classes) self.stage_channels = out_channels def _make_layer(self, out_channels, num_blocks): layers = [DownBlock(self.in_channels, out_channels)] for i in range(num_blocks): layers.append(BasicBlock(out_channels, is_last=(i == num_blocks - 1))) self.in_channels = out_channels return nn.Sequential(*layers) def get_feat_modules(self): feat_m = nn.ModuleList([]) feat_m.append(self.conv1) feat_m.append(self.bn1) feat_m.append(self.layer1) feat_m.append(self.layer2) feat_m.append(self.layer3) return feat_m def get_bn_before_relu(self): raise NotImplementedError( 'ShuffleNetV2 currently is not supported for "Overhaul" teacher' ) def get_stage_channels(self): return [24] + list(self.stage_channels[:-1]) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) # out = F.max_pool2d(out, 3, stride=2, padding=1) f0 = out out, f1_pre = self.layer1(out) f1 = out out, f2_pre = self.layer2(out) f2 = out out, f3_pre = self.layer3(out) f3 = out out = F.relu(self.bn2(self.conv2(out))) out = F.avg_pool2d(out, 4) out = out.reshape(out.size(0), -1) avg = out f4 = out out = self.linear(out) feats = {} feats["feats"] = [f0, f1, f2, f3] feats["preact_feats"] = [f0, f1_pre, f2_pre, f3_pre] feats["pooled_feat"] = f4 return out, feats configs = { 0.2: {"out_channels": (40, 80, 160, 512), "num_blocks": (3, 3, 3)}, 0.3: {"out_channels": (40, 80, 160, 512), "num_blocks": (3, 7, 3)}, 0.5: {"out_channels": (48, 96, 192, 1024), "num_blocks": (3, 7, 3)}, 1: {"out_channels": (116, 232, 464, 1024), "num_blocks": (3, 7, 3)}, 1.5: {"out_channels": (176, 352, 704, 1024), "num_blocks": (3, 7, 3)}, 2: {"out_channels": (224, 488, 976, 2048), "num_blocks": (3, 7, 3)}, } def ShuffleV2(**kwargs): model = ShuffleNetV2(net_size=1, **kwargs) return model if __name__ == "__main__": net = ShuffleV2(num_classes=100) x = torch.randn(3, 3, 32, 32) import time a = time.time() logit, feats = net(x) b = time.time() print(b - a) for f in feats["feats"]: print(f.shape, f.min().item()) print(logit.shape) ================================================ FILE: mdistiller/models/cifar/__init__.py ================================================ import os from .resnet import ( resnet8, resnet14, resnet20, resnet32, resnet44, resnet56, resnet110, resnet8x4, resnet32x4, ) from .resnetv2 import ResNet50, ResNet18 from .wrn import wrn_16_1, wrn_16_2, wrn_40_1, wrn_40_2 from .vgg import vgg19_bn, vgg16_bn, vgg13_bn, vgg11_bn, vgg8_bn from .mobilenetv2 import mobile_half from .ShuffleNetv1 import ShuffleV1 from .ShuffleNetv2 import ShuffleV2 from .mv2_tinyimagenet import mobilenetv2_tinyimagenet cifar100_model_prefix = os.path.join( os.path.dirname(os.path.abspath(__file__)), "../../../download_ckpts/cifar_teachers/" ) tiny_imagenet_model_prefix = os.path.join( os.path.dirname(os.path.abspath(__file__)), "../../../download_ckpts/tiny_imagenet_teachers/" ) cifar_model_dict = { # teachers "resnet56": ( resnet56, cifar100_model_prefix + "resnet56_vanilla/ckpt_epoch_240.pth", ), "resnet110": ( resnet110, cifar100_model_prefix + "resnet110_vanilla/ckpt_epoch_240.pth", ), "resnet32x4": ( resnet32x4, cifar100_model_prefix + "resnet32x4_vanilla/ckpt_epoch_240.pth", ), "ResNet50": ( ResNet50, cifar100_model_prefix + "ResNet50_vanilla/ckpt_epoch_240.pth", ), "wrn_40_2": ( wrn_40_2, cifar100_model_prefix + "wrn_40_2_vanilla/ckpt_epoch_240.pth", ), "vgg13": (vgg13_bn, cifar100_model_prefix + "vgg13_vanilla/ckpt_epoch_240.pth"), # students "resnet8": (resnet8, None), "resnet14": (resnet14, None), "resnet20": (resnet20, None), "resnet32": (resnet32, None), "resnet44": (resnet44, None), "resnet8x4": (resnet8x4, None), "ResNet18": (ResNet18, None), "wrn_16_1": (wrn_16_1, None), "wrn_16_2": (wrn_16_2, None), "wrn_40_1": (wrn_40_1, None), "vgg8": (vgg8_bn, None), "vgg11": (vgg11_bn, None), "vgg16": (vgg16_bn, None), "vgg19": (vgg19_bn, None), "MobileNetV2": (mobile_half, None), "ShuffleV1": (ShuffleV1, None), "ShuffleV2": (ShuffleV2, None), } tiny_imagenet_model_dict = { "ResNet18": (ResNet18, tiny_imagenet_model_prefix + "ResNet18_vanilla/ti_res18"), "MobileNetV2": (mobilenetv2_tinyimagenet, None), "ShuffleV2": (ShuffleV2, None), } ================================================ FILE: mdistiller/models/cifar/mobilenetv2.py ================================================ import torch import torch.nn as nn import math __all__ = ["mobilenetv2_T_w", "mobile_half"] BN = None def conv_bn(inp, oup, stride): return nn.Sequential( nn.Conv2d(inp, oup, 3, stride, 1, bias=False), nn.BatchNorm2d(oup), nn.ReLU(inplace=True), ) def conv_1x1_bn(inp, oup): return nn.Sequential( nn.Conv2d(inp, oup, 1, 1, 0, bias=False), nn.BatchNorm2d(oup), nn.ReLU(inplace=True), ) class InvertedResidual(nn.Module): def __init__(self, inp, oup, stride, expand_ratio): super(InvertedResidual, self).__init__() self.blockname = None self.stride = stride assert stride in [1, 2] self.use_res_connect = self.stride == 1 and inp == oup self.conv = nn.Sequential( # pw nn.Conv2d(inp, inp * expand_ratio, 1, 1, 0, bias=False), nn.BatchNorm2d(inp * expand_ratio), nn.ReLU(inplace=True), # dw nn.Conv2d( inp * expand_ratio, inp * expand_ratio, 3, stride, 1, groups=inp * expand_ratio, bias=False, ), nn.BatchNorm2d(inp * expand_ratio), nn.ReLU(inplace=True), # pw-linear nn.Conv2d(inp * expand_ratio, oup, 1, 1, 0, bias=False), nn.BatchNorm2d(oup), ) self.names = ["0", "1", "2", "3", "4", "5", "6", "7"] def forward(self, x): t = x if self.use_res_connect: return t + self.conv(x) else: return self.conv(x) class MobileNetV2(nn.Module): """mobilenetV2""" def __init__(self, T, feature_dim, input_size=32, width_mult=1.0, remove_avg=False): super(MobileNetV2, self).__init__() self.remove_avg = remove_avg # setting of inverted residual blocks self.interverted_residual_setting = [ # t, c, n, s [1, 16, 1, 1], [T, 24, 2, 1], [T, 32, 3, 2], [T, 64, 4, 2], [T, 96, 3, 1], [T, 160, 3, 2], [T, 320, 1, 1], ] # building first layer assert input_size % 32 == 0 input_channel = int(32 * width_mult) self.conv1 = conv_bn(3, input_channel, 2) # building inverted residual blocks self.blocks = nn.ModuleList([]) for t, c, n, s in self.interverted_residual_setting: output_channel = int(c * width_mult) layers = [] strides = [s] + [1] * (n - 1) for stride in strides: layers.append( InvertedResidual(input_channel, output_channel, stride, t) ) input_channel = output_channel self.blocks.append(nn.Sequential(*layers)) self.last_channel = int(1280 * width_mult) if width_mult > 1.0 else 1280 self.conv2 = conv_1x1_bn(input_channel, self.last_channel) # building classifier self.classifier = nn.Sequential( # nn.Dropout(0.5), nn.Linear(self.last_channel, feature_dim), ) H = input_size // (32 // 2) self.avgpool = nn.AvgPool2d(H, ceil_mode=True) self._initialize_weights() print(T, width_mult) self.stage_channels = [32, 24, 32, 96, 320] self.stage_channels = [int(c * width_mult) for c in self.stage_channels] def get_bn_before_relu(self): bn1 = self.blocks[1][-1].conv[-1] bn2 = self.blocks[2][-1].conv[-1] bn3 = self.blocks[4][-1].conv[-1] bn4 = self.blocks[6][-1].conv[-1] return [bn1, bn2, bn3, bn4] def get_feat_modules(self): feat_m = nn.ModuleList([]) feat_m.append(self.conv1) feat_m.append(self.blocks) return feat_m def get_stage_channels(self): return self.stage_channels def forward(self, x): out = self.conv1(x) f0 = out out = self.blocks[0](out) out = self.blocks[1](out) f1 = out out = self.blocks[2](out) f2 = out out = self.blocks[3](out) out = self.blocks[4](out) f3 = out out = self.blocks[5](out) out = self.blocks[6](out) f4 = out out = self.conv2(out) if not self.remove_avg: out = self.avgpool(out) out = out.reshape(out.size(0), -1) avg = out out = self.classifier(out) feats = {} feats["feats"] = [f0, f1, f2, f3, f4] feats["pooled_feat"] = avg return out, feats def _initialize_weights(self): for m in self.modules(): if isinstance(m, nn.Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2.0 / n)) if m.bias is not None: m.bias.data.zero_() elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_() elif isinstance(m, nn.Linear): n = m.weight.size(1) m.weight.data.normal_(0, 0.01) m.bias.data.zero_() def mobilenetv2_T_w(T, W, feature_dim=100): model = MobileNetV2(T=T, feature_dim=feature_dim, width_mult=W) return model def mobile_half(num_classes): return mobilenetv2_T_w(6, 0.5, num_classes) if __name__ == "__main__": x = torch.randn(2, 3, 32, 32) net = mobile_half(100) logit, feats = net(x) for f in feats["feats"]: print(f.shape, f.min().item()) print(logit.shape) ================================================ FILE: mdistiller/models/cifar/mv2_tinyimagenet.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F class LinearBottleNeck(nn.Module): def __init__(self, in_channels, out_channels, stride, t=6, class_num=100): super().__init__() self.residual = nn.Sequential( nn.Conv2d(in_channels, in_channels * t, 1), nn.BatchNorm2d(in_channels * t), nn.ReLU6(inplace=True), nn.Conv2d(in_channels * t, in_channels * t, 3, stride=stride, padding=1, groups=in_channels * t), nn.BatchNorm2d(in_channels * t), nn.ReLU6(inplace=True), nn.Conv2d(in_channels * t, out_channels, 1), nn.BatchNorm2d(out_channels) ) self.stride = stride self.in_channels = in_channels self.out_channels = out_channels def forward(self, x): residual = self.residual(x) if self.stride == 1 and self.in_channels == self.out_channels: residual += x return residual class MobileNetV2(nn.Module): def __init__(self, num_classes=100): super().__init__() self.pre = nn.Sequential( nn.Conv2d(3, 32, 1, padding=1), nn.BatchNorm2d(32), nn.ReLU6(inplace=True) ) self.stage1 = LinearBottleNeck(32, 16, 1, 1) self.stage2 = self._make_stage(2, 16, 24, 2, 6) self.stage3 = self._make_stage(3, 24, 32, 2, 6) self.stage4 = self._make_stage(4, 32, 64, 2, 6) self.stage5 = self._make_stage(3, 64, 96, 1, 6) self.stage6 = self._make_stage(3, 96, 160, 1, 6) self.stage7 = LinearBottleNeck(160, 320, 1, 6) self.conv1 = nn.Sequential( nn.Conv2d(320, 1280, 1), nn.BatchNorm2d(1280), nn.ReLU6(inplace=True) ) self.conv2 = nn.Conv2d(1280, num_classes, 1) def forward(self, x): x = self.pre(x) f0 = x x = self.stage1(x) x = self.stage2(x) f1 = x x = self.stage3(x) f2 = x x = self.stage4(x) f3 = x x = self.stage5(x) x = self.stage6(x) x = self.stage7(x) x = self.conv1(x) f4 = x x = F.adaptive_avg_pool2d(x, 1) avg = x x = self.conv2(x) x = x.view(x.size(0), -1) feats = {} feats["feats"] = [f0, f1, f2, f3, f4] feats["pooled_feat"] = avg return x, feats def _make_stage(self, repeat, in_channels, out_channels, stride, t): layers = [] layers.append(LinearBottleNeck(in_channels, out_channels, stride, t)) while repeat - 1: layers.append(LinearBottleNeck(out_channels, out_channels, 1, t)) repeat -= 1 return nn.Sequential(*layers) def mobilenetv2_tinyimagenet(**kwargs): return MobileNetV2(**kwargs) ================================================ FILE: mdistiller/models/cifar/resnet.py ================================================ from __future__ import absolute_import import torch.nn as nn import torch.nn.functional as F __all__ = ["resnet"] def conv3x3(in_planes, out_planes, stride=1): """3x3 convolution with padding""" return nn.Conv2d( in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False ) class BasicBlock(nn.Module): expansion = 1 def __init__(self, inplanes, planes, stride=1, downsample=None, is_last=False): super(BasicBlock, self).__init__() self.is_last = is_last self.conv1 = conv3x3(inplanes, planes, stride) self.bn1 = nn.BatchNorm2d(planes) self.relu = nn.ReLU(inplace=True) self.conv2 = conv3x3(planes, planes) self.bn2 = nn.BatchNorm2d(planes) self.downsample = downsample self.stride = stride def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) if self.downsample is not None: residual = self.downsample(x) out += residual preact = out out = F.relu(out) if self.is_last: return out, preact else: return out class Bottleneck(nn.Module): expansion = 4 def __init__(self, inplanes, planes, stride=1, downsample=None, is_last=False): super(Bottleneck, self).__init__() self.is_last = is_last self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = nn.Conv2d( planes, planes, kernel_size=3, stride=stride, padding=1, bias=False ) self.bn2 = nn.BatchNorm2d(planes) self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) self.bn3 = nn.BatchNorm2d(planes * 4) self.relu = nn.ReLU(inplace=True) self.downsample = downsample self.stride = stride def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) out = self.relu(out) out = self.conv3(out) out = self.bn3(out) if self.downsample is not None: residual = self.downsample(x) out += residual preact = out out = F.relu(out) if self.is_last: return out, preact else: return out class ResNet(nn.Module): def __init__(self, depth, num_filters, block_name="BasicBlock", num_classes=10): super(ResNet, self).__init__() # Model type specifies number of layers for CIFAR-10 model if block_name.lower() == "basicblock": assert ( depth - 2 ) % 6 == 0, "When use basicblock, depth should be 6n+2, e.g. 20, 32, 44, 56, 110, 1202" n = (depth - 2) // 6 block = BasicBlock elif block_name.lower() == "bottleneck": assert ( depth - 2 ) % 9 == 0, "When use bottleneck, depth should be 9n+2, e.g. 20, 29, 47, 56, 110, 1199" n = (depth - 2) // 9 block = Bottleneck else: raise ValueError("block_name shoule be Basicblock or Bottleneck") self.inplanes = num_filters[0] self.conv1 = nn.Conv2d(3, num_filters[0], kernel_size=3, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(num_filters[0]) self.relu = nn.ReLU(inplace=True) self.layer1 = self._make_layer(block, num_filters[1], n) self.layer2 = self._make_layer(block, num_filters[2], n, stride=2) self.layer3 = self._make_layer(block, num_filters[3], n, stride=2) self.avgpool = nn.AvgPool2d(8) self.fc = nn.Linear(num_filters[3] * block.expansion, num_classes) self.stage_channels = num_filters for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity="relu") elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): nn.init.constant_(m.weight, 1) nn.init.constant_(m.bias, 0) def _make_layer(self, block, planes, blocks, stride=1): downsample = None if stride != 1 or self.inplanes != planes * block.expansion: downsample = nn.Sequential( nn.Conv2d( self.inplanes, planes * block.expansion, kernel_size=1, stride=stride, bias=False, ), nn.BatchNorm2d(planes * block.expansion), ) layers = list([]) layers.append( block(self.inplanes, planes, stride, downsample, is_last=(blocks == 1)) ) self.inplanes = planes * block.expansion for i in range(1, blocks): layers.append(block(self.inplanes, planes, is_last=(i == blocks - 1))) return nn.Sequential(*layers) def get_feat_modules(self): feat_m = nn.ModuleList([]) feat_m.append(self.conv1) feat_m.append(self.bn1) feat_m.append(self.relu) feat_m.append(self.layer1) feat_m.append(self.layer2) feat_m.append(self.layer3) return feat_m def get_bn_before_relu(self): if isinstance(self.layer1[0], Bottleneck): bn1 = self.layer1[-1].bn3 bn2 = self.layer2[-1].bn3 bn3 = self.layer3[-1].bn3 elif isinstance(self.layer1[0], BasicBlock): bn1 = self.layer1[-1].bn2 bn2 = self.layer2[-1].bn2 bn3 = self.layer3[-1].bn2 else: raise NotImplementedError("ResNet unknown block error !!!") return [bn1, bn2, bn3] def get_stage_channels(self): return self.stage_channels def forward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) # 32x32 f0 = x x, f1_pre = self.layer1(x) # 32x32 f1 = x x, f2_pre = self.layer2(x) # 16x16 f2 = x x, f3_pre = self.layer3(x) # 8x8 f3 = x x = self.avgpool(x) avg = x.reshape(x.size(0), -1) out = self.fc(avg) feats = {} feats["feats"] = [f0, f1, f2, f3] feats["preact_feats"] = [f0, f1_pre, f2_pre, f3_pre] feats["pooled_feat"] = avg return out, feats def resnet8(**kwargs): return ResNet(8, [16, 16, 32, 64], "basicblock", **kwargs) def resnet14(**kwargs): return ResNet(14, [16, 16, 32, 64], "basicblock", **kwargs) def resnet20(**kwargs): return ResNet(20, [16, 16, 32, 64], "basicblock", **kwargs) def resnet32(**kwargs): return ResNet(32, [16, 16, 32, 64], "basicblock", **kwargs) def resnet44(**kwargs): return ResNet(44, [16, 16, 32, 64], "basicblock", **kwargs) def resnet56(**kwargs): return ResNet(56, [16, 16, 32, 64], "basicblock", **kwargs) def resnet110(**kwargs): return ResNet(110, [16, 16, 32, 64], "basicblock", **kwargs) def resnet8x4(**kwargs): return ResNet(8, [32, 64, 128, 256], "basicblock", **kwargs) def resnet32x4(**kwargs): return ResNet(32, [32, 64, 128, 256], "basicblock", **kwargs) if __name__ == "__main__": import torch x = torch.randn(2, 3, 32, 32) net = resnet8x4(num_classes=20) logit, feats = net(x) for f in feats["feats"]: print(f.shape, f.min().item()) print(logit.shape) ================================================ FILE: mdistiller/models/cifar/resnetv2.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F class BasicBlock(nn.Module): expansion = 1 def __init__(self, in_planes, planes, stride=1, is_last=False): super(BasicBlock, self).__init__() self.is_last = is_last self.conv1 = nn.Conv2d( in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False ) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = nn.Conv2d( planes, planes, kernel_size=3, stride=1, padding=1, bias=False ) self.bn2 = nn.BatchNorm2d(planes) self.shortcut = nn.Sequential() if stride != 1 or in_planes != self.expansion * planes: self.shortcut = nn.Sequential( nn.Conv2d( in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False, ), nn.BatchNorm2d(self.expansion * planes), ) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = self.bn2(self.conv2(out)) out += self.shortcut(x) preact = out out = F.relu(out) if self.is_last: return out, preact else: return out class Bottleneck(nn.Module): expansion = 4 def __init__(self, in_planes, planes, stride=1, is_last=False): super(Bottleneck, self).__init__() self.is_last = is_last self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = nn.Conv2d( planes, planes, kernel_size=3, stride=stride, padding=1, bias=False ) self.bn2 = nn.BatchNorm2d(planes) self.conv3 = nn.Conv2d( planes, self.expansion * planes, kernel_size=1, bias=False ) self.bn3 = nn.BatchNorm2d(self.expansion * planes) self.shortcut = nn.Sequential() if stride != 1 or in_planes != self.expansion * planes: self.shortcut = nn.Sequential( nn.Conv2d( in_planes, self.expansion * planes, kernel_size=1, stride=stride, bias=False, ), nn.BatchNorm2d(self.expansion * planes), ) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = F.relu(self.bn2(self.conv2(out))) out = self.bn3(self.conv3(out)) out += self.shortcut(x) preact = out out = F.relu(out) if self.is_last: return out, preact else: return out class ResNet(nn.Module): def __init__(self, block, num_blocks, num_classes=10, zero_init_residual=False): super(ResNet, self).__init__() self.in_planes = 64 self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False) self.bn1 = nn.BatchNorm2d(64) self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) self.linear = nn.Linear(512 * block.expansion, num_classes) for m in self.modules(): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity="relu") elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): nn.init.constant_(m.weight, 1) nn.init.constant_(m.bias, 0) # Zero-initialize the last BN in each residual branch, # so that the residual branch starts with zeros, and each residual block behaves like an identity. # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677 if zero_init_residual: for m in self.modules(): if isinstance(m, Bottleneck): nn.init.constant_(m.bn3.weight, 0) elif isinstance(m, BasicBlock): nn.init.constant_(m.bn2.weight, 0) self.stage_channels = [256, 512, 1024, 2048] def get_feat_modules(self): feat_m = nn.ModuleList([]) feat_m.append(self.conv1) feat_m.append(self.bn1) feat_m.append(self.layer1) feat_m.append(self.layer2) feat_m.append(self.layer3) feat_m.append(self.layer4) return feat_m def get_bn_before_relu(self): if isinstance(self.layer1[0], Bottleneck): bn1 = self.layer1[-1].bn3 bn2 = self.layer2[-1].bn3 bn3 = self.layer3[-1].bn3 bn4 = self.layer4[-1].bn3 elif isinstance(self.layer1[0], BasicBlock): bn1 = self.layer1[-1].bn2 bn2 = self.layer2[-1].bn2 bn3 = self.layer3[-1].bn2 bn4 = self.layer4[-1].bn2 else: raise NotImplementedError("ResNet unknown block error !!!") return [bn1, bn2, bn3, bn4] def get_stage_channels(self): return self.stage_channels def _make_layer(self, block, planes, num_blocks, stride): strides = [stride] + [1] * (num_blocks - 1) layers = [] for i in range(num_blocks): stride = strides[i] layers.append(block(self.in_planes, planes, stride, i == num_blocks - 1)) self.in_planes = planes * block.expansion return nn.Sequential(*layers) def encode(self, x, idx, preact=False): if idx == -1: out, pre = self.layer4(F.relu(x)) elif idx == -2: out, pre = self.layer3(F.relu(x)) elif idx == -3: out, pre = self.layer2(F.relu(x)) else: raise NotImplementedError() return pre def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) f0 = out out, f1_pre = self.layer1(out) f1 = out out, f2_pre = self.layer2(out) f2 = out out, f3_pre = self.layer3(out) f3 = out out, f4_pre = self.layer4(out) f4 = out out = self.avgpool(out) avg = out.reshape(out.size(0), -1) out = self.linear(avg) feats = {} feats["feats"] = [f0, f1, f2, f3, f4] feats["preact_feats"] = [f0, f1_pre, f2_pre, f3_pre, f4_pre] feats["pooled_feat"] = avg return out, feats def ResNet18(**kwargs): return ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) def ResNet34(**kwargs): return ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) def ResNet50(**kwargs): return ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) def ResNet101(**kwargs): return ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) def ResNet152(**kwargs): return ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) if __name__ == "__main__": net = ResNet18(num_classes=100) x = torch.randn(2, 3, 32, 32) logit, feats = net(x) for f in feats["feats"]: print(f.shape, f.min().item()) print(logit.shape) ================================================ FILE: mdistiller/models/cifar/vgg.py ================================================ import torch.nn as nn import torch.nn.functional as F import math __all__ = [ "VGG", "vgg11", "vgg11_bn", "vgg13", "vgg13_bn", "vgg16", "vgg16_bn", "vgg19_bn", "vgg19", ] model_urls = { "vgg11": "https://download.pytorch.org/models/vgg11-bbd30ac9.pth", "vgg13": "https://download.pytorch.org/models/vgg13-c768596a.pth", "vgg16": "https://download.pytorch.org/models/vgg16-397923af.pth", "vgg19": "https://download.pytorch.org/models/vgg19-dcbb9e9d.pth", } class VGG(nn.Module): def __init__(self, cfg, batch_norm=False, num_classes=1000): super(VGG, self).__init__() self.block0 = self._make_layers(cfg[0], batch_norm, 3) self.block1 = self._make_layers(cfg[1], batch_norm, cfg[0][-1]) self.block2 = self._make_layers(cfg[2], batch_norm, cfg[1][-1]) self.block3 = self._make_layers(cfg[3], batch_norm, cfg[2][-1]) self.block4 = self._make_layers(cfg[4], batch_norm, cfg[3][-1]) self.pool0 = nn.MaxPool2d(kernel_size=2, stride=2) self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2) self.pool3 = nn.MaxPool2d(kernel_size=2, stride=2) self.pool4 = nn.AdaptiveAvgPool2d((1, 1)) # self.pool4 = nn.MaxPool2d(kernel_size=2, stride=2) self.classifier = nn.Linear(512, num_classes) self._initialize_weights() self.stage_channels = [c[-1] for c in cfg] def get_feat_modules(self): feat_m = nn.ModuleList([]) feat_m.append(self.block0) feat_m.append(self.pool0) feat_m.append(self.block1) feat_m.append(self.pool1) feat_m.append(self.block2) feat_m.append(self.pool2) feat_m.append(self.block3) feat_m.append(self.pool3) feat_m.append(self.block4) feat_m.append(self.pool4) return feat_m def get_bn_before_relu(self): bn1 = self.block1[-1] bn2 = self.block2[-1] bn3 = self.block3[-1] bn4 = self.block4[-1] return [bn1, bn2, bn3, bn4] def get_stage_channels(self): return self.stage_channels def forward(self, x): h = x.shape[2] x = F.relu(self.block0(x)) f0 = x x = self.pool0(x) x = self.block1(x) f1_pre = x x = F.relu(x) f1 = x x = self.pool1(x) x = self.block2(x) f2_pre = x x = F.relu(x) f2 = x x = self.pool2(x) x = self.block3(x) f3_pre = x x = F.relu(x) f3 = x if h == 64: x = self.pool3(x) x = self.block4(x) f4_pre = x x = F.relu(x) f4 = x x = self.pool4(x) x = x.reshape(x.size(0), -1) f5 = x x = self.classifier(x) feats = {} feats["feats"] = [f0, f1, f2, f3, f4] feats["preact_feats"] = [f0, f1_pre, f2_pre, f3_pre, f4_pre] feats["pooled_feat"] = f5 return x, feats @staticmethod def _make_layers(cfg, batch_norm=False, in_channels=3): layers = [] for v in cfg: if v == "M": layers += [nn.MaxPool2d(kernel_size=2, stride=2)] else: conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1) if batch_norm: layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)] else: layers += [conv2d, nn.ReLU(inplace=True)] in_channels = v layers = layers[:-1] return nn.Sequential(*layers) def _initialize_weights(self): for m in self.modules(): if isinstance(m, nn.Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2.0 / n)) if m.bias is not None: m.bias.data.zero_() elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_() elif isinstance(m, nn.Linear): n = m.weight.size(1) m.weight.data.normal_(0, 0.01) m.bias.data.zero_() cfg = { "A": [[64], [128], [256, 256], [512, 512], [512, 512]], "B": [[64, 64], [128, 128], [256, 256], [512, 512], [512, 512]], "D": [[64, 64], [128, 128], [256, 256, 256], [512, 512, 512], [512, 512, 512]], "E": [ [64, 64], [128, 128], [256, 256, 256, 256], [512, 512, 512, 512], [512, 512, 512, 512], ], "S": [[64], [128], [256], [512], [512]], } def vgg8(**kwargs): """VGG 8-layer model (configuration "S") Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ model = VGG(cfg["S"], **kwargs) return model def vgg8_bn(**kwargs): """VGG 8-layer model (configuration "S") Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ model = VGG(cfg["S"], batch_norm=True, **kwargs) return model def vgg11(**kwargs): """VGG 11-layer model (configuration "A") Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ model = VGG(cfg["A"], **kwargs) return model def vgg11_bn(**kwargs): """VGG 11-layer model (configuration "A") with batch normalization""" model = VGG(cfg["A"], batch_norm=True, **kwargs) return model def vgg13(**kwargs): """VGG 13-layer model (configuration "B") Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ model = VGG(cfg["B"], **kwargs) return model def vgg13_bn(**kwargs): """VGG 13-layer model (configuration "B") with batch normalization""" model = VGG(cfg["B"], batch_norm=True, **kwargs) return model def vgg16(**kwargs): """VGG 16-layer model (configuration "D") Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ model = VGG(cfg["D"], **kwargs) return model def vgg16_bn(**kwargs): """VGG 16-layer model (configuration "D") with batch normalization""" model = VGG(cfg["D"], batch_norm=True, **kwargs) return model def vgg19(**kwargs): """VGG 19-layer model (configuration "E") Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ model = VGG(cfg["E"], **kwargs) return model def vgg19_bn(**kwargs): """VGG 19-layer model (configuration 'E') with batch normalization""" model = VGG(cfg["E"], batch_norm=True, **kwargs) return model if __name__ == "__main__": import torch x = torch.randn(2, 3, 32, 32) net = vgg19_bn(num_classes=100) logit, feats = net(x) for f in feats["feats"]: print(f.shape, f.min().item()) print(logit.shape) ================================================ FILE: mdistiller/models/cifar/wrn.py ================================================ import math import torch import torch.nn as nn import torch.nn.functional as F __all__ = ["wrn"] class BasicBlock(nn.Module): def __init__(self, in_planes, out_planes, stride, dropRate=0.0): super(BasicBlock, self).__init__() self.bn1 = nn.BatchNorm2d(in_planes) self.relu1 = nn.ReLU(inplace=True) self.conv1 = nn.Conv2d( in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False ) self.bn2 = nn.BatchNorm2d(out_planes) self.relu2 = nn.ReLU(inplace=True) self.conv2 = nn.Conv2d( out_planes, out_planes, kernel_size=3, stride=1, padding=1, bias=False ) self.droprate = dropRate self.equalInOut = in_planes == out_planes self.convShortcut = ( (not self.equalInOut) and nn.Conv2d( in_planes, out_planes, kernel_size=1, stride=stride, padding=0, bias=False, ) or None ) def forward(self, x): if not self.equalInOut: x = self.relu1(self.bn1(x)) else: out = self.relu1(self.bn1(x)) out = self.relu2(self.bn2(self.conv1(out if self.equalInOut else x))) if self.droprate > 0: out = F.dropout(out, p=self.droprate, training=self.training) out = self.conv2(out) return torch.add(x if self.equalInOut else self.convShortcut(x), out) class NetworkBlock(nn.Module): def __init__(self, nb_layers, in_planes, out_planes, block, stride, dropRate=0.0): super(NetworkBlock, self).__init__() self.layer = self._make_layer( block, in_planes, out_planes, nb_layers, stride, dropRate ) def _make_layer(self, block, in_planes, out_planes, nb_layers, stride, dropRate): layers = [] for i in range(nb_layers): layers.append( block( i == 0 and in_planes or out_planes, out_planes, i == 0 and stride or 1, dropRate, ) ) return nn.Sequential(*layers) def forward(self, x): return self.layer(x) class WideResNet(nn.Module): def __init__(self, depth, num_classes, widen_factor=1, dropRate=0.0): super(WideResNet, self).__init__() nChannels = [16, 16 * widen_factor, 32 * widen_factor, 64 * widen_factor] assert (depth - 4) % 6 == 0, "depth should be 6n+4" n = (depth - 4) // 6 block = BasicBlock # 1st conv before any network block self.conv1 = nn.Conv2d( 3, nChannels[0], kernel_size=3, stride=1, padding=1, bias=False ) # 1st block self.block1 = NetworkBlock(n, nChannels[0], nChannels[1], block, 1, dropRate) # 2nd block self.block2 = NetworkBlock(n, nChannels[1], nChannels[2], block, 2, dropRate) # 3rd block self.block3 = NetworkBlock(n, nChannels[2], nChannels[3], block, 2, dropRate) # global average pooling and classifier self.bn1 = nn.BatchNorm2d(nChannels[3]) self.relu = nn.ReLU(inplace=True) self.fc = nn.Linear(nChannels[3], num_classes) self.nChannels = nChannels[3] for m in self.modules(): if isinstance(m, nn.Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2.0 / n)) elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_() elif isinstance(m, nn.Linear): m.bias.data.zero_() self.stage_channels = nChannels def get_feat_modules(self): feat_m = nn.ModuleList([]) feat_m.append(self.conv1) feat_m.append(self.block1) feat_m.append(self.block2) feat_m.append(self.block3) return feat_m def get_bn_before_relu(self): bn1 = self.block2.layer[0].bn1 bn2 = self.block3.layer[0].bn1 bn3 = self.bn1 return [bn1, bn2, bn3] def get_stage_channels(self): return self.stage_channels def forward(self, x): out = self.conv1(x) f0 = out out = self.block1(out) f1 = out out = self.block2(out) f2 = out out = self.block3(out) f3 = out out = self.relu(self.bn1(out)) out = F.avg_pool2d(out, 8) out = out.reshape(-1, self.nChannels) f4 = out out = self.fc(out) f1_pre = self.block2.layer[0].bn1(f1) f2_pre = self.block3.layer[0].bn1(f2) f3_pre = self.bn1(f3) feats = {} feats["feats"] = [f0, f1, f2, f3] feats["preact_feats"] = [f0, f1_pre, f2_pre, f3_pre] feats["pooled_feat"] = f4 return out, feats def wrn(**kwargs): """ Constructs a Wide Residual Networks. """ model = WideResNet(**kwargs) return model def wrn_40_2(**kwargs): model = WideResNet(depth=40, widen_factor=2, **kwargs) return model def wrn_40_1(**kwargs): model = WideResNet(depth=40, widen_factor=1, **kwargs) return model def wrn_16_2(**kwargs): model = WideResNet(depth=16, widen_factor=2, **kwargs) return model def wrn_16_1(**kwargs): model = WideResNet(depth=16, widen_factor=1, **kwargs) return model if __name__ == "__main__": import torch x = torch.randn(2, 3, 32, 32) net = wrn_40_2(num_classes=100) logit, feats = net(x) for f in feats["feats"]: print(f.shape, f.min().item()) print(logit.shape) ================================================ FILE: mdistiller/models/imagenet/__init__.py ================================================ from .resnet import resnet18, resnet34, resnet50, resnet101, resnet152 from .mobilenetv1 import MobileNetV1 imagenet_model_dict = { "ResNet18": resnet18, "ResNet34": resnet34, "ResNet50": resnet50, "ResNet101": resnet101, "MobileNetV1": MobileNetV1, } ================================================ FILE: mdistiller/models/imagenet/mobilenetv1.py ================================================ import torch import torch.nn as nn import torch.nn.functional as F class MobileNetV1(nn.Module): def __init__(self, **kwargs): super(MobileNetV1, self).__init__() def conv_bn(inp, oup, stride): return nn.Sequential( nn.Conv2d(inp, oup, 3, stride, 1, bias=False), nn.BatchNorm2d(oup), nn.ReLU(inplace=True), ) def conv_dw(inp, oup, stride): return nn.Sequential( nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False), nn.BatchNorm2d(inp), nn.ReLU(inplace=True), nn.Conv2d(inp, oup, 1, 1, 0, bias=False), nn.BatchNorm2d(oup), nn.ReLU(inplace=True), ) self.model = nn.Sequential( conv_bn(3, 32, 2), conv_dw(32, 64, 1), conv_dw(64, 128, 2), conv_dw(128, 128, 1), conv_dw(128, 256, 2), conv_dw(256, 256, 1), conv_dw(256, 512, 2), conv_dw(512, 512, 1), conv_dw(512, 512, 1), conv_dw(512, 512, 1), conv_dw(512, 512, 1), conv_dw(512, 512, 1), conv_dw(512, 1024, 2), conv_dw(1024, 1024, 1), nn.AvgPool2d(7), ) self.fc = nn.Linear(1024, 1000) def forward(self, x, is_feat=False): feat1 = self.model[3][:-1](self.model[0:3](x)) feat2 = self.model[5][:-1](self.model[4:5](F.relu(feat1))) feat3 = self.model[11][:-1](self.model[6:11](F.relu(feat2))) feat4 = self.model[13][:-1](self.model[12:13](F.relu(feat3))) feat5 = self.model[14](F.relu(feat4)) avg = feat5.reshape(-1, 1024) out = self.fc(avg) feats = {} feats["pooled_feat"] = avg feats["feats"] = [F.relu(feat1), F.relu(feat2), F.relu(feat3), F.relu(feat4)] feats["preact_feats"] = [feat1, feat2, feat3, feat4] return out, feats def get_bn_before_relu(self): bn1 = self.model[3][-2] bn2 = self.model[5][-2] bn3 = self.model[11][-2] bn4 = self.model[13][-2] return [bn1, bn2, bn3, bn4] def get_stage_channels(self): return [128, 256, 512, 1024] ================================================ FILE: mdistiller/models/imagenet/resnet.py ================================================ import torch import torch.nn as nn import math import torch.utils.model_zoo as model_zoo import torch.nn.functional as F __all__ = ["ResNet", "resnet18", "resnet34", "resnet50", "resnet101", "resnet152"] model_urls = { "resnet18": "https://download.pytorch.org/models/resnet18-5c106cde.pth", "resnet34": "https://download.pytorch.org/models/resnet34-333f7ec4.pth", "resnet50": "https://download.pytorch.org/models/resnet50-19c8e357.pth", "resnet101": "https://download.pytorch.org/models/resnet101-5d3b4d8f.pth", "resnet152": "https://download.pytorch.org/models/resnet152-b121ed2d.pth", } def conv3x3(in_planes, out_planes, stride=1): """3x3 convolution with padding""" return nn.Conv2d( in_planes, out_planes, kernel_size=3, stride=stride, padding=1, bias=False ) class BasicBlock(nn.Module): expansion = 1 def __init__(self, inplanes, planes, stride=1, downsample=None): super(BasicBlock, self).__init__() self.conv1 = conv3x3(inplanes, planes, stride) self.bn1 = nn.BatchNorm2d(planes) self.relu = nn.ReLU(inplace=True) self.conv2 = conv3x3(planes, planes) self.bn2 = nn.BatchNorm2d(planes) self.downsample = downsample self.stride = stride def forward(self, x): x = F.relu(x) residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) if self.downsample is not None: residual = self.downsample(x) out += residual # out = self.relu(out) return out class Bottleneck(nn.Module): expansion = 4 def __init__(self, inplanes, planes, stride=1, downsample=None): super(Bottleneck, self).__init__() self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = nn.Conv2d( planes, planes, kernel_size=3, stride=stride, padding=1, bias=False ) self.bn2 = nn.BatchNorm2d(planes) self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) self.bn3 = nn.BatchNorm2d(planes * 4) self.relu = nn.ReLU(inplace=True) self.downsample = downsample self.stride = stride def forward(self, x): x = F.relu(x) residual = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) out = self.relu(out) out = self.conv3(out) out = self.bn3(out) if self.downsample is not None: residual = self.downsample(x) out += residual # out = self.relu(out) return out class ResNet(nn.Module): def __init__(self, block, layers, num_classes=1000): self.inplanes = 64 super(ResNet, self).__init__() self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False) self.bn1 = nn.BatchNorm2d(64) self.relu = nn.ReLU(inplace=True) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) self.layer1 = self._make_layer(block, 64, layers[0]) self.layer2 = self._make_layer(block, 128, layers[1], stride=2) self.layer3 = self._make_layer(block, 256, layers[2], stride=2) self.layer4 = self._make_layer(block, 512, layers[3], stride=2) self.avgpool = nn.AvgPool2d(7, stride=1) self.fc = nn.Linear(512 * block.expansion, num_classes) for m in self.modules(): if isinstance(m, nn.Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2.0 / n)) elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_() def _make_layer(self, block, planes, blocks, stride=1): downsample = None if stride != 1 or self.inplanes != planes * block.expansion: downsample = nn.Sequential( nn.Conv2d( self.inplanes, planes * block.expansion, kernel_size=1, stride=stride, bias=False, ), nn.BatchNorm2d(planes * block.expansion), ) layers = [] layers.append(block(self.inplanes, planes, stride, downsample)) self.inplanes = planes * block.expansion for i in range(1, blocks): layers.append(block(self.inplanes, planes)) return nn.Sequential(*layers) def get_bn_before_relu(self): if isinstance(self.layer1[0], Bottleneck): # bn1 = self.layer1[-1].bn3 bn2 = self.layer2[-1].bn3 bn3 = self.layer3[-1].bn3 bn4 = self.layer4[-1].bn3 elif isinstance(self.layer1[0], BasicBlock): # bn1 = self.layer1[-1].bn2 bn2 = self.layer2[-1].bn2 bn3 = self.layer3[-1].bn2 bn4 = self.layer4[-1].bn2 else: print("ResNet unknown block error !!!") return [bn2, bn3, bn4] def get_stage_channels(self): return [256, 512, 1024, 2048] def forward(self, x): x = self.conv1(x) x = self.bn1(x) stem = x x = self.relu(x) x = self.maxpool(x) feat1 = self.layer1(x) feat2 = self.layer2(feat1) feat3 = self.layer3(feat2) feat4 = self.layer4(feat3) x = self.avgpool(F.relu(feat4)) x = x.view(x.size(0), -1) avg = x out = self.fc(x) feats = {} feats["pooled_feat"] = avg feats["feats"] = [ F.relu(stem), F.relu(feat1), F.relu(feat2), F.relu(feat3), F.relu(feat4), ] feats["preact_feats"] = [stem, feat1, feat2, feat3, feat4] return out, feats def resnet18(pretrained=False, **kwargs): """Constructs a ResNet-18 model. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) if pretrained: model.load_state_dict(model_zoo.load_url(model_urls["resnet18"])) return model def resnet34(pretrained=False, **kwargs): """Constructs a ResNet-34 model. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) if pretrained: model.load_state_dict(model_zoo.load_url(model_urls["resnet34"])) return model def resnet50(pretrained=False, **kwargs): """Constructs a ResNet-50 model. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) if pretrained: model.load_state_dict(model_zoo.load_url(model_urls["resnet50"])) return model def resnet101(pretrained=False, **kwargs): """Constructs a ResNet-101 model. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) if pretrained: model.load_state_dict(model_zoo.load_url(model_urls["resnet101"])) return model def resnet152(pretrained=False, **kwargs): """Constructs a ResNet-152 model. Args: pretrained (bool): If True, returns a model pre-trained on ImageNet """ model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) if pretrained: model.load_state_dict(model_zoo.load_url(model_urls["resnet152"])) return model ================================================ FILE: requirements.txt ================================================ torch==1.9.0 torchvision==0.10.0 tensorboard-logger==0.1.0 yacs wandb tqdm tensorboardX ================================================ FILE: setup.py ================================================ """MDistiller: a deep learning toolkit for knowledge distillation. """ import os.path import sys import setuptools if __name__ == "__main__": sys.path.insert(0, os.path.join(os.path.dirname(__file__), "mdistiller")) DISTNAME = "mdistiller" DESCRIPTION = "A Deep Learning Toolkit for Knowledge Distillation." AUTHOR = "zhaoborui" DOCLINES = __doc__ setuptools.setup( name=DISTNAME, packages=setuptools.find_packages(), version="0.1", description=DESCRIPTION, long_description=DOCLINES, long_description_content_type="text/markdown", author=AUTHOR, ) ================================================ FILE: tools/eval.py ================================================ import argparse import torch import torch.backends.cudnn as cudnn cudnn.benchmark = True from mdistiller.distillers import Vanilla from mdistiller.models import cifar_model_dict, imagenet_model_dict, tiny_imagenet_model_dict from mdistiller.dataset import get_dataset from mdistiller.dataset.imagenet import get_imagenet_val_loader from mdistiller.engine.utils import load_checkpoint, validate from mdistiller.engine.cfg import CFG as cfg if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("-m", "--model", type=str, default="") parser.add_argument("-c", "--ckpt", type=str, default="pretrain") parser.add_argument( "-d", "--dataset", type=str, default="cifar100", choices=["cifar100", "imagenet", "tiny_imagenet"], ) parser.add_argument("-bs", "--batch-size", type=int, default=64) args = parser.parse_args() cfg.DATASET.TYPE = args.dataset cfg.DATASET.TEST.BATCH_SIZE = args.batch_size if args.dataset == "imagenet": val_loader = get_imagenet_val_loader(args.batch_size) if args.ckpt == "pretrain": model = imagenet_model_dict[args.model](pretrained=True) else: model = imagenet_model_dict[args.model](pretrained=False) model.load_state_dict(load_checkpoint(args.ckpt)["model"]) elif args.dataset in ("cifar100", "tiny_imagenet"): train_loader, val_loader, num_data, num_classes = get_dataset(cfg) model_dict = tiny_imagenet_model_dict if args.dataset == "tiny_imagenet" else cifar_model_dict model, pretrain_model_path = model_dict[args.model] model = model(num_classes=num_classes) ckpt = pretrain_model_path if args.ckpt == "pretrain" else args.ckpt model.load_state_dict(load_checkpoint(ckpt)["model"]) model = Vanilla(model) model = model.cuda() model = torch.nn.DataParallel(model) test_acc, test_acc_top5, test_loss = validate(val_loader, model) ================================================ FILE: tools/train.py ================================================ import os import argparse import torch import torch.nn as nn import torch.backends.cudnn as cudnn cudnn.benchmark = True from mdistiller.models import cifar_model_dict, imagenet_model_dict, tiny_imagenet_model_dict from mdistiller.distillers import distiller_dict from mdistiller.dataset import get_dataset from mdistiller.engine.utils import load_checkpoint, log_msg from mdistiller.engine.cfg import CFG as cfg from mdistiller.engine.cfg import show_cfg from mdistiller.engine import trainer_dict def main(cfg, resume, opts): experiment_name = cfg.EXPERIMENT.NAME if experiment_name == "": experiment_name = cfg.EXPERIMENT.TAG tags = cfg.EXPERIMENT.TAG.split(",") if opts: addtional_tags = ["{}:{}".format(k, v) for k, v in zip(opts[::2], opts[1::2])] tags += addtional_tags experiment_name += ",".join(addtional_tags) experiment_name = os.path.join(cfg.EXPERIMENT.PROJECT, experiment_name) if cfg.LOG.WANDB: try: import wandb wandb.init(project=cfg.EXPERIMENT.PROJECT, name=experiment_name, tags=tags) except: print(log_msg("Failed to use WANDB", "INFO")) cfg.LOG.WANDB = False # cfg & loggers show_cfg(cfg) # init dataloader & models train_loader, val_loader, num_data, num_classes = get_dataset(cfg) # vanilla if cfg.DISTILLER.TYPE == "NONE": if cfg.DATASET.TYPE == "imagenet": model_student = imagenet_model_dict[cfg.DISTILLER.STUDENT](pretrained=False) elif cfg.DATASET.TYPE == "tiny_imagenet": model_student = tiny_imagenet_model_dict[cfg.DISTILLER.STUDENT][0](num_classes=num_classes) else: model_student = cifar_model_dict[cfg.DISTILLER.STUDENT][0]( num_classes=num_classes ) distiller = distiller_dict[cfg.DISTILLER.TYPE](model_student) # distillation else: print(log_msg("Loading teacher model", "INFO")) if cfg.DATASET.TYPE == "imagenet": model_teacher = imagenet_model_dict[cfg.DISTILLER.TEACHER](pretrained=True) model_student = imagenet_model_dict[cfg.DISTILLER.STUDENT](pretrained=False) else: model_dict = tiny_imagenet_model_dict if cfg.DATASET.TYPE == "tiny_imagenet" else cifar_model_dict net, pretrain_model_path = model_dict[cfg.DISTILLER.TEACHER] assert ( pretrain_model_path is not None ), "no pretrain model for teacher {}".format(cfg.DISTILLER.TEACHER) model_teacher = net(num_classes=num_classes) model_teacher.load_state_dict(load_checkpoint(pretrain_model_path)["model"]) model_student = model_dict[cfg.DISTILLER.STUDENT][0]( num_classes=num_classes ) if cfg.DISTILLER.TYPE == "CRD": distiller = distiller_dict[cfg.DISTILLER.TYPE]( model_student, model_teacher, cfg, num_data ) else: distiller = distiller_dict[cfg.DISTILLER.TYPE]( model_student, model_teacher, cfg ) distiller = torch.nn.DataParallel(distiller.cuda()) if cfg.DISTILLER.TYPE != "NONE": print( log_msg( "Extra parameters of {}: {}\033[0m".format( cfg.DISTILLER.TYPE, distiller.module.get_extra_parameters() ), "INFO", ) ) # train trainer = trainer_dict[cfg.SOLVER.TRAINER]( experiment_name, distiller, train_loader, val_loader, cfg ) trainer.train(resume=resume) if __name__ == "__main__": import argparse parser = argparse.ArgumentParser("training for knowledge distillation.") parser.add_argument("--cfg", type=str, default="") parser.add_argument("--resume", action="store_true") parser.add_argument("opts", default=None, nargs=argparse.REMAINDER) args = parser.parse_args() cfg.merge_from_file(args.cfg) cfg.merge_from_list(args.opts) cfg.freeze() main(cfg, args.resume, args.opts) ================================================ FILE: tools/visualizations/correlation.ipynb ================================================ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Correlation matrices visualization of CIFAR-100 models" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/usr/lib/python3/dist-packages/requests/__init__.py:80: RequestsDependencyWarning: urllib3 (1.26.6) or chardet (3.0.4) doesn't match a supported version!\n", " RequestsDependencyWarning)\n" ] } ], "source": [ "import numpy as np\n", "import torch\n", "from tqdm import tqdm\n", "import matplotlib.pyplot as plt\n", "import seaborn\n", "\n", "from mdistiller.models import cifar_model_dict\n", "from mdistiller.dataset import get_dataset\n", "from mdistiller.engine.utils import load_checkpoint\n", "from mdistiller.engine.cfg import CFG as cfg" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# visualize the difference between the teacher's output logits and the student's\n", "def get_output_metric(model, val_loader, num_classes=100):\n", " model.eval()\n", " all_preds, all_labels = [], []\n", " with torch.no_grad():\n", " for i, (data, labels) in tqdm(enumerate(val_loader)):\n", " outputs, _ = model(data)\n", " preds = outputs\n", " all_preds.append(preds.data.cpu().numpy())\n", " all_labels.append(labels.data.cpu().numpy())\n", " \n", " all_preds = np.concatenate(all_preds, 0)\n", " all_labels = np.concatenate(all_labels, 0)\n", " matrix = np.zeros((num_classes, num_classes))\n", " cnt = np.zeros((num_classes, 1))\n", " for p, l in zip(all_preds, all_labels):\n", " cnt[l, 0] += 1\n", " matrix[l] += p\n", " matrix /= cnt\n", " return matrix\n", "\n", "def get_tea_stu_diff(tea, stu, mpath, max_diff):\n", " cfg.defrost()\n", " cfg.DISTILLER.STUDENT = stu\n", " cfg.DISTILLER.TEACHER = tea\n", " cfg.DATASET.TYPE = 'cifar100'\n", " cfg.freeze()\n", " train_loader, val_loader, num_data, num_classes = get_dataset(cfg)\n", " model = cifar_model_dict[cfg.DISTILLER.STUDENT][0](num_classes=num_classes)\n", " model.load_state_dict(load_checkpoint(mpath)[\"model\"])\n", " tea_model = cifar_model_dict[cfg.DISTILLER.TEACHER][0](num_classes=num_classes)\n", " tea_model.load_state_dict(load_checkpoint(cifar_model_dict[cfg.DISTILLER.TEACHER][1])[\"model\"])\n", " print(\"load model successfully!\")\n", " ms = get_output_metric(model, val_loader)\n", " mt = get_output_metric(tea_model, val_loader)\n", " diff = np.abs((ms - mt)) / max_diff\n", " for i in range(100):\n", " diff[i, i] = 0\n", " print('max(diff):', diff.max())\n", " print('mean(diff):', diff.mean())\n", " seaborn.heatmap(diff, vmin=0, vmax=1.0, cmap=\"PuBuGn\")\n", " plt.show()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# set a common max-value of the difference for fair comparsion between different methods\n", "MAX_DIFF = 3.0" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Files already downloaded and verified\n", "Files already downloaded and verified\n", "load model successfully!\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "157it [00:27, 5.78it/s]\n", "157it [02:13, 1.18it/s]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "max(diff): 0.8985582387199003\n", "mean(diff): 0.09006057001758816\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# KD baseline\n", "mpath = \"../../download_ckpts/kd_resnet8x4\"\n", "get_tea_stu_diff(\"resnet32x4\", \"resnet8x4\", mpath, MAX_DIFF)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Files already downloaded and verified\n", "Files already downloaded and verified\n", "load model successfully!\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "157it [00:28, 5.44it/s]\n", "157it [04:52, 1.86s/it]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "max(diff): 0.41605710864067075\n", "mean(diff): 0.04375380312281896\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# Our DKD\n", "mpath = \"../../download_ckpts/dkd_resnet8x4\"\n", "get_tea_stu_diff(\"resnet32x4\", \"resnet8x4\", mpath, MAX_DIFF)" ] } ], "metadata": { "interpreter": { "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" }, "kernelspec": { "display_name": "Python 3.6.9 64-bit", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.9" }, "orig_nbformat": 2 }, "nbformat": 4, "nbformat_minor": 2 } ================================================ FILE: tools/visualizations/tsne.ipynb ================================================ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# t-SNE visualization of CIFAR-100 models" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/usr/lib/python3/dist-packages/requests/__init__.py:80: RequestsDependencyWarning: urllib3 (1.26.6) or chardet (3.0.4) doesn't match a supported version!\n", " RequestsDependencyWarning)\n" ] } ], "source": [ "from tqdm import tqdm\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "from sklearn.manifold import TSNE\n", "import torch\n", "\n", "from mdistiller.models import cifar_model_dict\n", "from mdistiller.dataset import get_dataset\n", "from mdistiller.engine.utils import load_checkpoint\n", "from mdistiller.engine.cfg import CFG as cfg" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# visualize t-SNE\n", "def get_tsne(stu, mpath):\n", " cfg.defrost()\n", " cfg.DISTILLER.STUDENT = stu\n", " cfg.DATASET.TYPE = 'cifar100'\n", " cfg.freeze()\n", " train_loader, val_loader, num_data, num_classes = get_dataset(cfg)\n", " model = cifar_model_dict[cfg.DISTILLER.STUDENT][0](num_classes=num_classes)\n", " model.load_state_dict(load_checkpoint(mpath)[\"model\"])\n", " all_features, all_labels = [], []\n", " model.eval()\n", " with torch.no_grad():\n", " for i, (data, labels) in tqdm(enumerate(val_loader)):\n", " outputs, features = model(data)\n", " all_features.append(features['pooled_feat'].data.cpu().numpy())\n", " all_labels.append(labels.data.cpu().numpy())\n", " all_features = np.concatenate(all_features, 0)\n", " all_labels = np.concatenate(all_labels, 0)\n", "\n", " tsne = TSNE()\n", " all_features = tsne.fit_transform(all_features)\n", " plot_features(all_features, all_labels, num_classes)\n", "\n", "def plot_features(features, labels, num_classes):\n", " colors = ['C' + str(i) for i in range(num_classes)]\n", " plt.figure(figsize=(6, 6))\n", " for l in range(num_classes):\n", " plt.scatter(\n", " features[labels == l, 0],\n", " features[labels == l, 1],\n", " c=colors[l], s=1, alpha=0.4)\n", " plt.xticks([])\n", " plt.yticks([])\n", " plt.show()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Files already downloaded and verified\n", "Files already downloaded and verified\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "157it [01:05, 2.40it/s]\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# KD baseline\n", "mpath = \"../../download_ckpts/kd_resnet8x4\"\n", "get_tsne(\"resnet8x4\", mpath)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Files already downloaded and verified\n", "Files already downloaded and verified\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "157it [01:05, 2.40it/s]\n" ] }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Our DKD\n", "mpath = \"../../download_ckpts/dkd_resnet8x4\"\n", "get_tsne(\"resnet8x4\", mpath)" ] } ], "metadata": { "interpreter": { "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.9" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }