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
}